1,摘要
? ? ? ?任何业务脱离场景无任何实际意义。下面的文字对新手并不是很友好,多数是理论知识,具体实践需要大家自己去模拟(但是理论是一切的源头)
2,应用场景
场景:
? ? ? ? ①:实现了多种存储方式,redis和本地内存或者其它,但是你希望根据注解配置只加载一种类到容器。
? ? ? ? ②:经典场景:mybatis将接口的代理类动态加载到容器。
分类:
静态加载:(明确要加载某些类,生成BeanDefinition)
????????①:springboot中会扫描同包路径下的(@configuration @Service @Component)标记了上述注解,自动加入容器
? ? ? ? ②:@Import直接导入某个类
动态加载:
????????分为2种,一种Bean的初始化比较简单(比如:场景1),另外一个中Bean的构建比较复杂(比如:场景2需要根据XML和接口动态生成一个具体实现类)。
????????场景1:可以直接实现ImportSelector接口,根据一下判断条件,将需要加载的类,动态返回即可,容器会自动加载
@ImportSelectorThresholdAnnotation(value ="ttttttt")
public class CloudClassAdminApplication {
public static void main(String[] args) {
//设置默认时区
//? ? ? ? TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("GMT+8")));
? ? ? ? SpringApplication.run(CloudClassAdminApplication.class, args);
? ? ? ? log.info("运营端启动成功");
? ? }
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(ImportSelectorThreshold.class)
public @interface ImportSelectorThresholdAnnotation {
String[]value()default {};
}
public class ImportSelectorThresholdimplements ImportSelector {
@Override
? ? public String[]selectImports(AnnotationMetadata importingClassMetadata) {
//根据importingClassMetadata创建的逻辑业务条件,动态过滤要加载的类
? ? ? ? //String[] :中要加载到容器中具体类(全路径名)
? ? ? ? return new String[0];
? ? }
}
场景2:可以实现ImportBeanDefinitionRegistrar接口,手动加载某些类到容器中
@Import(value = {ImportCustomBeanDefinitionRegistrar.class})
public class CloudClassAdminApplication {
public static void main(String[] args) {
? ? ? ? SpringApplication.run(CloudClassAdminApplication.class, args);
? ? }
}
public class ImportCustomBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
public? void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//这里可以进行复杂的Bean初始化,如依赖各种外部条件,组装Bean
? ? ? ? String simpleName = B.class.getName();
? ? ? ? RootBeanDefinition rootBeanDefinition =new RootBeanDefinition();
? ? ? ? rootBeanDefinition.setBeanClass(B.class);
? ? ? ? registry.registerBeanDefinition(simpleName, rootBeanDefinition);
? ? }
}
????????动态加载类到容器,实际业务中很少出现,常规场景中:如你的业务中有自定义JAR包,那么上述业务就很有存在的意义啦。你需要指定自定义的jar中那些类需要启动就交个容器管理。
3,springboot如何实现自动装配的
? ? ? ①:首先自动装配核心原理就是上述的这些,并且根据场景分类,大部分jar的自动装配都是简单的初始化过程并且交个IOC容器管理,所以采用场景1的方案(实现importSelector)。?
? ? ? ②:其次需要明确告诉springBoot那些类要加载到容器中,这里springboot采用类似spi的方式(spi是告诉系统接口有哪些实现类),springboot采用类似的方式在spring.factories中定义那些类需要加载到容器中(EnableAutoConfiguration="需要加载到容器中类")
? ? ? ③:springboot还很贴心的允许使用者在spring.factories中允许你定义一些过滤器(AutoConfigurationImportFilter="定义的过滤器"),目的是过滤EnableAutoConfiguration定义的类,禁止他们加载到容器中,常见的过滤器如:OnBeanCondition,OnClassCondition,是不是很熟悉,对的这个本身也是ConditionOnBean,ConditionOnClass的处理类(个人感觉这些filter没啥作用,相比较Condition更好用)
? ? ?④:上述步骤最终结果是生成一系列要加载到容器中的BeanDefinition,但是还木有加载到容器中(缺少初始化)
? ? ?⑤:初始化之前需要在进行一次过滤,方式有ConditionOn***系列进行判断,Bean实现了BeanFactoryPostProcessor,进行Bean裁剪
? ? ?⑥:上述步骤完成以后才能帮Bean加入容器中
个人不喜欢技术性文章中出现大量代码。介绍应用场景为主,具体使用为辅。
欢迎留言讨论,交流才有进步