Java-Shiro是如何影响自定义BeanPostProcessor运作

介绍Shiro是如何影响自定义BeanPostProcessor运作。

Let‘s Go!


1.解决方案

  • 隔离shiro使用的组件与业务监控的组件。

如:shiro使用的redis实例和业务使用的redis实例不使用同一个,但一定要将需要监控的组件托管给spring

2.场景

3.问题现象

  • 加入通过自定义BeanPostProcessor的监控组件之后,不能监控mysql和redis。

错误信息

2019-07-31 17:20:54.311 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'spring.redis-org.springframework.boot.autoconfigure.data.redis.RedisProperties' of type [org.springframework.boot.autoconfigure.data.redis.RedisProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:54.556 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'lettuceConnectionFactory' of type [org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:54.693 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'shiroRedisTemplate' of type [org.springframework.data.redis.core.RedisTemplate] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:54.883 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'shiroConfig' of type [com.common.security.config.ShiroConfig$$EnhancerBySpringCGLIB$$37c03ac9] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:57.525 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'redisCacheManager' of type [com.common.security.cache.RedisCacheManager] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:58.060 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'sessionFactory' of type [com.common.security.config.SessionFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:58.227 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'sessionManager' of type [org.apache.shiro.web.session.mgt.DefaultWebSessionManager] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:20:58.725 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'securityManager' of type [org.apache.shiro.web.mgt.DefaultWebSecurityManager] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:15.457 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'mybatis-plus-com.baomidou.mybatisplus.spring.boot.starter.MybatisPlusProperties' of type [com.baomidou.mybatisplus.spring.boot.starter.MybatisPlusProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:16.404 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'mybatisPlusConfig' of type [com.common.config.MybatisPlusConfig$$EnhancerBySpringCGLIB$$48de742d] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:16.704 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'performanceInterceptor' of type [com.baomidou.mybatisplus.plugins.PerformanceInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:16.793 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'paginationInterceptor' of type [com.baomidou.mybatisplus.plugins.PaginationInterceptor] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:17.156 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'com.baomidou.mybatisplus.spring.boot.starter.MybatisPlusAutoConfiguration' of type [com.baomidou.mybatisplus.spring.boot.starter.MybatisPlusAutoConfiguration$$EnhancerBySpringCGLIB$$61864f65] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:17.334 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Generic' of type [org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Generic] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-07-31 17:32:19.705 restartedMain | [] | INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker 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)

4.问题分析

初步分析

  • 通过查看错误信息log发现,其中会包含redis与mysql,是否这些提示就是和无法使用BeanPostProcessor有关系呢?
  • 通过not eligible for auto-proxying信息查找到对应的代码,为什么是:not eligible for auto-proxying 不适用于自动代理?
    public Object postProcessAfterInitialization(Object bean, String beanName) {
              if (bean != null && !(bean instanceof BeanPostProcessor) && !this.isInfrastructureBean(beanName) && this.beanFactory.getBeanPostProcessorCount() < this.beanPostProcessorTargetCount && 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;
          }
    
  • 仔细观察之下发现,log会归为几类:shiro、redis、jdbc、session。redis和jdbc都是需要监控的组件,会影响bbp吗?先假定不会。那么就剩下shiro了。
  • 尝试把shiro屏蔽,错误信息中的log没了一大部分,自定义的bbp也能进去了,为什么呢?

深入分析

  • shiroFilter依赖了securityManager,securityManager依赖了userRealm,userRealm为了获取AuthenticationInfo和AuthorizationInfo又依赖了redis和mysql。
  • ShiroFitlerFactoryBean这个bean继承了FactoryBean,将SecurityManager提前初始化,并无将初始化过程托管给spring,导致其所有引用的类都没有托管给spring,所以自定义bpp无效。

测试代码

结果:helloA 证明:增加了factorybean之后,并不会走自定义bpp

去掉factorybean之后,托管给spring初始化之后 结果: sayHello InitBBean before sayHello InitABean before helloA sayHello InitABean after sayHello InitBBean after

测试用例
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Conf.class)
public class BeanPostProcessorTestTest {

    @Autowired
    BeanPostProcessorATest test;

    @Test
    public void sayHello() {
        test.sayHello();
    }
}
被测试代码
public interface BeanPostProcessorTest {

    void sayHello();
}
public class BeanPostProcessorATest implements BeanPostProcessorTest {

    @Override
    public void sayHello(){
        System.out.println("helloA");
    }
}
public class BeanPostProcessorBTest implements BeanPostProcessorTest {

    @Override
    public void sayHello(){
        System.out.println("helloB");
    }
}
@Configuration
@ComponentScan
public class Conf {
}

@Component
public class InitABean implements FactoryBean<BeanPostProcessorATest>,BeanPostProcessor
{

    private BeanPostProcessorATest instance;
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof BeanPostProcessorATest){
            ProxyFactoryBean pfb = new ProxyFactoryBean();
            pfb.setTarget(bean);
            pfb.setAutodetectInterfaces(false);
            NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
            advisor.addMethodName("sayHello");
            advisor.setAdvice((MethodInterceptor) invocation -> {
                System.out.println("sayHello InitABean before");
                Object result = invocation.getMethod().invoke(invocation.getThis(), invocation.getArguments());
                System.out.println("sayHello InitABean after");
                return result;
            });
            pfb.addAdvisor(advisor);

            return pfb.getObject();
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public BeanPostProcessorATest getObject() throws Exception {
        if (this.instance == null) {
            this.instance = new BeanPostProcessorATest();
        }
        return this.instance;
    }

    @Override
    public Class<?> getObjectType() {
        return BeanPostProcessorATest.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

@Component
public class InitBBean implements BeanPostProcessor
{
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if(bean instanceof BeanPostProcessorATest){
            ProxyFactoryBean pfb = new ProxyFactoryBean();
            pfb.setTarget(bean);
            pfb.setAutodetectInterfaces(false);
            NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
            advisor.addMethodName("sayHello");
            advisor.setAdvice((MethodInterceptor) invocation -> {
                System.out.println("sayHello InitBBean before");
                Object result = invocation.getMethod().invoke(invocation.getThis(), invocation.getArguments());
                System.out.println("sayHello InitBBean after");
                return result;
            });
            pfb.addAdvisor(advisor);

            return pfb.getObject();
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
Written on July 29, 2019