前言
- springboot 2.0.0.RELEASE
- maven 3.5.0
- 这里介绍内容为,在spring boot启动时,排除/不加载某些Bean。spring boot启动时,排除/不加载某些模块/AutoConfiguration类,看这里。
排除/不加载某些Bean
排除/不加载某些Bean时,需要使用@ComponentScan。具体做法,可以采用下面的方式:
- 方式1:自定义
@ComponentScan
- 方式2:自定义
@ComponentScans
- 方式3:自定义
TypeExcludeFilter
方式1:自定义 @ComponentScan
假设:我在使用 RuoYi 的时候,想自己的实现 ShiroConfig,而不用 RuoYi 自带的 ShiroConfig ,且,不删除 RuoYi 自带的 ShiroConfig 类。
此种情况下,就需要启动项目时,不加载 ShiroConfig 类。
针对此种情况,可以这样做:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.REGEX, pattern = {
"com.ruoyi.framework.config.ShiroConfig"})
})
public class RuoYiApplication {
...
}
说明:
- 使用自定义的
@ComponentScan
注解替换@SpringBootApplication
的注解。 - 定义
excludeFilters
属性。该属性指定排除的Bean/类。 - 使用正则表达式方式(
FilterType.REGEX
)排除类"com.ruoyi.framework.config.ShiroConfig"
方式2:自定义 @ComponentScans
@SpringBootApplication
有些特殊,官方的解释是:same as @Configuration @EnableAutoConfiguration @ComponentScan
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
你看!@SpringBootApplication
带了一个 @ComponentScan
。一个 @ComponentScan
会影响 @ComponentScans
(为啥?暂不清楚)。
所以,自定义 @ComponentScans
是应该这样:
@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@ComponentScans({
@ComponentScan(
basePackages = {"com.ruoyi"},
excludeFilters = {
@Filter(type = FilterType.REGEX, pattern = {
"com.ruoyi.framework.config.ShiroConfig"})}),
@ComponentScan(basePackages = {"com.third.package"}),
})
public class RuoYiApplication {
...
}
说明:
- 使用
@Configuration @EnableAutoConfiguration @ComponentScans
替换了@SpringBootApplication
。 - 使用
@ComponentScans
是为了添加多个@ComponentScan
。只有一个@ComponentScan
时,可以不用@ComponentScans
。
方式3:自定义 TypeExcludeFilter
@SpringBootApplication
有些特殊,它带了一个 @ComponentScan
。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
...
}
你看!@SpringBootApplication
自带的 @ComponentScan
中已经有了自定义的 excludeFilters
。可以利用此特性实现排除/不加载某些Bean。
- 实现自己的
TypeExcludeFilter
public class MyTypeExcludeFilter extends TypeExcludeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
if("com.ruoyi.framework.config.ShiroConfig".equals(metadataReader.getClassMetadata().getClassName())){
System.out.println("skip >>>>>>> " + metadataReader.getClassMetadata().getClassName());
return true;
}
return false;
}
}
- 将
MyTypeExcludeFilter
在ApplicationContext Initializer
时注册Bean(通过注解注册的Bean,进入 Spring 容器太晚了,不起作用)。
public class MyTypeExcludeFilterApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(new MyTypeExcludeFilterPostProcessor());
}
private static class MyTypeExcludeFilterPostProcessor
implements PriorityOrdered, BeanDefinitionRegistryPostProcessor {
public static final String BEAN_NAME = "com.ruoyi." + "myTypeExcludeFilter";
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition definition = new RootBeanDefinition(
MyTypeExcludeFilter.class);
registry.registerBeanDefinition(BEAN_NAME, definition);
}
}
}
- 注册
MyTypeExcludeFilterApplicationContextInitializer
在src/main/resources
目录下创建文件META-INF/spring.factories
(如果该文件已存在,则无须创建)。在文件META-INF/spring.factories
中添加内容:
org.springframework.context.ApplicationContextInitializer=\
com.ruoyi.MyTypeExcludeFilterApplicationContextInitializer
说明:操作复杂,实测效果不理想,不推荐使用。
参考
https://www.cnblogs.com/yql1986/p/9418419.html
https://stackoverflow.com/questions/41287276/when-should-i-use-typeexcludefilters-in-spring
https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/reference/htmlsingle/#boot-features-testing-spring-boot-applications-excluding-config