• 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

  • 相关阅读:
    vue中使用keepAlive(缓存页面&记忆上次浏览位置)及使用后生命周期的改变
    vue搭配antD-Vue开发项目(一)
    vscode使用
    vue移动端项目经验(三)
    [CF960F] Pathwalks
    [CF1004E] Sonya and Ice-cream
    [CF1142B] Lynyrd Skynyrd
    [CF55D] Beautiful numbers
    [洛谷P4438] HNOI2018 道路
    JOI2019 有趣的家庭菜园3
  • 原文地址:https://www.cnblogs.com/yql1986/p/9418419.html
Copyright © 2020-2023  润新知