> 文档中心 > Spring源码分析之AOP源码分析

Spring源码分析之AOP源码分析

文章目录

  • 前言
  • 一、AOP回顾
  • 二、源码分析
    • EnableAspectJAutoProxy注解
    • AnnotationAwareAspectJAutoProxyCreator

前言

Spring框架的两大核心思想IOC和AOP,IOC在我们开发中可能除了注入之外真正涉及到的内容不多,大多数是原理性的,而AOP在开发过程中实际用到的就多了,例如常用的事务操作、权限框架、日志记录等,本文简单的就AOP的实现原理做出简单的介绍。

一、AOP回顾

对于Spring中AOP大家在入门的时候应该就已经很清楚了,这里就不过多的介绍了,简单的回顾几个概念

概念 说明
通知(Advice) AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理
连接点(join point) 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出
切点(PointCut) 可以插入增强处理的连接点
切面(Aspect) 切面是通知和切点的结合
引入(Introduction) 引入允许我们向现有的类添加新的方法或者属性
织入(Weaving) 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入

下面在Spring源码中创建AOP的例子。
gradle中的配置:

dependencies {    compile(project(":spring-context"))    compile(project(":spring-aspects"))    testCompile group: 'junit', name: 'junit', version: '4.12'}

写个切面类:

@Aspect@Componentpublic class MyAspect {@Pointcut("execution(public void com.jack.service.TestService.doSomething())")public void point(){}@Before("point()")public void beforeMethod() {System.out.println("beforeMethod----");}}

被代理对象:

@Servicepublic class TestService {public void doSomething(){System.out.println("doSomething---");}}

Config配置

@Configuration@ComponentScan("com.jack.service")@EnableAspectJAutoProxy(proxyTargetClass = true)public class JavaConfig {}

写个测试类:

public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(JavaConfig.class);TestService testService = applicationContext.getBean(TestService.class);testService.doSomething();}

执行结果:
Spring源码分析之AOP源码分析

二、源码分析

EnableAspectJAutoProxy注解

我们知道想要使切面生效必须加EnableAspectJAutoProxy注解,这个注解具体干了什么呢?咱来看一下

@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy {//true使用Cglib代理,false使用Java的Proxyboolean proxyTargetClass() default false;//代理的暴露方式boolean exposeProxy() default false;}

看这个类引入了AspectJAutoProxyRegistrar类,这个类里面只有一个方法手动的注册了一个类。

//注册bean模板public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy =AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);if (enableAspectJAutoProxy != null) {if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);}if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);}}}

代码层层的点击,最后定位到了注册的类为AnnotationAwareAspectJAutoProxyCreator,跟IOC一样注册成为BeanDefinition。

@Nullablepublic static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);}

AnnotationAwareAspectJAutoProxyCreator

上面我们知道了最终注册的类为AnnotationAwareAspectJAutoProxyCreator,这个类是干什么的呢?找到这个类看一下类图,可以看到它最终实现的是BeanPostProcessor,这个类大家应该很熟悉,Bean的后置处理类,可以在bean对象初始化之前和之后做一些处理。
在这里插入图片描述
既然AnnotationAwareAspectJAutoProxyCreator最终实现了BeanPostProcessor,那咱看一下它的前置和后置方法都干了些什么,最终定位到了AbstractAutoProxyCreator父类才实现了前置方法和后置方法,这个地方需要注意一下方法名称因为其中有很多名称相似的方法。

//前置处理没有做任何处理public Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}//后置处理public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {//在这里创建了代理类return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}

继续往下看创建代理类

//这个方法是所有bean对象都会进入的,最终根据是否有代理方法判断是否需要处理protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {... //上面是一堆判断// 看一下是否有代理方法,这个地方可以打断点看一下其实就是代理的before after arround等方法Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);//如果有代理方法则创建代理类if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}

根据断点的截图可以看到被代理对象testService拥有代理方法,咱只写了个前置代理方法那所以就一个
在这里插入图片描述

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}//代理工厂ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);//判断是否设置proxyTargetClass,如果是true的情况下强制使用CGLIB代理,false根据是否实现接口判断if (proxyFactory.isProxyTargetClass()) {//true的情况增加接口来实现强制CGLIB代理,其实没有强制这一说,接口的用CGLIB代理,通过参数配置接口让其后面用CGLIB代理if (Proxy.isProxyClass(beanClass)) {for (Class<?> ifc : beanClass.getInterfaces()) {proxyFactory.addInterface(ifc);}}}else {// 此时是false的,判断是否是对类进行的代理,设置对应参数if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}//把其他拦截器和代理合并一下,由于没有其他的方法拦截,所以这里最终结果还是上面截图的那个Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}//准备工作做完后开始创建代理return proxyFactory.getProxy(getProxyClassLoader());}

看一下创建代理,最后使用的代理工厂创建的代理

public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);}//创建代理方法,config记录了一些配置信息public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {//获取被代理的对象class,然后做判断区分不同的代理方式Class<?> targetClass = config.getTargetClass();...//看一下,代理接口的时候使用的JDK代理,咱写的Class所以使用的CGLIB代理的if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}//其他的使用的是CGLIB动态代理return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}}

getProxy()有两个具体实现方法,一个是JDK代理一个是CGLIB代理,通过createAopProxy判断不同的代理方式来调用。

饲料网