zoukankan      html  css  js  c++  java
  • 记一次Spring配置事故

    在引入Spring的Validated时,需要声明如下bean:
     
    @Bean
    public
    MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor(); }
    出于偷懒,放在了如下的一个初始化中:
    @Configuration
    public class ConfigService implements WebMvcConfigurer {
        @Resource
        private LogService logService;
        @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)
    在如下代码块中
    @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上下文初始化的过程可以看出来。
    在注册BeanPostProcessor时,会区分出priorityOrderedPostProcessor,internalPostProcessor,orderedPostProcessor,noOrderedPostProcessor等4个级别的BeanPostProcessor。
    按注册顺序为:priorityOrderedPostProcessor -> orderedPostProcessor -> noOrderedPostProcessor -> internalPostProcessor。
    每个BeanPostProcessor会先实例化,然后再进行注册。在实例化完成后,会进行实例化后置处理。
    在这个后置处理中,有一个关键的BeanPostProcessor是BeanPostProcessorChecker。在其后置处理逻辑中会检查并抛出上述问题的错误提示。
    其处理代码如下:
            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;
            }

    这部分代码逻辑如下:

    当实例化的bean不为BeanPostProcessor,且不是归属框架类的bean定义,且当前已注册的BeanPostProcessor比初始化时登记的数量小(代表还未注册所有的BeanPostProcessor到beanFactory中,因为不同级别的BeanPostProcessor是分别处理的,故存在数量逐渐增加的这么一个过程)时,发起bean告警,提示该bean可能是不完全正确的,因为未经过所有BeanPostProcessor的前置后置处理。

    上面的问题,是因为在orderedPostProcessor集合初始化过程中引入了业务bean的初始化,导致部分业务bean提前初始化没有被所有的BeanPostProcessor前后置处理,使得事务失效。

    解决办法有很多种,上面列出来的单独一个类是一种方式,还可以在@Bean修饰的方法上增加static修饰。

    因为@Configuration注解会对修饰的类进行CGLIB增强,会跳过static修饰的方法增强处理,不会导致业务bean的提前初始化;

    在单独的类中,也可以移除@configuration注解,spring会将@Bean修饰的方法视为工厂方法,此时也不会导致注入的业务bean被提前初始化。

    参考资料:

    https://docs.spring.io/spring/docs/4.2.x/javadoc-api/org/springframework/context/annotation/Bean.html

     
  • 相关阅读:
    调整数组顺序使奇数位于偶数前面
    数值的整数次方
    矩形覆盖
    变态跳台阶
    跳台阶
    ubuntu图形界面切换文字界面(文字界面切换图形界面)
    Django环境安装、虚拟机端口映射、pycharm远程配置
    sql注入(一)-----数字型
    mysql基本语法
    渗透测试之------信息收集
  • 原文地址:https://www.cnblogs.com/asfeixue/p/9535851.html
Copyright © 2011-2022 走看看