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加入容器中
个人不喜欢技术性文章中出现大量代码。介绍应用场景为主,具体使用为辅。
欢迎留言讨论,交流才有进步