spring boot֮org.springframework.boot.context.TypeExcludeFilter

匿名 (未验证) 提交于 2019-12-02 20:37:20

曾经碰到过这样一种情况,想让某个使用了spring 注解的类不被spring扫描注入到spring bean池中,比如下面的类使用了@Component和@ConfigurationProperties("example1.user")自动绑定属性,不想让这个类被注入。

 1 package com.github.torlight.sbex;  2   3 import java.io.Serializable;  4   5 import org.springframework.boot.context.properties.ConfigurationProperties;  6 import org.springframework.stereotype.Component;  7   8 @Component  9 @ConfigurationProperties("example1.user") 10 public class User implements Serializable{ 11      12     private static final long serialVersionUID = 6913838730034509179L; 13  14     private String name; 15      16     private Integer age; 17  18     public String getName() { 19         return name; 20     } 21  22     public void setName(String name) { 23         this.name = name; 24     } 25  26     public Integer getAge() { 27         return age; 28     } 29  30     public void setAge(Integer age) { 31         this.age = age; 32     } 33      34      35 }

一开始不想使用BeanPostProcessor接口的实现类来实现这样的功能,想可以借助@SpringBootApplication注解,使用exclude来实现该功能。

 1 package com.github.torlight.sbex;  2   3 import org.springframework.boot.SpringApplication;  4 import org.springframework.boot.autoconfigure.SpringBootApplication;  5 import org.springframework.context.ApplicationContext;  6 import org.springframework.context.annotation.Bean;  7   8   9 /** 10  * Hello world! 11  * 12  */ 13 @SpringBootApplication(exclude={com.github.torlight.sbex.User.class}) 14 public class Example1 { 15      16  17     @Bean 18     public UserAction userAction(){ 19         return new UserAction(); 20     } 21      22      23     public static void main( String[] args ) { 24         25      ApplicationContext context= SpringApplication.run(Example1.class, args); 26       27      ((UserAction)context.getBean(UserAction.class)).sysOutUserInfo();   28         29     } 30 }

运行程序后,控制台报如下错误:

2018-08-04 13:15:57.079 ERROR 4504 --- [           main] o.s.boot.SpringApplication               : Application startup failed  org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [com.github.torlight.sbex.Example1]; nested exception is java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes:     - com.github.torlight.sbex.User      at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:556) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:185) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:308) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:270) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:93) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at com.github.torlight.sbex.Example1.main(Example1.java:25) [classes/:na] Caused by: java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes:     - com.github.torlight.sbex.User      at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.handleInvalidExcludes(AutoConfigurationImportSelector.java:193) ~[spring-boot-autoconfigure-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.checkExcludedClasses(AutoConfigurationImportSelector.java:178) ~[spring-boot-autoconfigure-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.selectImports(AutoConfigurationImportSelector.java:100) ~[spring-boot-autoconfigure-1.5.4.RELEASE.jar:1.5.4.RELEASE]     at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:547) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]     ... 14 common frames omitted

错误提示不能使用exclude={com.github.torlight.sbex.User.class},因为该类不并不是被spring boot自动装配的类,类似于RedisAutoConfiguration这样的类。仔细研究一番后,发现可以扩展org.springframework.boot.context.TypeExcludeFilter来实现这一功能。spring boot在执行扫描过程中,会使用TypeExcludeFilter进行过滤。

 1 public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {  2   3     private BeanFactory beanFactory;  4   5     @Override  6     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {  7         this.beanFactory = beanFactory;  8     }  9  10     @Override 11     public boolean match(MetadataReader metadataReader, 12             MetadataReaderFactory metadataReaderFactory) throws IOException { 13         if (this.beanFactory instanceof ListableBeanFactory 14                 && getClass().equals(TypeExcludeFilter.class)) { 15             Collection<TypeExcludeFilter> delegates = ((ListableBeanFactory) this.beanFactory) 16                     .getBeansOfType(TypeExcludeFilter.class).values(); 17             for (TypeExcludeFilter delegate : delegates) { 18                 if (delegate.match(metadataReader, metadataReaderFactory)) { 19                     return true; 20                 } 21             } 22         } 23         return false; 24     } 25  26     @Override 27     public boolean equals(Object obj) { 28         throw new IllegalStateException( 29                 "TypeExcludeFilter " + getClass() + " has not implemented equals"); 30     } 31  32     @Override 33     public int hashCode() { 34         throw new IllegalStateException( 35                 "TypeExcludeFilter " + getClass() + " has not implemented hashCode"); 36     } 37  38 }

可以看出,spring boot会加载spring bean池中所有针对TypeExcludeFilter的扩展,并循环遍历这些扩展类调用其match方法。那么思路出来了,只要继承该类并重写match方法,在该方法内部进行相应的处理即可。示例代码如下:

 1 public class MyTypeExcludeFilter extends TypeExcludeFilter {  2   3     @Override  4     public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)  5             throws IOException {  6           7         if("com.github.torlight.sbex.User".equals(metadataReader.getClassMetadata().getClassName())){  8             return true;  9         } 10          11         return false; 12     } 13      14 }

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled. 2018-08-04 13:27:14.556 ERROR 4964 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   :   *************************** APPLICATION FAILED TO START ***************************  Description:  Field user in com.github.torlight.sbex.UserAction required a bean of type 'com.github.torlight.sbex.User' that could not be found.   Action:  Consider defining a bean of type 'com.github.torlight.sbex.User' in your configuration.

相关示例代码已经上传到github上面,https://github.com/gittorlight/springboot-example

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!