Springboot如何按需加载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指定需要排除的组件。规则同上
useDefaultFiltersTrue 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;
	}
}

版权声明:
作者:Miigua
链接:https://www.miigua.com/article/337.html
来源:米瓜的博客
文章版权归作者所有,未经允许请勿转载。

THE END
二维码
打赏
请在后台主题设置处设置打赏图片
< <上一篇
下一篇>>