image.png

spring aop默认使用哪一种动态代理?
这个问题就是个坑

代理创建

直接看demo

编写一个UserServiceImpl,实现UserService,使用AspectJ注解形式写一个切面类(需开启@EnableAspectJ***注解,不然测试方法不会走代理);

@Service public class UserServiceImpl implements UserService { @Override public List<User> findAll() {
        System.out.println("11111111"); return null;
    }
} @Component @Aspect public class Aop { @Pointcut("execution(* com.yang.service..*.*(..))") public void pointcut() {
        } @Before("pointcut()") public void before() {
                System.out.println("增强-------------------------------------------");
        }
}
image.png

从上图可以看到,获得的service实例其实是一个JDK代理的UserServiceImpl对象。

接下来修改UserServiceImpl类,改成不实现UserService,稍微改下getBean那行的代码再运行看下结果:

image.png

结果发现:从jdk代理的对象变成了cglib代理对象。

结论:(1)如果目标对象实现了接口,默认会采用JDK的动态代理机制实现AOP

(2)如果目标对象没有实现接口,必须使用CGLIB生成代理,Spring会自动在CGLIB和JDK动态代理之间切换

追踪源码

从cfg.getBean()方法查找源码看是如何处理的,在下图代码处debug模式下添加Condition;

image.png

image.png

跟到doGetBean方法看到是经过Object sharedInstance = getSingleton(beanName)这行代码后生成的代理对象;

进入getSingleton方法后发现其是从singletonObjects获取的bean,其实就是从三级缓存的单例池中拿到的,不懂的小伙伴可以去看一下spring启动流程的源码。

image.png

image.png

我们顺藤摸瓜,找到此map的put方法,只有一个,添加断点,重新debug启动测试;

image.png

image.png

上图可以看到put的确实是代理对象,接下来通过该方法的调用栈去分析是哪一步生成的代理对象。

image.png

定位到是在createBean(beanName, mbd, args);这一步操作

image.png

在 doCreateBean(beanName, mbdToUse, args)方法执行后获取的代理对象,接着深入;

image.png

从图中可以看到bean是经过initializeBean方法后变成了代理对象;

image.png

image.png

到此发现经过一个叫AnnotationAwareAspectJ***Creator的Bean后置处理器后返回的代理对象;

发现AnnotationAwareAspectJ***Creator继承了Abstract***Creator,顶层并实现了BeanPostProcessor;

实现了BeanPostProcessor要实现其两个重要方法:postProcessBeforeInitialization和postProcessAfterInitialization

而执行AnnotationAwareAspectJ***Creator中并没有postProcessAfterInitialization这个方***调父类Abstract***Creator中的。

image.png

Abstract***Creator的postProcessAfterInitialization方***调wrapIfNecessary;

image.png

wrapIfNecessary方法中执行了createProxy();

image.png

到此终于找到了答案,会根据是否有实现了接口,Spring会自动在CGLIB和JDK动态代理之间切换。

其中if中的config.isProxyTargetClass() 正式我们使用的注解@EnableAspectJ***(proxyTargetClass = false)中配置的参数。

该属性值默认为false,表示使用JDK动态代理增强;当值为true时,表示使用CGLib动态代理增强;但是,即使设置为false,如果目标类没有实现接口,则Spring将自动使用CGLib动态代理。

image.png

下一章讲怎么发现@aspect注解并解析我们的切入点的,以及为什么要使用@EnableAspectJ***注解