learn and grow up

解析springBean类的注解引发的一系列如AOP|cglib代理等问题一

字数统计: 685阅读时长: 2 min
2020/05/24 Share

写在前面

接上一篇,同样的需求:需要写一个针对controller内参数的数据权限校验组件,所以需要想办法获取都某个对象的某个变量(可能跨层级)的值,所以研究和封装了一套可以使用的工具。这个工具类需要开发时定义好取值的路径,最终决定使用对参数注解,这样就可以针对单独参数的某个值进行权限校验。

开发思路:

​ 1、在controller层的方法的参数上进行注解

​ 2、为了提高拦截时的程序运行效率,项目启动时扫描所有注解的参数的方法放入缓存

​ 3、aop拦截时进行判断是否需要存在于缓存,如有则进行权限校验

问题

写完了注解代码,然后决定使用BeanPostProcessor来进行controller方法的注解解析。

BeanPostProcessor应该很多人都了解,主要是对bean实例化前后的增强,实现了该接口后,主要流程如下

1
2
3
4
===Spring IOC容器实例化Bean===
===调用BeanPostProcessor的postProcessBeforeInitialization方法===
===调用bean实例的初始化方法===
===调用BeanPostProcessor的postProcessAfterInitialization方法===

所以我写了如下方法进行扫描,但是本以为顺理成章的流程却出现了问题,问题见注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//无关代码已省略

@Override
@Nullable
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//对controller进行解析和注入
RestController restController = bean.getClass().getAnnotation(RestController.class);
if(restController==null){
//问题在这里:所有的controller都走了这里,Annotion判断不成功
return bean;
}
Class cls = bean.getClass();
List<Method> methods = findAllMethod(cls);
if(CollectionUtils.isEmpty(methods)){
return bean;
}
for(Method method : methods){
checkMethod(method);

}

return bean;
}

上面的错误经过多此debug排查终于找到原因:SpringAOP引起的。具体如下截图

原因

可以看到图中标示处,beanObject的className为springCglib的动态代理类!所以通过反射拿到的class肯定不会有我们在controller里写的注解。

但是为什么bean实例对象是动态代理类呢?突然想起来之前用了AOP,如下

AOP

,设置了controller的切面来进行日志打印和输出,所以spring会自动帮我们把bean设置为动态代理后的实例。

找到了问题才可以对症下药

解决方案

1、如果不需要init初始化后置处理,则可以使用postProcessBeforeInitialization而非postProcessBeforeInitialization

2、实现Order接口,将order值set为AOP相关BeanPostProcessor的前面(具体原理后面几篇讲到)

3、寻找cglib内部结构,再通过java反射获取真实的代理对象(正在研究中,应该可以实现)

CATALOG
  1. 1. 写在前面
  2. 2. 问题
  3. 3. 解决方案