BeanNameAutoProxyCreator 实际上是通过为目标bean创建代理类然后为其织入advice实现的自动代理
如此就引发一个问题:当使用BeanNameAutoProxyCreator为controller实现自动代理并拦截对应方法后
会影响到controller本身,servlet在为controller创建映射关系时因为代理类的干扰而映射失败,导致访问对应的url时报404错误
解决方案:super.setOptimize(true);设置为最优使用cglib代理
原理分析:optimize默认是false,使用jdk动态代理。
1-1、JDK动态代理只能针对实现了接口的类生成代理,此时代理对象和目标对象实现了相同的接口,目标对象作为代理对象的一个属性,具体接口实现中,可以在调用目标对象相应方法前后加上其他业务处理逻辑。
1-2、CGLIB代理是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的(利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理)
1-3、DefaultAopProxyFactory创建代理代码如下
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } }
2、servletDispatcher 分配url时
AbstractHandlerMethodMapping.initHandlerMethods方法判断对应controller是否需要映射时就会出问题了。
2-1、因为jdk动态代理已经是一个$proxy类来代替controller了,所有获取其注解@controller和@requestMapping时会获取不到,从而么有映射map关系,url访问时就会报404了
initHandlerMethods方法关键代码:
for (String beanName : beanNames) {
if (isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } }isHandler方法关键代码:
protected boolean isHandler(Class<?> beanType) {
return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) || (AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null)); }此时的beanType是$proxy类,已经获取不到对应的注解了