1. 程式人生 > >記一次Spring配置事故

記一次Spring配置事故

vcc @override iba initial web color 差異 info ida

在引入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();
    }
}

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

記一次Spring配置事故