前言
前言的仪式感还是要有的。这次回来讲 Spring AOP
的主要原因之前写过一篇文章是关于 AOP
的一个概念性文章,然后作死地在文末讲“下一篇会进行源码”解析。但是后面却跑去写别的知识了。额...
其实造成我这么偏执写 Spring AOP
的原因是,毕竟是框架重点,里面的抽象代码以及思想不能丢;况且,咱们淳朴的程序猿,如果不能实打实地看到代码实现,怎么可能善罢甘休!
这篇文章主要还是希望能够完完整整地讲明白 AOP In Spring
是怎么实现的。所以整篇文章的顺序是:
AOP
的实现原理AOP
的具体源码解析- 手写一个简易版的
AOP
来加深理解
Let' Go!
实现原理
关于原理,上篇文章 Spring AOP
之详解与基础用法② 我有说过一点点。但是目前还是想补充一下。
Spring AOP
的实现方式有两种:AspectJ
与 Spring AOP
。它们的区别在于
Spring AOP | AspectJ |
---|---|
只在 Java 实现 | 使用 Java 编程语言的扩展实现 |
不需要单独的编译过程 | 使用 AspectJ 特定编译器,除非 LTW 被设置 |
只有运行时编织可用 | 运行时织入不可用。支持编译时,编译后和加载时织入 |
方法级别织入 | 更加强大 - 包括字段,方法,构造函数,静态初始化器 final 类 / 方法等 |
依赖 IOC 容器上管理实现 | 可以应用所有对象 |
仅支持方法执行切入点 | 所有方法切面 |
代理由目标对象创建,并且这些代理应用切面 | 在代码层面扩展,也就是在 runtime 前生成了代理类 |
比 AspectJ 慢得多 | 更高的性能 |
易学易用 | 比较复杂 |
源码解析
版本
此次源码解析是基于 Spring.5.1.2.release
版本上。
我们都知道,Spring
的核心要素是 IOC
。所以它预留了非常多的扩展抽象类以及接口。我们就拿一个常规的 Spring
对 Bean
管理的生命周期的流程图:
![e97fc51c0919f34ea9f424b808b278fc.png](https://img-blog.csdnimg.cn/img_convert/e97fc51c0919f34ea9f424b808b278fc.png)
我们可以发现只要实现上面的抽象类的方法,我们就可以通过通过方法在 Bean
的不同阶段的周期对 Bean
进行灵活配置和改变。
那么这个生命周期对于 AOP
起到什么帮助呢?其实不难想象,因为 AOP
的实现原理其实就是动态代理,而我们需要对 Bean
进行代理的话,最好的时间点就是在 Bean
合适的生命周期对其作出改变,这么一想是不是很合理?那我们在这里简单梳理一下,Spring 启动的时候是怎么触发到 AOP 相关的处理器的,步骤如下:
SpringApplication.run()
进行应用启动- run 方法中会调用方法
refreshContext()
进行上下文的准备以及数据刷新 refreshContext
会调用上下文Context
的refresh
方法refresh
里面做很多工作,但是我们只需要关注finishBeanFactoryInitialization()
方法。finishBeanFactoryInitialization
会调用preInstantiateSingletons
方法preInstantiateSingletons
方法会调用AbstractBeanFactory
的getBean
方法getBean
继续调用AbstractBeanFactory
的doGetBean
方法doGetbean
会继续调用AbstractBeanFactory
的getSingleton
->getObject
->doGetBean
,最后进入lambda
循环- 循环的过程中,调用了
AbstractAutowireCapableBeanFactory#createBean
方法。 createBean
这个时候会调用resolveBeforeInstantiation
方法。这个方法在此时此刻会给BeanPostProcessors
一个机会去生成代理类来替代原来的目标类,具体会调用的方法就是postProcessBeforeInstantiation
和postProcessAfterInitialization
。applyBeanPostProcessorsBeforeInstantiation
方法会通过获取当前上下文的所有BeanPostProcessors
进行循环,然后调用其postProcessBeforeInstantiation
和postProcessAfterInitialization
。
ok!虽然中间我们省略过程,但是我们目前来到了比较重要的一步。这个时候,真正去扫描生成 Bean 的时候到了。这个 BeanPostProcessors
中有一个叫 AnnotationAwareAspectJAutoProxyCreator
的类。它实现了 InstantiationAwareBeanPostProcessor
(属于 BeanPostProcessor
的子类,主要的功能是在实例化后属性被设置之前会进行自动装配)。同时 AnnotationAwareAspectJAutoProxyCreator
也实例化了 AbstractAutoProxyCreator
(属于 BeanPostProcessor
、可以拓展 AOP 代理的抽象类)。我们来看看它的 postProcessBeforeInstantiation
方法
需要注意一点,由于 Spring Boot 加载上下文的原因,所以出现加载的类与源码解析不相符,那么有可能是处于不同的上下文当中
public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) {
//获取该 bean 已经缓存好的名字
Object cacheKey = getCacheKey(beanClass, beanName);
//根据名判断是否已经加载过了
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
//查看是否是关于 AOP 相关的类 || 判断是否需要跳过加载
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
// 获取 TargetSource
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
上面的代码的步骤是
- 通过
isInfrastructureClass
判断是不是AOP
相关的类 - 通过
shouldSkip
来判断是否跳过这个Bean
的代理 - 如果上面都通过了,那么通过
getAdvicesAndAdvisorsForBean
方法获取对应的切面信息 - 根据切面信息生成代理类,然后将代理类返回去,便于替换原来的对象类
补充一下,上面的代码中的 TargetSource
其实就是一个持有对象的 Holder
。这样的好处在于,真正代理的不是实际对象而是 TargetSource
,这样我们可以通过替换 TargetSource
的持有的对象从而实现不用重新生成代理带来的消耗。
那么我们先看一下 shouldSkip
方法是怎么判断需不需要生成代理类的;然后看 getAdvicesAndAdvisorsForBean
是怎么解析找到对应的切面信息的;最后看 createProxy
在 Spring
中是怎么生成代理类的。
shouldSkip
protected boolean shouldSkip(Class> beanClass, String beanName) {
List candidateAdvisors = findCandidateAdvisors();for (Advisor advisor : candidateAdvisors) {if (advisor instanceof AspectJPointcutAdvisor) {if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {return true;
}
}
}return super.shouldSkip(beanClass, beanName);
}
上面代码主要是通过 findCandidateAdvisors
方法来获取所有的切面的名字,循环比较是否相同;如果相同则返回 true
。而 findCandidateAdvisors
方法主要是调 BeanFactoryAdvisorRetrievalHelper
的方法。需要注意当前类是全局单例,它的作用主要是在当前的 beanFactory
找所有合适的 Advisor
,但是不包括 FactoryBeans
。
public List findAdvisorBeans() {
//存储 advisors 的名字
String[] advisorNames = null;
synchronized (this) {
advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 在这里不会进行 FactoryBeans 的初始化,只要正常的,非加载的类
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
}
if (advisorNames.length == 0) {
return new LinkedList();
}
List advisors = new LinkedList();// 循环 adivors 的名字for (String name : advisorNames) {if (isEligibleBean(name)) {//如果查看是否排除创建或者是正在创建if (this.beanFactory.isCurrentlyInCreation(name)) {// log info
}else {// 添加try {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}catch (BeanCreationException ex) {// throw Exception
}
}
}
}return advisors;
}
上面主要是从 BeanFactory
中找到 Advisor
的类,然后进行判断。
findCandidateAdvisors() 方法返回的 Bean 可以用缓存来保存,这样有利于提高检索速度
getAdvicesAndAdvisorsForBean
getAdvicesAndAdvisorsForBean
方法在 AbstractAutoProxyCreator
是一个模板方法,主要是预留给子类去实现。我们来看看其子类 AbstractAdvisorAutoProxyCreator
的实现。
protected Object[] getAdvicesAndAdvisorsForBean(Class> beanClass, String beanName, TargetSource targetSource) {
List advisors = findEligibleAdvisors(beanClass, beanName);if (advisors.isEmpty()) {return DO_NOT_PROXY;
}return advisors.toArray();
}
findEligibleAdvisors
方法是调用了 AbstractAdvisorAutoProxyCreator
的。
protected List findEligibleAdvisors(Class> beanClass, String beanName) {
List candidateAdvisors = findCandidateAdvisors();
List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);if (!eligibleAdvisors.isEmpty()) { //对切面进行排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}return eligibleAdvisors;
}protected void extendAdvisors(List candidateAdvisors) {
AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
}
上面代码代码的作用是找到合适 Bean
的 Advisor
。主要是步骤是:
- 获取所有的
Advisors
- 通过
findAdvisorsThatCanApply
方法将Advisors
与beanName
开始匹配 - 通过
extendAdvisors
对匹配到的Advisor
进行一个小扩展(也就是添加一个头Advisor
) - 最后进行排序(便于顺序执行)
下面我将分标题进行讲解!
获取所有 Advisors
我们先看是如何获取所有的 Advisors
。这个方法是调用了 AnnotationAwareAspectAutoProxyCreator
的 findCandidateAdvisors
方法。
protected List findCandidateAdvisors() {
// 根据父类规则去获取
// 其实也就是上面的 advisorRetrievalHelper.findAdvisorBeans() 的调用
List advisors = super.findCandidateAdvisors();// 添加所有带 @Aspect 注解的切面类
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());return advisors;
}
通过 findAdvisorsThatCanApply 进行匹配匹配
然后我们看是如何匹配的。
protected List findAdvisorsThatCanApply(
List candidateAdvisors, Class> beanClass, String beanName) {
//通过 ThreadLocal 设置 beanName
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
AopUtils.findAdvisorsThatCanApply
进行匹配
public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {
// 省略一些判断的代码
List eligibleAdvisors = new LinkedList();for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}boolean hasIntroductions = !eligibleAdvisors.isEmpty();for (Advisor candidate : candidateAdvisors) {if (candidate instanceof IntroductionAdvisor) {//跳过,上面的代码已经加载了continue;
}if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}return eligibleAdvisors;
}
上面比较核心的代码是 canApply
方法,它主要是用来过滤不合适的 Advisor
。源码解析如下:
public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
//如果是 IntroductionAdvisor 则拿 PointCut 进行过滤
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// 如果没有任何匹配默认返回 true
return true;
}
}
通过 extendAdvisors 进行扩展
再看 extendAdvisors
到底是扩展了啥玩意。扩展代码主要是调用了 AspectJProxyUtils
的 makeAdvisorChainAspectJCapableIfNecessary
。这个方法的作用是给刚才过滤好的 Advisors
链上加上 ExposeBeanNameAdvisors
这个比较特殊的 Adviors
。而 ExposeBeanNameAdvisors
的作用是在调用那一步的时候,用来传递 MethodInvocation
的。我们简单看一下代码:
public static boolean makeAdvisorChainAspectJCapableIfNecessary(List advisors) {
// 如果为空则不需要执行
if (!advisors.isEmpty()) {
boolean foundAspectJAdvice = false;
for (Advisor advisor : advisors) {
// Be careful not to get the Advice without a guard, as
// this might eagerly instantiate a non-singleton AspectJ aspect
// 确认是否为切面
if (isAspectJAdvice(advisor)) {
foundAspectJAdvice = true;
}
}
//如果没有 ExposeInvocationInterceptor 则添加
if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
return true;
}
}
return false;
}
private static boolean isAspectJAdvice(Advisor advisor) {
return (advisor instanceof InstantiationModelAwarePointcutAdvisor ||
advisor.getAdvice() instanceof AbstractAspectJAdvice ||
(advisor instanceof PointcutAdvisor &&
((PointcutAdvisor) advisor).getPointcut() instanceof AspectJExpressionPointcut));
}
对 Advisor 进行排序
最后瞧瞧主要是通过哪些元素进行排序的。其实在 Spring Boot
里面,主要排序是通过 @Order
注解实现的。通过比较器 AnnotationAwareOrderComparator
实现。有兴趣可以看看它的 findOrder
方法。
createProxy
createProxy
方法主要是 AbstractAutoProxyCreator
方式实现的。
如果你对 AOP 还需要另外的扩展,可以继承 BeanNameAutoProxyCreator 或 AbstractAutoProxyCreator 来做进一步的增强
我想说一下 createProxy
主要做了些什么。步骤是
- 创建
ProxyFactory
- 判断决定对于给定的 bean 是否应该使用 targetClass 而不是他的接口代理
- 通过
buildAdvisors
方法创建Advisor
proxyFactory
设置对应的信息包括advisors
、目标对象、是否允许子类提前过滤需要被执行的 Advisor 以及调用模板方法customizeProxyFactory
来配置proxyFactory
- 最后调用
proxyFactory.getProxy
进行动态代理
protected Object createProxy(
Class> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
// 如果是 ConfigurableListableBeanFactory 可以将 TargetSource 进行暴露
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
//创建 ProxyFactory,将切面的配置信息进行复制
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//增强器的封装
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
//设置要代理的类
proxyFactory.addAdvisors(advisors);
//设置要代理的类
proxyFactory.setTargetSource(targetSource);
//为子类提供了定制的函数customizeProxyFactory
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
ok!上面大致上的代码已经讲完了加载这个流程。你说"啥?Spring AOP 的实现原理不是 JDK Dynamic Proxy
和 Cglib
吗?我怎么一点代码都没看到?我面试的时候可是背的妥妥的"。莫慌,现在我开始单独讲这一部分,因为它很重要也很长。
ProxyFactory.getProxy()
讲之前我先介绍一些类 ProxyFactory
/ ProxyCreatorSupport
/ AdvisedSupport ProxyConfig
/ Advised
类 | 说明 |
---|---|
ProxyFactory | 装饰工具类,对外提供 API |
ProxyCreatorSupport | 代理基础工厂,提供可配置的 AopProxyFactory 以及代理监听器 |
AdvisedSupport | AOP 代理配置管理器的基类,提供拦截链、接口缓存、是否提前过滤参数等等 |
ProxyConfig | 最高父类,保证全局参数一致 |
前面我们已经设置好了 ProxyFactory
的属性,现在开始调用 getProxy
来获取代理类。
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
上面的 createAopProxy
其实就是获取 ProxyCreatorSupport
中设置的 aopProxyFactory
。如果你看 createAopProxy
你会发现它会将自身作为参数传入,这就是 AdvisedSupport
的作用。
继续往下走的话,我们会调用 getProxy()
方法。
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() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
实际上返回的是 AopProxy
。这下重点来了,实际上 AopProxy 有两个子类:CglibAopProxy
和 JdkDynamicAopProxy
。这就是 JDK 代理以及 Cglib 代理。
我们来看看 JdkDynamicAopProxy
是怎么样的。源代码里面,JdkDynamicAopProxy
实现了 InvocationHandler
接口,这个也符合 Java
原生动态代理实现的标准。既然实现了 InvocationHandler
,那么当调用其目标方法时候,肯定也是调用它的 invoke
方法。让我们来看看
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// 如果調用的方法是 equals
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// 如果調用的方法是 hashCode
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//DecoratingProxy的方法和Advised接口的方法 都是是最终调用了config
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
//通过反射调用
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//查看是否“暴露代理”,为 true 则设置 proxy
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 尽量延迟获取对象的时间,因为这个目标对象可能来源于对象池或别的地方
target = targetSource.getTarget();
Class> targetClass = (target != null ? target.getClass() : null);
// 获取当前方法的调用链条
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);// 如果链条为空,直接调用if (chain.isEmpty()) {//减少创建 MethodInvocation 的机会,可以直接调用方法即可
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}else {// 创建 ReflectiveMethodInvocation,这个是为了结合调用链以及 法 进行原型链调用
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);// 通过方法的调用链处理 joinpoint
retVal = invocation.proceed();
}// 获取方法返回值的类型,处理返回的信息
Class> returnType = method.getReturnType();if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {// 如果返回值等于目标对象,只能直接返回 Proxy 对象
retVal = proxy;
}else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {//throw Exception
}return retVal;
}finally {if (target != null && !targetSource.isStatic()) {// 预留模板方法来释放对象(一般是一些拥有对象池的需要实现此方法)
targetSource.releaseTarget(target);
}if (setProxyContext) {// 重置为旧的代理对象
AopContext.setCurrentProxy(oldProxy);
}
}
}
exposeProxy
主要是解决嵌套方法代理的问题。举个例子
class A {
@Transactional(propagation = Propagation.REQUIRED)
public void a() {
new B().b();
}
}
class B {
@Transactional(propagation = Propagation.REQUIRED_NEW)
public void b() {
System.out.println("method b");
}
}
上面的例子中,b 方法是不会被切面拦截的。因为 b 方法属于 a 方法的内部调用。那么如 b 方法也实现 AOP
那么只能通过 expose-proxy
属性。
上面大致上是 JdkDynamicAopProxy
的代理方式。下面来看看属于 Cglib
的 ObjenesisCglibAopProxy
。Cglib
方式主要是在创建的时候已经准备好拦截方法进行生成代理类了。
public Object getProxy(ClassLoader classLoader) {
//throw code
try {
Class> rootClass = this.advised.getTargetClass();
Class> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
//循环父类接口,保存
Class>[] additionalInterfaces = rootClass.getInterfaces();
for (Class> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 校验
validateClassIfNecessary(proxySuperClass, classLoader);
// 配置 CGLIB 增强
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));
//根据 Class 获取拦截方法
Callback[] callbacks = getCallbacks(rootClass);
Class>[] types = new Class>[callbacks.length];
for (int x = 0; x types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap 在 getCallbacks 后调用
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
//生成代理并实例化
return createProxyClassAndInstance(enhancer, callbacks);
}
//throw Exception
}
获取 Proxy
的过程中,我们会去根据 TargetSource
获取对应的拦截方法。获取的方法是 getCallbacks
。
private Callback[] getCallbacks(Class> rootClass) throws Exception {
// 优化的参数
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// 选择 AOP 的拦截器
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// 是否暴露对象
Callback targetInterceptor;
if (exposeProxy) {
targetInterceptor = isStatic ?
new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
}
else {
targetInterceptor = isStatic ?
new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
}
// Choose a "direct to target" dispatcher (used for
// unadvised calls to static targets that cannot return this).
Callback targetDispatcher = isStatic ?
new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();
Callback[] mainCallbacks = new Callback[] {
aopInterceptor, // for normal advice
targetInterceptor, // invoke target without considering advice, if optimized
new SerializableNoOp(), // no override for methods mapped to this
targetDispatcher, this.advisedDispatcher,
new EqualsInterceptor(this.advised),
new HashCodeInterceptor(this.advised)
};
Callback[] callbacks;
// If the target is a static one and the advice chain is frozen,
// then we can make some optimizations by sending the AOP calls
// direct to the target using the fixed chain for that method.
if (isStatic && isFrozen) {
Method[] methods = rootClass.getMethods();
Callback[] fixedCallbacks = new Callback[methods.length];
this.fixedInterceptorMap = new HashMap(methods.length);// TODO: small memory optimization here (can skip creation for methods with no advice)for (int x = 0; x List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());this.fixedInterceptorMap.put(methods[x].toString(), x);
}// 复制 callbacks
callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);this.fixedInterceptorOffset = mainCallbacks.length;
}else {
callbacks = mainCallbacks;
}return callbacks;
}
一系列配置后,Spring 生成代理并实例化。
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class> proxyClass = enhancer.createClass();
Object proxyInstance = null;
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
//throw Exception
}
}
if (proxyInstance == null) {
// 如果 proxyInstance 为 null 就使用常规构造器进行初始化啊
try {
proxyInstance = (this.constructorArgs != null ?
proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
proxyClass.newInstance());
}
catch (Throwable ex) {
//throw Exception
}
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
最后,Cglib 与 JDK Proxy 也类似,会调用一个类似 invoke 的方法。在 Cglib 中主要有几个实现:
类名 | 说明 | |
---|---|
StaticUnadvisedInterceptor | 没有 advise 的静态方法拦截器调用 |
StaticUnadvisedExposedInterceptor | 没有 advise 的静态方法拦截器,但是需要暴露 proxy 的 |
DynamicUnadvisedInterceptor | 没有 advise 的动态方法拦截器调用 |
DynamicUnadvisedExposedInterceptor | 没有 advise 的动态方法拦截器,但是需要暴露 proxy 的 |
StaticDispatcher | 保证返回值不是 this |
EqualsInterceptor | equals 方法拦截器 |
HashCodeInterceptor | hashCode 方法拦截器 |
FixedChainStaticTargetInterceptor | 拦截器专门用于冻结的静态代理上的 advise |
DynamicAdvisedInterceptor | 有 advise 的动态方法拦截器 |
由于我们一般多数是 有 advise 的动态方法拦截器,所以看 DynamicAdvisedInterceptor#intercept
方法。
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Class> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 延迟获取对象的时间,因为这个目标对象可能来源于对象池
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
//获取调用链
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;// 如果没有 advice 直接调用方法if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}else {// 创建 CglibMethodInvocation,并且进行调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);return retVal;
}finally {//释放if (target != null) {
releaseTarget(target);
}//重置旧的 Proxyif (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
一个简单的 AOP 例子
通过上面的源码解析,我们知道了 Spring AOP
实际上就是 4 个步骤:
- 应用启动的时候,对
AOP
相关的配置类进行读取 - 然后通过
Spring
的扩展函数,处理需要被代理的目标对象 - 根据目标对象获取拦截链,然后进行参数赋值
- 最后进行代理实例化,返回替换原来的目标类
那我们也可以模仿 Spring
实现一个 AOP
的例子。
- 首先我们创建一个切面类
Aspects
,里面包含了各种通知(前置,后置等,对标Spring
的MethodBeforeAdvice
) - 然后我们编写实现了
Aspects
的SimpleAspect
,这个默认拦截都通过的。 - 然后我们编写一个
LogAspect
继承SimpleAspect
,这个LogAspect
可以重写父类自己感兴趣的方法 - 然后我们编写一个使用
JDK Dynamic Proxy
的代理生成类JdkDynamicAopProxy
(对标 Spring 的JdkDynamicAopProxy
) - 然后我们编写一个
TargetSource
作为代理数据源 - 上面的基础
AOP
代码写完了,我们开始写一个业务接口以及实现类UserService
和UserServceImpl
(记住是因为JDK Dynamic Proxy
需要接口) - 最后我们编写测试类来测试
第一步
public interface Aspects {
boolean before(Object target, Method method, Object[] args);
boolean after(Object target, Method method, Object[] args);
boolean afterException(Object target, Method method, Object[] args, Throwable e);
}
' 第二步
public class SimpleAspect implements Aspects{
@Override
public boolean before(Object target, Method method, Object[] args) {
return true;
}
@Override
public boolean after(Object target, Method method, Object[] args) {
return true;
}
@Override
public boolean afterException(Object target, Method method, Object[] args, Throwable e) {
return true;
}
}
第三步
public class LogAspect extends SimpleAspect{
@Override
public boolean before(Object target, Method method, Object[] args) {
System.out.println("log in the time " + System.currentTimeMillis());
return true;
}
}
第四步
public class JdkDynamicAopProxy implements InvocationHandler {
private TargetSource target;
private Aspects aspect;
//构造器
public JdkDynamicAopProxy(TargetSource target, Aspects aspect) {
this.target = target;
this.aspect = aspect;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final Object target = this.target.getTarget();
final Aspects aspects = this.aspect;
Object result = null;
if (aspects.before(target, method, args)) { //调用前置
result = method.invoke(target, args==null ? null : args);
}
if (aspects.after(target, method, args)) { //后置
return result;
}
return null;
}
}
第五步
public class TargetSource {
private Object target;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
}
第六步UserService
接口
public interface UserService {
public void show();
}
实现类
public class UserServiceImpl implements UserService{
public void show(){
System.out.println("User create");
}
}
最后一步
public class AopTest {
public static void main(String[] args) {
//创建一个切面
Aspects aspects = new LogAspect();
TargetSource targetSource = new TargetSource();
UserServiceImpl userService = new UserServiceImpl();
targetSource.setTarget(userService);
//创建代理类,调用方法
JdkDynamicAopProxy jdkProxyIntercept = new JdkDynamicAopProxy(targetSource, aspects);
UserService userService1 = (UserService)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class>[]{UserService.class}, jdkProxyIntercept);
userService1.show();
}
}
输出结果为
log in the time 1605582637979
User create
上面的例子是一个非常简单完整的例子,所以它没有考虑非常多的东西,例如
- 解决嵌套通知(通过责任链调用)
- 考虑拦截的方式如果是
equals
、hashCode
、静态方法等的处理 - 目前是硬编码方式判断,
AOP
如果是随时随地添加拦截器如何解决? - 以及更多...
建议如果想深究的同学可以去看一下 Spring AOP
实现的每一个细节。
结语
Spring AOP 源码解读终于还愿了。