記一次Spring配置事故


在引入Spring的Validated時,需要聲明如下bean:
 
@Bean
public
MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor(); }

 

出於偷懶,放在了如下的一個初始化中:
@Configuration
public class ConfigService implements WebMvcConfigurer {
 
.........
 
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
 
.........
 
}

 

配置好后,@Validated生效了,但是aop,事務等出現異常。啟動日志如下:
2018-08-25 20:03:09 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'org.springframework.boot.context.properties.ConversionServiceDeducer$Factory' of type [org.springframework.boot.context.properties.ConversionServiceDeducer$Factory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:09 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'mybatis-org.mybatis.spring.boot.autoconfigure.MybatisProperties' of type [org.mybatis.spring.boot.autoconfigure.MybatisProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:09 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration' of type [org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration$$EnhancerBySpringCGLIB$$f57f05de] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:09 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari' of type [org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:09 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties' of type [org.springframework.boot.autoconfigure.jdbc.DataSourceProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:09 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'dataSource' of type [com.zaxxer.hikari.HikariDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:10 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'sqlSessionFactory' of type [org.apache.ibatis.session.defaults.DefaultSqlSessionFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2018-08-25 20:03:10 [INFO] [main] [o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker][328] Bean 'sqlSessionTemplate' of type [org.mybatis.spring.SqlSessionTemplate] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

 

從日志提示的地方看到如下代碼:
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            if (!(bean instanceof BeanPostProcessor) && !isInfrastructureBean(beanName) &&
                    this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount) {
                if (logger.isInfoEnabled()) {
                    logger.info("Bean '" + beanName + "' of type [" + bean.getClass().getName() +
                            "] is not eligible for getting processed by all BeanPostProcessors " +
                            "(for example: not eligible for auto-proxying)");
                }
            }
            return bean;
        }

 

因為問題的引入是已知的,所以,在這里打了斷點測試了下進入的條件。發現在加上MethodValidationPostProcessor的bean時,this.beanFactory.getBeanPostProcessorCount()獲取到的值為10,不加這個bean時,獲取到的值為21.那有問題,肯定是構造完成后,處理流程差異導致的問題。從構造函數開始尋找BeanPostProcessorChecker的初始化地點。
從這里找到PostProcessorRegistrationDelegate的registerBeanPostProcessors方法,
        int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
        beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
 
        // Separate between BeanPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.

 

從注釋中可以看出,在初始化BeanPostProcessorChecker后,又繼續初始化高優先級的,有順序要求的,然后是剩下的BeanPostProcessor。
往下看:
        // First, register the BeanPostProcessors that implement PriorityOrdered.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
 
        // Next, register the BeanPostProcessors that implement Ordered.
        List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
        for (String ppName : orderedPostProcessorNames) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            orderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        }
        sortPostProcessors(orderedPostProcessors, beanFactory);
        registerBeanPostProcessors(beanFactory, orderedPostProcessors);
 
        // Now, register all regular BeanPostProcessors.

 

在初始化高優先的BeanPostProcessor后,開始load帶有順序條件的BeanPostProcessor,准備初始化。
回到最開始,我們的MethodValidationPostProcessor的父類實現了Ordered接口。故也在這個for循環的加載過程中load進來,此時,在加載的時候出現問題。
在如下代碼塊中
@Configuration
public class ConfigService implements WebMvcConfigurer {
    @Resource
    private LogService logService;
 
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

 

我們注入了業務定義的bean,而這些bean是由最低優先級的BeanPostProcessor來加載並完成初始化的。但此時,為了加載其中的MethodValidationPostProcessor,導致不得不優先裝載低優先級bean,此時,aop處理器,數據庫處理器等都未完成裝載,故由這部分業務bean牽扯到的相關邏輯的aop初始化,注解事務初始化,都事實上失敗了。但spring就提示了一個INFO級別的提示,然后剩下的bean由最低優先級的BeanPostProcessor正常處理。
 
問題找到后,解決的方式很簡單,由框架層初始化的bean,不要牽扯到業務層。不然即便初始化成功,也會導致一些模塊因為順序的緣故,未完成合適的處理流程,比如aop。
針對我這里的問題,如下解決:
@Configuration
public class MethodValidation {
 
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }
}

 

重新創建一個類,單獨初始化此類即可。 


免責聲明!

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



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