spring boot之org.springframework.boot.context.TypeExcludeFilter


曾經碰到過這樣一種情況,想讓某個使用了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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM