Spring AOP 源码解析

一、什么是AOP

Spring AOP依赖于IOC相关的知识

AOP面向切面编程,它底层基于动态代理实现,而动态代理又可分为jdk动态代理和cglib动态代理

面向切面编程,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

通俗描述,不通过修改源代码方式,在主干功能里面添加新功能

如果对Spring IOC不大清楚,请参考上一篇博客Spring IOC容器源码解析Spring扩展点解析Spring AOP的使用

为了通俗的理解AOP,下面举一个例子

有A,B,C三个方法,但是在调用每一个方法之前,要求打印一个日志:某一个方法被开始调用了!

在调用每个方法之后,也要求打印日志:某个方法被调用完了!


一般人会在每一个方法的开始和结尾部分都会添加一句日志打印吧,这样做如果方法多了,就会有很多重复的代码,显得很麻烦。

这时候有人会想到,为什么不把打印日志这个功能封装一下,然后让它能在指定的地方(比如执行方法前,或者执行方法后)自动的去调用呢?

如果可以的话,业务功能代码中就不会掺杂其他的代码,所以AOP就是做了这一类的工作,比如,日志输出,事务控制,异常的处理等...


如果把AOP当做给我们写的“业务功能”增添一些特效,就会有这么几个问题:

1.我们要制作哪些特效

2.这些特效使用在什么地方

3.这些特效什么时候来使用

有了这三个疑问,加上上面的讲解,下面我们来说一下AOP的一些术语

1.通知 (Advice):又叫增强,就是你想要的功能,也就是上面说的 安全,事物,日志等。你把它先定义好,然后在想用的地方用一下。

2.连接点 (JoinPoint):这个更好解释了,就是spring允许你使用通知的地方,那可真就多了,基本每个方法的前,后(两者都有也行),或抛出异常时都可以是连接点,spring只支持方法连接点。

其他如aspectJ还可以让你在构造器或属性注入时作为连接点,不过那不是咱关注的,只要记住,和方法有关的前前后后(抛出异常),都是连接点。

3.切入点 (Pointcut):在上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对吧,但是你并不想在所有方法附近都使用通知(使用叫织入,以后再说)

你只想让其中的几个,在调用这几个方法之前,之后或者抛出异常时干点什么,那么就用切点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。

4.切面 (Aspect):是一个动作,把通知应用到切入点的过程。切面是通知和切入点的结合。现在发现了吧,没连接点什么事情,连接点就是为了让你好理解切点,搞出来的,明白这个概念就行了。

通知说明了干什么和什么时候干(什么时候通过方法名中的Before,After,Around等就能知道),而切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。

5.引入 (introduction):允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗

6.目标 (target):引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咱们织入切面。而自己专注于业务本身的逻辑。

7.代理 (proxy):怎么实现整套AOP机制的,都是通过代理,这个一会给细说。

8.织入 (weaving):把切面应用到目标对象来创建新的代理对象的过程。有3种方式,spring采用的是运行时,为什么是运行时,后面解释。

关键就是:切点定义了哪些连接点会得到通知

二、调试代码

@Configuration
@ComponentScan(value = "com.best")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}
// 被增强类
@Component
public class Calculator {

    public Integer add(Integer a, Integer b) {
        int sum = a + b;
        return sum;
    }
}
/ 增强的类
@Aspect // 生成代理对象
@Component
public class LogUtil {

    @Pointcut("execution(* *(..))")
    public void myPointCut(){}

    // 前置通知
    @Before(value = "myPointCut()")
    @Order(1)
    public int before(JoinPoint joinPoint) {
        // 获取方法签名
        Signature signature = joinPoint.getSignature();
        // 获取参数信息
        Object[] args = joinPoint.getArgs();
        System.out.println("log---before: " + signature.getName() + "方法执行: 参数是" + Arrays.asList(args));
        return 100;
    }

    // 后置通知(返回通知)
    @AfterReturning(value = "myPointCut()", returning = "result")
    @Order(2)
    public void afterReturning(JoinPoint joinPoint, Object result) {
        Signature signature = joinPoint.getSignature();
        System.out.println("log---afterReturning: " + signature.getName() + "方法执行结束,结果是: " + result);
    }

    // 最终通知
    @After("myPointCut()")
    @Order(3)
    public void after(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        System.out.println("log---after: " + signature.getName() + "方法执行结束");
    }

    // 异常通知
    @AfterThrowing(value = "myPointCut()", throwing = "e")
    @Order(4)
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        Signature signature = joinPoint.getSignature();
        System.out.println("log---afterThrowing: " + signature.getName() + "方法抛出异常: " + e.getMessage());
    }

    @Around("myPointCut()")
    @Order(5)
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Signature signature = pjp.getSignature();
        Object[] args = pjp.getArgs();
        Object result = null;
        try {
            System.out.println("log---around---start: " + signature.getName() + "方法执行");
            // 通过反射的方式调用目标的方法,相当于执行method.invoke(),可以自己修改结果值
            result = pjp.proceed(args);
            // result = 100;
            System.out.println("log---around---stop: " + signature.getName() + "方法执行结束");
        } catch (Throwable throwable) {
            System.out.println("log---around---异常: " + signature.getName() + "出现异常");
            throw throwable;
        } finally {
            System.out.println("log---around---返回: " + signature.getName() + "返回结果: " + result);
        }
        return result;
    }
}

 

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        Calculator calculator = (Calculator) applicationContext.getBean("calculator");
        System.out.println("*********调用业务逻辑**********");
        calculator.add(1, 2);
    }
}

 执行结果:

三、Spring AOP实现原理

在 Spring 的容器中,我们面向的对象是一个个的 bean 实例,bean 是什么?

我们可以简单理解为是 BeanDefinition 的实例,Spring 会根据 BeanDefinition 中的信息为我们生产合适的 bean 实例出来。

当我们需要使用 bean 的时候,通过 IOC 容器的 getBean(…) 方法从容器中获取 bean 实例,只不过大部分的场景下,我们都用了依赖注入,所以很少手动调用 getBean(...) 方法。

Spring AOP 的原理很简单,就是动态代理,它和 AspectJ 不一样,AspectJ 是直接修改掉你的字节码。

代理模式很简单,接口 + 真实实现类 + 代理类,其中 真实实现类 和 代理类 都要实现接口,实例化的时候要使用代理类。

所以,Spring AOP 需要做的是生成这么一个代理类,然后替换掉真实实现类来对外提供服务

替换的过程怎么理解呢?

在 Spring IOC 容器中非常容易实现,就是在 getBean(…) 的时候返回的实际上是代理类的实例,而这个代理类我们自己没写代码,它是 Spring 采用 JDK ProxyCGLIB 动态生成的。


getBean(…) 方法用于查找或实例化容器中的 bean,这也是为什么 Spring AOP 只能作用于 Spring 容器中的 bean 的原因,对于不是使用 IOC 容器管理的对象,Spring AOP 是无能为力的。

3.1 IOC容器管理AOP实例

本节介绍 Spring AOP 是怎么作用于 IOC 容器中的 bean 的。

Spring AOP的使用介绍那篇文章已经介绍过 DefaultAdvisorAutoProxyCreator 类了,它能实现自动将所有的 advisor 生效。

这里我们来理解 Advisor 的概念,它也比较简单,它内部需要指定一个 AdviceAdvisor 决定该拦截哪些方法,功能如@Pointcut。拦截后需要完成的工作还是内部的 Advice 来做。

它有好几个实现类,这里我们使用实现类 NameMatchMethodPointcutAdvisor 来演示,从名字上就可以看出来,它需要我们给它提供方法名字,这样符合该配置的方法才会做拦截。

advisor 负责匹配方法,内部的 advice 负责实现方法包装。相比直接指定 advice,advisor 实现了更细粒度的控制

 Advisor 还有一个更加灵活的实现类 RegexpMethodPointcutAdvisor,它能实现正则匹配,也就是说,我们能通过配置 Advisor,精确定位到需要被拦截的方法,然后使用内部的 Advice 执行逻辑处理。

之后,我们需要配置 DefaultAdvisorAutoProxyCreator,它的配置非常简单,直接使用下面这段配置就可以了,它就会使得所有的 Advisor 自动生效,无须其他配置。


 
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

我们来追踪下 DefaultAdvisorAutoProxyCreator 类,看看它是怎么一步步实现的动态代理。然后在这个基础上,我们再简单追踪下 @AspectJ 配置方式下的源码实现。

首先,先看下 DefaultAdvisorAutoProxyCreator 的继承结构:

我们可以发现,DefaultAdvisorAutoProxyCreator 最后居然是一个 BeanPostProcessor,在 Spring IOC 源码分析的时候说过,BeanPostProcessor 的两个方法,分别在 init-method 的前后得到执行。

 这里再贴一下 IOC 的源码,我们回顾一下:

// AbstractAutowireCapableBeanFactory

在上面第 3 步 initializeBean(...) 方法中会调用 BeanPostProcessor 中的方法,如下:

也就是说,Spring AOP 会在 IOC 容器创建 bean 实例的最后对 bean 进行处理。其实就是在这一步进行代理增强

我们回过头来,DefaultAdvisorAutoProxyCreator 的继承结构中,postProcessAfterInitialization() 方法在其父类 AbstractAutoProxyCreator 这一层被覆写了:

// AbstractAutoProxyCreator

	@Override
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
		// 获取当前bean的key: 如果beanName不为空,则以beanName为key, 如果为FactoryBean类型,
		// 前面还会添加$符号,如果beanName为空,则以当前bean对应的class为key
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			// 判断当前bean是否正在被代理,如果正在被代理则不进行封装
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				// 如果它需要被代理,则需要封装指定的bean
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

继续往里看 wrapIfNecessary(...) 方法,这个方法将返回代理类(如果需要的话):

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		// 如果已经处理过,直接返回
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		// 这里advisedBeans缓存了已经进行了代理的bean,如果缓存中存在,则可以直接返回
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		// 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,自带的bean是不用进行代理的;
		// shouldSkip()则用于判断当前bean是否应该被略过
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			// 对当前bean进行缓存
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		// 获取当前bean的Advices和Advisors;
		// 返回匹配当前 bean 的所有的 advisor、advice、interceptor
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		// 对当前bean的代理状态进行缓存
		if (specificInterceptors != DO_NOT_PROXY) {
			// 对当前bean的代理状态进行缓存
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			// 根据获取到的Advices和Advisors为当前bean生成代理对象
			// 创建代理...创建代理...创建代理...
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			// 缓存生成的代理bean的类型,并且返回生成的代理bean
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

这里有两个点提一下:

getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null),这个方法将得到所有的可用于拦截当前 bean 的 advisor、advice、interceptor。

另一个就是 TargetSource 这个概念,它用于封装真实实现类的信息,上面用了 SingletonTargetSource 这个实现类,其实我们这里也不太需要关心这个,知道有这么回事就可以了。

我们继续往下看 createProxy(…) 方法:

// 注意看这个方法的几个参数
	// 第三个参数携带了所有的advisors
	// 第四个参数targetSource携带了真实实现的信息
	protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		// 给bean定义设置暴露属性
		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		// 创建代理工厂
		// 创建 ProxyFactory 实例
		ProxyFactory proxyFactory = new ProxyFactory();
		// 获取当前类中相关属性
		proxyFactory.copyFrom(this);

		// 决定对于给定的bean是否应该使用targetClass而不是它的接口代理,检查proxyTargetClass设置以及preserverTarget
		// 在 schema-based 的配置方式中,我们介绍过,如果希望使用 CGLIB 来代理接口,可以配置
		// proxy-target-class="true",这样不管有没有接口,都使用 CGLIB 来生成代理:
		// <aop:config proxy-target-class="true">......</aop:config>
		if (!proxyFactory.isProxyTargetClass()) {
			// 判断是 使用jdk动态代理 还是cglib代理
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				// 添加代理接口
				// 点进去稍微看一下代码就知道了,主要就两句:
				// 1. 有接口的,调用一次或多次:proxyFactory.addInterface(ifc);
				// 2. 没有接口的,调用:proxyFactory.setProxyTargetClass(true);
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		// 构建增强器
		// 这个方法会返回匹配了当前 bean 的 advisors 数组
		// 对于本文的例子,"userServiceImpl" 和 "OrderServiceImpl" 到这边的时候都会返回两个 advisor
		// 注意:如果 specificInterceptors 中有 advice 和 interceptor,它们也会被包装成 advisor,进去看下源码就清楚了
		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		// 设置要代理的类
		proxyFactory.setTargetSource(targetSource);
		// 定制代理
		customizeProxyFactory(proxyFactory);

		// 控制代理工厂被配置之后,是否还允许修改通知,默认值是false
		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}

		// 真正创建代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}

我们看到,这个方法主要是在内部创建了一个 ProxyFactory 的实例,然后 set 了一大堆内容,剩下的工作就都是这个 ProxyFactory 实例的了,通过这个实例来创建代理: getProxy(classLoader)

ProxyFactory 详解

根据上面的源码,我们走到了 ProxyFactory 这个类了,我们到这个类来一看究竟。

顺着上面的路子,我们首先到 ProxyFactory#getProxy(classLoader) 方法:

	public Object getProxy(@Nullable ClassLoader classLoader) {
		// createAopProxy() 用来创建我们的代理工厂
		return createAopProxy().getProxy(classLoader);
	}

该方法首先通过 createAopProxy() 创建一个 AopProxy 的实例:

创建 AopProxy 之前,我们需要一个 AopProxyFactory 实例,然后看 ProxyCreatorSupport 的构造方法:

	/**
	 * Create a new ProxyCreatorSupport instance.
	 */
	public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}

	/**
	 * Return the AopProxyFactory that this ProxyConfig uses.
	 */
	public AopProxyFactory getAopProxyFactory() {
		return this.aopProxyFactory;
	}

这样就将我们导到 DefaultAopProxyFactory 这个类了,我们看它的 createAopProxy(…) 方法:

到这里,我们知道 createAopProxy 方法有可能返回 JdkDynamicAopProxy 实例,也有可能返回 ObjenesisCglibAopProxy 实例,这里总结一下:

如果被代理的目标类实现了一个或多个自定义的接口,那么就会使用 JDK 动态代理,如果没有实现任何接口,会使用 CGLIB 实现代理,如果设置了 proxy-target-class="true",那么都会使用 CGLIB

JDK 动态代理基于接口,所以只有接口中的方法会被增强,而 CGLIB 基于类继承,需要注意就是如果方法使用了 final 修饰,或者是 private 方法,是不能被增强的

有了 AopProxy 实例以后,我们就回到这个方法了:

我们分别来看下两个 AopProxy 实现类的 getProxy(classLoader) 实现。

JdkDynamicAopProxy 类的源码比较简单,总共两百多行,

java.lang.reflect.Proxy.newProxyInstance(…) 方法需要三个参数:

第一个是 ClassLoader

第二个参数代表需要实现哪些接口

第三个参数最重要,是 InvocationHandler 实例,我们看到这里传了 this,因为 JdkDynamicAopProxy 本身实现了 InvocationHandler 接口

这里对比着JDK动态代理Demo,更容易理解JDK动态代理和CGLIB动态代理Demo

InvocationHandler 只有一个方法,当生成的代理类对外提供服务的时候,都会导到这个方法中:

下面来看看 JdkDynamicAopProxy 对其的实现:

JDK&CGLIB动态代理源码解析

结合着例子对比理解

@Override
	@Nullable
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object oldProxy = null;
		boolean setProxyContext = false;

		TargetSource targetSource = this.advised.targetSource;
		Object target = null;

		try {
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				// The target does not implement the equals(Object) method itself.
				// 代理的equals方法
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				// The target does not implement the hashCode() method itself.
				// 代理的hashCode方法
				return hashCode();
			}
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				// There is only getDecoratedClass() declared -> dispatch to proxy config.
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
					method.getDeclaringClass().isAssignableFrom(Advised.class)) {
				// Service invocations on ProxyConfig with the proxy config...
				return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
			}

			Object retVal;

			// 如果设置了exposeProxy,那么将proxy放到ThreadLocal中
			if (this.advised.exposeProxy) {
				// Make invocation available if necessary.
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}

			// Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			Class<?> targetClass = (target != null ? target.getClass() : null);

			// Get the interception chain for this method.
			// 创建一个chain,包含所有要执行的advice
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

			// Check whether we have any advice. If we don't, we can fallback on direct
			// reflective invocation of the target, and avoid creating a MethodInvocation.
			if (chain.isEmpty()) {
				// We can skip creating a MethodInvocation: just invoke the target directly
				// Note that the final invoker must be an InvokerInterceptor so we know it does
				// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
				// chain是空的,说明不需要被增强,这种情况很简单
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// We need to create a method invocation...
				// 执行方法,得到返回值
				MethodInvocation invocation =
						new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				// Proceed to the joinpoint through the interceptor chain.
				retVal = invocation.proceed();
			}

			// Massage return value if necessary.
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				// Special case: it returned "this" and the return type of the method
				// is type-compatible. Note that we can't help if the target sets
				// a reference to itself in another returned object.
				retVal = proxy;
			}
			else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
				throw new AopInvocationException(
						"Null return value from advice does not match primitive return type for: " + method);
			}
			return retVal;
		}
		finally {
			if (target != null && !targetSource.isStatic()) {
				// Must have come from TargetSource.
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				// Restore old proxy.
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}

 这里用到了责任链模式责任链模式在SpringAop中的使用责任链模式

 

// MethodBeforeAdviceInterceptor#invoke

 

 // AspectJAroundAdvice#invoke

 // AfterReturningAdviceInterceptor#invoke

 // AspectJAfterAdvice#invoke

// AspectJAfterThrowingAdvice#invoke

上面就三言两语说了一下,感兴趣的读者自己去深入探索下,不是很难。简单地说,就是在执行每个方法的时候,判断下该方法是否需要被一次或多次增强(执行一个或多个 advice)。

说完了 JDK 动态代理 JdkDynamicAopProxy#getProxy(classLoader),我们再来瞄一眼 CGLIB 的代理实现 ObjenesisCglibAopProxy#getProxy(classLoader)

ObjenesisCglibAopProxy 继承了 CglibAopProxy,而 CglibAopProxy 继承了 AopProxy。

通过 CGLIB 生成代理的代码量有点大,我们就不进行深入分析了,我们看下大体的骨架。它的 getProxy(classLoader) 方法在父类 CglibAopProxy 类中:

// CglibAopProxy#getProxy(classLoader)

@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
		}

		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			if (ClassUtils.isCglibProxyClass(rootClass)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// fixedInterceptorMap only populated at this point, after getCallbacks call above
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException | IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

CGLIB动态代理

 

3.2 基于注解的 Spring AOP 源码分析

上面我们走马观花地介绍了使用 DefaultAdvisorAutoProxyCreator 来实现 Spring AOP 的源码,这里,我们也同样走马观花地来看下 @AspectJ 的实现原理。

我们之前说过,开启 @AspectJ 的两种方式,一个是 <aop:aspectj-autoproxy/>,一个是 @EnableAspectJAutoProxy,它们的原理是一样的,都是通过注册一个 bean 来实现的。

解析 <aop:aspectj-autoproxy/> 需要用到 AopNamespaceHandler:

然后到类 AspectJAutoProxyBeanDefinitionParser:

 

进去 registerAspectJAnnotationAutoProxyCreatorIfNecessary(...) 方法:

再进去 AopConfigUtils#registerAspectJAnnotationAutoProxyCreatorIfNecessary(...):

最终我们看到,Spring 注册了一个 AnnotationAwareAspectJAutoProxyCreator 的 bean,beanName 为:"org.springframework.aop.config.internalAutoProxyCreator"。

我们看下 AnnotationAwareAspectJAutoProxyCreator 的继承结构: 

和前面介绍的 DefaultAdvisorAutoProxyCreator 一样,它也是一个 BeanPostProcessor,剩下的我们就不说了,它和它的父类 AspectJAwareAdvisorAutoProxyCreator 都不复杂。

  视频教程视频教程参考博客参考博客

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOPSpring框架的一个重要模块,它提供了一种面向切面编程的方式,可以让开发者将一些通用的、横切的关注点(如事务、安全、缓存等)从业务逻辑剥离出来,使得业务逻辑更加清晰简洁,代码复用更加方便。 Spring AOP的实现原理主要基于Java动态代理和CGLIB动态代理两种方式,其Java动态代理主要用于接口代理,而CGLIB动态代理则主要用于类代理。Spring AOP的核心概念是切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)和织入(Weaving)。 在Spring AOP,切面是一个横向的关注点,它跨越多个对象和方法,通常包含一些通用的功能,如日志记录、安全控制等。连接点则是程序可以被切面拦截的特定点,如方法调用、异常抛出等。通知是切面在连接点执行前后所执行的动作,包括前置通知(Before)、后置通知(After)、异常通知(AfterThrowing)、返回通知(AfterReturning)和环绕通知(Around)。切点则是用来匹配连接点的规则,它可以指定哪些连接点会被切面拦截。织入则是将切面应用到目标对象的过程,它可以在编译时、类加载时、运行时等不同的阶段进行。 Spring AOP源码解析涉及到很多细节,包括代理的生成、通知的执行、切点的匹配等,需要深入了解Spring框架的内部实现和Java的反射机制。对于初学者而言,可以先从Spring AOP的基本概念和用法入手,了解其实现原理的同时,也可以通过调试和查看源码来加深理解

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值