当前位置: 首页>后端>正文

SpringBoot中如何动态加载类到容器

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加入容器中

个人不喜欢技术性文章中出现大量代码。介绍应用场景为主,具体使用为辅。

欢迎留言讨论,交流才有进步


https://www.xamrdz.com/backend/3q61941459.html

相关文章: