【Spring Boot 】 如何按需加载Bean
在启动SpringBoot应用时,有这样一种需求,不需要加载全部的Bean,按照业务不同,按需加载。
为什么要按需加载
按需加载的概念很简单,按照系统的要求加载不同的模块。在SpringBoot应用中,即加载指定的Bean到Spring容器中。
按需加载有两个好处,首先容器中不需要加载额外的类,造成不必要的资源浪费。其次代码可以按package区分,既高内聚又方便管理。
按需加载的实现
Conditional
/**
Condition类是一个函数式接口,作为判定一个组件是否应该注入到Spring容器中。
在Bean definition前就执行检查,如果不符合校验规则就不进行注册。
*/
@FunctionalInterface
public interface Condition {
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
public class TravelLoadCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
System.out.println("business=" + context.getEnvironment().getProperty("search.business"));
//获取application.yml配置文件中的search.business属性,并匹配是否等于travel
return context.getEnvironment().getProperty("search.business").equals("travel");
}
}
@Component
//如果TravelLoadCondition返回true,则注入TravelBasicSearch。
@Conditional(TravelLoadCondition.class)
public class TravelBasicSearch {
public TravelBasicSearch() {
System.out.println(this.getClass().getSimpleName() + " loaded....");
}
@PostConstruct
private void init() {
System.out.println(this.getClass().getSimpleName() + " inited....");
}
}
ComponentScan
ComponentScan是用在Configuration
上的指令,等同于XML中的<context:component-scan>
。它可以自动扫描@Component
注解或者被它标记的注解,@Controller
,@Service
,@Repository
都是被@Component标记的注解。
<context:component-scan
base-package="com.yibai.spring.annotation" use-default-filters="false">
<context:include-filter type="custom"
expression="com.yibai.spring.annotation.filter.ColorBeanLoadFilter" />
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Component" />
</context:component-scan>
属性 | 含义 |
---|---|
value | 指定要扫描的package |
includeFilters | 指定只包含的组件,FilterType:指定过滤规则,支持的过滤规则有。ANNOTATION:按照注解规则,过滤被指定注解标记的类;ASSIGNABLE_TYPE:按照给定的类型; ASPECTJ:按照ASPECTJ表达式;REGEX:按照正则表达式 CUSTOM:自定义规则; |
excludeFilters | 指定需要排除的组件。规则同上 |
useDefaultFilters | True or False。指定是否需要使用Spring默认的扫描规则:被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件; |
1. 扫描指定类文件
@ComponentScan(basePackageClasses = Person.class)
2. 扫描指定包,使用默认扫描规则,即被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件;
@ComponentScan(value = "com.yibai")
3. 扫描指定包,加载被@Component注解标记的组件和默认规则的扫描(因为useDefaultFilters默认为true)
@ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
4. 扫描指定包,只加载Person类型的组件
@ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE, value = Person.class) }, useDefaultFilters = false)
5. 扫描指定包,过滤掉被@Component标记的组件
@ComponentScan(value = "com.yibai", excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
6. 扫描指定包,自定义过滤规则
@ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.CUSTOM, value = ColorBeanLoadFilter.class) }, useDefaultFilters = true)
自定义扫描过滤规则
public class ColorBeanLoadFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 当前被扫描类的注解信息
@SuppressWarnings("unused")
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 当前被扫描类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 当前被扫描类资源信息
@SuppressWarnings("unused")
Resource resource = metadataReader.getResource();
try {
String className = classMetadata.getClassName();
Class<?> forName = Class.forName(className);
if (Color.class.isAssignableFrom(forName)) {
// 如果是Color的子类,就加载到IOC容器
return true;
}
} catch (ClassNotFoundException e) {
}
return false;
}
}
版权声明:
作者:白纸画
链接:https://www.fanyicloud.cn/article-42.fan
来源:白纸画的博客
文章版权归作者所有,未经允许请勿转载。

全部评论