在启动SpringBoot应用时,有这样一种需求,不需要加载全部的Bean,按照业务不同,按需加载。
为什么要按需加载
按需加载的概念很简单,按照系统的要求加载不同的模块。在SpringBoot应用中,即加载指定的Bean到Spring容器中。
按需加载有两个好处,首先容器中不需要加载额外的类,造成不必要的资源浪费。其次代码可以按package区分,既高内聚又方便管理。
按需加载的实现
Conditional
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
@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")); return context.getEnvironment().getProperty("search.business").equals("travel"); } }
@Component
@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标记的注解。
1 2 3 4 5 6 7
| <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 2 3 4 5 6 7 8 9 10 11 12
| 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)
|
自定义扫描过滤规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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)) { return true; } } catch (ClassNotFoundException e) {
} return false; } }
|
参考
1、Spring组件注册注解之@ComponentScan,@ComponentScans