在引入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(); } }
重新創建一個類,單獨初始化此類即可。