上一篇文章spring源码系列-从@Autowired与@Resource异同中看依赖注入中,我们着重分析了依赖注入的实现。我们都是知道spring是一个ioc容器(即依赖注入),同时提供了aop功能。既然我们前面已经与ioc深入交流过,那么aop这位大佬我们也不能放过。究竟aop是用了什么手段,才坐上了spring扛把子的头把交椅呢?让我们一探究竟。本文可以分为如下几个模块
- aop
1.1 什么是aop
1.2 spring aop 用法
1.3 两个问题
1.3.1 切入实现类的自有方法
1.3.2 切入未实现接口的final类- 代理
2.1 静态代理
2.2 动态代理
2.2.1 JDK proxy
2.2.1.1 jdk proxy 用法
2.2.2 cglib proxy- spring aop 源码分析
3.1 动态aop 自定义标签
3.1.1 开启aop 自定义标签
3.1.2 aop 自定义标签标签的解析过程
3.2 注册AnnotationAwareAspectJAutoProxyCreator
3.2.1 处理proxy-target-class属性和expose-proxy属性
3.3 创建aop
3.3.1 获取增强方法或者增强器
3.3.1.1 寻找所有增强器和增强方法
3.3.1.2 寻找匹配增强器
3.3.2 根据增强方法创建代理
3.3.2.1 初始化ProxyFactory
3.3.2.2 选择代理类型
3.3.3 创建代理
3.3.2.3 获取代理
3.4 代理的方法拦截和方法回调
3.4.1 JdkDynamicAopProxy方法拦截
3.4.1.1 proceed 方法的调用
3.4.2 cglib 方法回调- 总结
1. 前言
用过spring的相信都用过spring的Aspectj和transaction,我们只需要编写相应的业务逻辑,然后开启配置就能实现切面和事物。不知道大家有没有想过,这些功能spring是如何做的,这就是下面我们要探讨的内容。当然本文不涉及事物的源码,事物源码刨析会放在下一篇文章中,单独分析。
1.1 什么是aop
究竟何为aop呢?
aop 即Aspect Oriented Programming,面向切面编程。
aop 将业务共通点进行切面提取,横切到代码中
-
aop 是对oop(Object Oriented Programming),面向对象编程的补充
、 oop 是一种纵向的层级关系,强调的是通过类之间的关系(组合,引用,继承等)来实现精准的逻辑单元
-
aop 是一种横向的关系,强调的是业务共通性的切面提取,然后横切到代码中。
上面的话可能有点晦涩,举个栗子。我们现在有很多service,现在有个需求要统计各个service的代码的执行时间。那么这个需求要如何实现呢? - 基于oop的实现方法:每个service里增加个stopwatch计时。service和统计紧耦合。
哪天统计的内容改变,我们就需要把每个service中的统计方法改一遍。service和 - 基于aop的实现方法:定义切面,开启aop功能,ok。无需硬编码到每个service,后续有修改只需要改动切面内容即可。service和统计松耦合。
1.2 spring aop 用法
下面演示一段spring aop的基本用法
- 定义切面
@Aspect
public class MyAspectJ {
//定义切点,即要切入的范围
@Pointcut(value = "execution(* com.moxieliunian.spring.service.*.*(..))")
public void something(){
}
@Before("something()")
public void before(){
System.out.println("before***********");
}
@After("something()")
public void after(){
System.out.println("after***************");
}
@Around("execution(* com.moxieliunian.spring.service.*.*(..)) && args(name)")
public Object around(ProceedingJoinPoint joinPoint,String name){
System.out.println("around***********start****name:"+name);
name = "moxieliunian";
Object result=null;
try {
result=joinPoint.proceed(new Object[]{name});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("around***********end");
return result;
}
}
- 定义代理类
public interface TestService {
void sayHello(String name);
}
public class TestServiceImpl implements TestService {
@Override
public void sayHello(String name) {
System.out.println("hello:"+name);
}
}
- 开启spring的aop 功能,同时导入需要的aspectjweaver包
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启spring aop 功能-->
<aop:aspectj-autoproxy/>
<!--注册切面,使其由spring管理-->
<bean id="ms" class="com.moxieliunian.spring.aop.MyAspectJ"/>
<!--配置bean-->
<bean id="tsi" class="com.moxieliunian.spring.service.impl.TestServiceImpl"/>
</beans>
这样就完成了aop的功能,我们来测试一下
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring-config.xml");
TestService testService=(TestService)applicationContext.getBean("tsi");
System.out.println(testService.sayHello("test"));
}
结果如下
around***********start****name:test
before***********
hello:moxieliunian
around***********end
after***************
可以看到我们定义的切面生效了,是不是很easy。spring 的aop可以很方便的让我们把业务共通的东西提取为切面,降低了系统的耦合度。带来这种便捷性的同时,我们需要更多的去思考这种黑盒后面的实现,以及我们可能会踩到的坑。
1.3 两个问题
下面我们看以下两个case
1.3.1 切入实现类的自有方法
public interface TestService {
String sayHello(String name);
}
public class TestServiceImpl implements TestService {
@Override
public String sayHello(String name) {
return "hello:"+name;
}
/**
* 这个方法未在接口里定义
* @param hi hi
* @return String
*/
public String sayHi(String hi){
return "hi:"+hi;
}
}
public class TestAop {
public static void main(String[] args) {
ApplicationContext applicationContext=
new ClassPathXmlApplicationContext("spring-config.xml");
TestServiceImpl testService=
(TestServiceImpl)applicationContext.getBean("tsi");
System.out.println(testService.sayHi("test"));
}
}
执行结果
Exception in thread "main" java.lang.ClassCastException:
com.sun.proxy.$Proxy8 cannot be cast to com.moxieliunian.spring.service.impl.TestServiceImpl
at com.moxieliunian.spring.TestAop.main(TestAop.java:16)
可以看到,无法切入接口实现类的自有方法
1.3.2 切入未实现接口的final类
public class TestFinalImpl {
public String sayHello(String name){
return "say Hello from:"+name;
}
}
public static void main(String[] args) {
ApplicationContext applicationContext=
new ClassPathXmlApplicationContext("spring-config.xml");
TestFinalImpl testFinal=
(TestFinalImpl)applicationContext.getBean("tfi");
System.out.println(testFinal.sayHello("test"));
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--开启spring aop 功能-->
<aop:aspectj-autoproxy/>
<!--注册切面,使其由spring管理-->
<bean id="ms" class="com.moxieliunian.spring.aop.MyAspectJ"/>
<!--配置bean-->
<bean id="tsi" class="com.moxieliunian.spring.service.impl.TestServiceImpl"/>
<!--配置bean-->
<bean id="tfi" class="com.moxieliunian.spring.service.TestFinalImpl"/>
</beans>
执行结果
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tfi' defined in class path resource [spring-config.xml]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class com.moxieliunian.spring.service.TestFinalImpl: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class com.moxieliunian.spring.service.TestFinalImpl
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
可以看到,无法切入未实现接口的final类
通过以上case,我们可以得到如下问题
为什么无法切入接口实现类的自有方法?
为什么无法切入未实现接口的final类?
为什么around方法执行中才执行before方法?为什么around方法执行完才执行after方法?
2. 代理
我们都知道spring的aop是基于代理实现的,那么要解释spring的aop,就有必要先回顾一下代理的相关内容。java中的代理按照代理类的生成时间可以分为静态代理与动态代理。动态代理又分为jdk动态代理(接口代理),cglib代理(子类代理)。
2.1 静态代理
所谓静态代理,即在编译期已经存在的代理类,一般手动指定代理类,下面是一个简单的例子。
//接口
public interface IOriginalService {
void serviceMethod();
}
//实现类
public class OriginalServiceImpl implements IOriginalService {
@Override
public void serviceMethod() {
System.out.println("OriginalServiceImpl do something....");
}
}
//代理类
public class OriginalServiceProxy implements IOriginalService {
private IOriginalService originalService;
public OriginalServiceProxy(IOriginalService originalService) {
this.originalService = originalService;
}
@Override
public void serviceMethod() {
System.out.println("OriginalServiceProxy do something begin ");
originalService.serviceMethod();
System.out.println("OriginalServiceProxy do something end ");
}
}
测试一下
public static void main(String[] args) {
IOriginalService iOriginalService=new OriginalServiceImpl();
IOriginalService originalServiceProxy=new OriginalServiceProxy(iOriginalService);
originalServiceProxy.serviceMethod();
}
运行结果如下
OriginalServiceProxy do something begin
OriginalServiceImpl do something....
OriginalServiceProxy do something end
可以看到静态代理在编译期已经指定了代理类是谁。如果将来被代理的类方法变动,则代理类也要手动修改代码
2.2 动态代理
所谓动态代理指的是在运行期间才生成代理类的代理技术。根据类结构的不同,又分为接口代理(JDK Proxy)和 类代理(cglib proxy)
。
注意:spring选择代理的时候,默认情况下,会根据类的结构来选择代理的实现方式。即如果类实现了接口,则使用jdk proxy。反之使用cglib proxy。
下面对这两种代理方式做基本演示:
2.2.1 jdk proxy
2.2.1.1 jdk proxy 用法
//接口
public interface IOriginalService {
void serviceMethod();
}
//实现类
public class OriginalServiceImpl implements IOriginalService {
@Override
public void serviceMethod() {
System.out.println("OriginalServiceImpl do something....");
}
}
test
public static void main(String[] args) {
IOriginalService iOriginalService=new OriginalServiceImpl();
InvocationHandler handler = (proxy,method,as)->{
System.out.println("jdk proxy start");
method.invoke(iOriginalService, as);
System.out.println("jdk proxy end");
return null;
};
IOriginalService originalService=(IOriginalService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IOriginalService.class},handler);
originalService.serviceMethod();
}
运行结果
jdk proxy start
OriginalServiceImpl do something....
jdk proxy end
可以看到关键在于InvocationHandler的定义,同时我们注意到Proxy.newProxyInstance第二个参数必须传入要代理类的接口名称,所以这也就是为什么其只能代理实现接口的类。
2.2.1.1 jdk proxy 实现原理
可能有的同学会好奇jdk动态代理的实现原理是什么,其实核心就在与如何将InvocationHandler作为参数传递给要生成的代理类,同时加载该代理类到内存中使用。
大致看下生成的proxyclasss
package com.sun.proxy;
import com.moxieliunian.spring.proxy.staticproxy.IOriginalService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements IOriginalService {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void serviceMethod() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.moxieliunian.spring.proxy.staticproxy.IOriginalService").getMethod("serviceMethod");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到$Proxy0 通过继承 Proxy 持有了Invocation的引用,同时通过实现 代理接口,重写了代理接口的实现
public final void serviceMethod() throws {
try {
//调用自定义InvocationHandler的invoke方法
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
通过调用自定义InvocationHandler的invoke方法,实现了代理
2.2.2 cglib proxy
public class OriginalServiceImpl implements IOriginalService {
@Override
public void serviceMethod() {
System.out.println("OriginalServiceImpl do something....");
}
}
test
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(OriginalServiceImpl.class);
//设置方法拦截
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib start");
methodProxy.invokeSuper(o,objects);
System.out.println("cglib end");
return null;
}
});
OriginalServiceImpl originalService=(OriginalServiceImpl) enhancer.create();
originalService.serviceMethod();
}
运行结果
cglib start
OriginalServiceImpl do something....
cglib end
看下cglib生成的代理class
public class OriginalServiceImpl$$EnhancerByCGLIB$$26f0d50b extends OriginalServiceImpl implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$serviceMethod$0$Method;
private static final MethodProxy CGLIB$serviceMethod$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("com.moxieliunian.spring.proxy.staticproxy.OriginalServiceImpl$$EnhancerByCGLIB$$26f0d50b");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$serviceMethod$0$Method = ReflectUtils.findMethods(new String[]{"serviceMethod", "()V"}, (var1 = Class.forName("com.moxieliunian.spring.proxy.staticproxy.OriginalServiceImpl")).getDeclaredMethods())[0];
CGLIB$serviceMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "serviceMethod", "CGLIB$serviceMethod$0");
}
final void CGLIB$serviceMethod$0() {
super.serviceMethod();
}
public final void serviceMethod() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$serviceMethod$0$Method, CGLIB$emptyArgs, CGLIB$serviceMethod$0$Proxy);
} else {
super.serviceMethod();
}
}
可以看到cglib是通过extends 目标类,即生成目标类的子类的方式来实现代理的。这也就解释了final类不能被cglib代理的原因
3. spring aop 源码分析
前面我们介绍了spring aop的用法,及代理的种类及实现原理。终于到了本文的核心部分,源码分析。其实总结的过程就是这样,往往要解释清楚一个点,需要N个点做铺垫。这个过程往往是比较劳心费神,同时也是提升最大的。3.1 动态aop 自定义标签
3.1.1 开启aop 自定义标签
上面我们演示使用spring aop的时候,我们首先在配置文件中开启了aop功能
<!--开启spring aop 功能-->
<aop:aspectj-autoproxy/>
那么解析aop的源码也得从这个配置入手。先说结果:这个配置文件的最终作用是注册AnnotationAwareAspectJAutoProxyCreator类
。那么就又出来两个问题:
- 问题1
<aop:aspectj-autoproxy/> 是如何解析到 AnnotationAwareAspectJAutoProxyCreator类?
- 问题2
AnnotationAwareAspectJAutoProxyCreator类又有什么作用,为什么要注册它?
3.1.2 aop 自定义标签标签的解析过程
解析<aop:aspectj-autoproxy/> 就是典型的自定义节点的解析过程,
先给出流程图,再对细节部分做出说明。
1.加载Bean的定义文件
关键在于 XmlBeanDefinitionReader.loadBeanDefinitions 方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//开始加载配置文件,转换bean定义
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
获取document 对象,准备解析document 转换为BeanDefinitions
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将流转换为document
Document doc = doLoadDocument(inputSource, resource);
//解析document
return registerBeanDefinitions(doc, resource);
}
}
解析document,并创建XmlReader上下文(该上下文包含默认的Namespace解析器)
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//创建XmlReaderContext
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
public XmlReaderContext createReaderContext(Resource resource) {
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, getNamespaceHandlerResolver());
}
public NamespaceHandlerResolver getNamespaceHandlerResolver() {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
}
return this.namespaceHandlerResolver;
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());
}
这里面有个很关键的地方,即DefaultNamespaceHandlerResolver,该类定义了 从"META-INF/spring.handlers"中加载对应的key,value到 private volatile Map<String, Object> handlerMappings。为以后解析自定义配置文件的Namespace提供查找依据
。
如 spring-aop-4.3.18.RELEASE.jar 中的spring.handlers 中定义如下
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
则以后遇到namespace为http://www.springframework.org/schema/aop的xml标签时,则会去取AopNamespaceHandler作为Namespace解析器。
解析document,将其转换为BeanDefinition
protected void doRegisterBeanDefinitions(Element root) {
preProcessXml(root);
//解析配置文件
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
}
开始配置文件解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
//aop 的标签解析会走这里
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
解析自定义配置文件
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
从private volatile Map<String, Object> handlerMappings 中根据key=http\://www.springframework.org/schema/aop,取到value=org.springframework.aop.config.AopNamespaceHandler
同时调用 AopNamespaceHandler.init 方法,为aop标签的每个属性绑定一个BeanDefinitionParser
-
调用上一步绑定的AspectJAutoProxyBeanDefinitionParser.parse 方法注册AnnotationAwareAspectJAutoProxyCreator
下面是AopNamespaceHandler的init 实现
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
到此为止,我们终于完成了<aop:aspectj-autoproxy/>配置的解析,可以看到spring在解析的过程中,有很多考虑的地方,篇幅限制,我们只是理出了其骨架。
3.2 注册AnnotationAwareAspectJAutoProxyCreator
调用AspectJAutoProxyBeanDefinitionParser.parse方法来注册AnnotationAwareAspectJAutoProxyCreator。
class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
extendBeanDefinition(element, parserContext);
return null;
}
这里有个特别关键的点AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary
public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
registerComponentIfNecessary(beanDefinition, parserContext);
}
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
-
注册AnnotationAwareAspectJAutoProxyCreator,这个关键类的作用我们后面再详细说
。 处理proxy-target-class属性和expose-proxy属性
3.2.1 处理proxy-target-class属性和expose-proxy属性
上面我们说到处理proxy-target-class属性和expose-proxy属性,那么这俩属性有什么作用,我们可以从下面的代码中得到答案
private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
if (sourceElement != null) {
boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
if (proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
if (exposeProxy) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
- proxy-target-class:spring aop在创建代理的时候,会选择jdk动态代理或者cglib代理的方式创建。选择的依据为:
如果当前类实现了至少一个接口,则会使用jdk动态代理,所有该目标类型实现的接口都将被代理(基于实现接口)。如果当前类没有实现接口,则使用cglib创建代理(基于继承当前类)
。如果要强制使用cglib代理(通过asm生成字节码,比jdk 代理效率高),则将proxy-target-class设置为true即可。但是要注意cglib代理不能代理final类(final类不能被继承),这也就是问题1和问题2 的答案
。 - expose-proxy:暴露当前代理。当使用JDK代理的时候,方法内部的自我调用将无法实施切面中的增强。比如下面代码
public interface AService {
void a();
void b();
}
public class AServiceImpl implements AService {
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void a() {
this.b();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void b() {
}
}
此时this.b()方法被调用的时候,其方上配置的开启新事物的增强将不会生效。为了解决这个问题,我们可以将expose-proxy 设置为true,暴露当前代理,并通过AopContext.currentProxy()方式调用
。
public class AServiceImpl implements AService {
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void a() {
((AService)AopContext.currentProxy()).b();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void b() {
}
}
值得注意的是,使用cglib不会有上面的问题,因为cglib是对所有方法做了增强,这也是cglib和jdk代理的不同点之一
,关于这个我们后续会详细解释。
3.3 创建aop
还记得我们上面说的AnnotationAwareAspectJAutoProxyCreator吗,前面做的核心工作就是为了注册AnnotationAwareAspectJAutoProxyCreator。那么这个AnnotationAwareAspectJAutoProxyCreator究竟是怎么实现了aop的创建。下面我们来一层一层剥开她的心。
从类图中我们看到了一个熟悉的接口BeanPostProcessor。我们都知道类初始化的的时候,会调用所有BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,看下AnnotationAwareAspectJAutoProxyCreator.postProcessBeforeInitialization和postProcessAfterInitialization方法,这也是我们分析aop的入口所在
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
关键在于wrapIfNecessary(bean, beanName, cacheKey),它封装了实现aop的核心逻辑。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
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;
}
流程图如下
其中蓝色部分都是AbstractAdvisorAutoProxyCreator的父类AbstractAutoProxyCreator所实现的功能,也是整个aop的核心逻辑。关键流程为
获取增强方法或者增强器-getAdvicesAndAdvisorsForBean
-
根据增强方法创建代理-createProxy
下面我们详细分析这两个步骤
3.3.1 获取增强方法或者增强器
获取增强方法或者增强器又分为两个步骤
寻找所有增强器和增强方法
寻找匹配增强器
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
//查找所有增强器和增强方法
List<Advisor> candidateAdvisors = findCandidateAdvisors();
//选择适用当前bean的并应用
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
3.3.1.1 寻找所有增强器和增强方法
试想如果我们要寻找所有增强器和增强方法,最简单直接的做法就是遍历所有的bean,找到type为Aspect的bean,并包装。其实spring也是这么做的:
获取所有的beanname(这个所有指的是所有在beanfactory中注册的bean)
遍历所有beanname,找到声明为Aspect 的类。
对步骤2 查找到的bean进行增强器的提取。
将提取的结果加入缓存。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new LinkedList<Advisor>();
aspectNames = new LinkedList<String>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new LinkedList<Advisor>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
下面分步骤解析上面的代码
- 获取所有的beanname
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
- 遍历所有beanname,找到声明为Aspect 的类
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
.........................
}
}
private boolean hasAspectAnnotation(Class<?> clazz) {
return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}
- 增强器的提取
增强器的提取又包含以下步骤:
查找当前Aspect类及其父类或者父接口中非@Pointcut标记的方法。注意这里包含从Object类继承的方法。
查找切点信息,即被@Before、@Around、@After、@AfterReturning、@AfterThrowing、@Pointcut 标记的方法。并将其包装成AspectJAnnotation。
根据AspectJAnnotation 初始化AspectJExpressionPointcut
根据AspectJExpressionPointcut 初始化 InstantiationModelAwarePointcutAdvisorImpl。
-
InstantiationModelAwarePointcutAdvisorImpl 初始化的时候,根据步骤2 中annotation的不同,生成不同的Advice,绑定在当前类中
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
关键点在于实例化InstantiationModelAwarePointcutAdvisorImpl 时的instantiateAdvice
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
}
switch (aspectJAnnotation.getAnnotationType()) {
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
从上面的代码中我们可以看到,初始化Advice的时候,会根据method上的注解类型,生成不同的Advice。包括AspectJMethodBeforeAdvice、AspectJAfterAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice、AspectJAroundAdvice。这些是代理实现的核心
至此我们已经完成了增强器的提取,下面就是把增强器应用到当前bean了
3.3.1.2 寻找匹配增强器
寻找匹配的增强器的过程,就是查找当前类的方法信息是否在@pointcout("execution()")生效范围内的过程。
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
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) {
// already processed
continue;
}
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
关键在于canApply方法
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
3.3.2 根据增强方法创建代理
创建代理又是一个复杂的工程,总体来说包含以下几步
初始化ProxyFactory。这个步骤会当前代理类的相关属性及之前匹配到的Advisors复制进去。
选择代理类型。
获取代理。
3.3.2.1 初始化ProxyFactory
初始化ProxyFactory其实就是一个赋值的过程,便于后面创建代理时使用
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
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(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
3.3.2.2 选择代理类型
之前我们多次提到,spring 会根据类的结构选择使用jdk 代理或者cglib 代理,即当前类实现至少一个接口则使用jdk代理,否则使用cglib代理。现在我们从代码上看这个逻辑
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);
}
}
- isOptimize 使用cglib优化策略
- isProxyTargetClass proxy-target-class为true
- hasNoUserSuppliedProxyInterfaces 不存在代理接口
- isInterface 继承自接口
- isProxyClass 是Proxy的子类
可以看到,当使用cglib优化策略或者proxy-target-class=true或者不存在代理接口,且当前类不是interface,且不是Proxy的子类的时候,才会使用cglib代理 。否则都使用jdk代理
3.3.2.3 获取代理
上面我们选择了代理类型,那么就可以根据代理类型(JdkDynamicAopProxy/ObjenesisCglibAopProxy)来创建代理了。创建代理的过程与我们在章节2中演示的两种代理的创建方式类似,都是api的调用过程,核心就在于拦截器的使用,下面我们先看下代理的获取过程
- JdkDynamicAopProxy
@Override
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//关键在这里,设置InvocationHandler
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
- 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));
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
//关键在于设置不同方法对应不同的callback索引
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
// 关键点,设置callback ,方法拦截的回掉
return createProxyClassAndInstance(enhancer, callbacks);
我们可以看到,上面两种代理的创建是对jdk代理和cglib代理的标准使用。与我们在章节2中演示的最大区别就在于设置方法拦截或方法回调,这也是整个aop实现的核心。
下面我们分别来介绍jdk动态代理的方法拦截,以及cglib动态代理的方法回调
3.4 代理的方法拦截和方法回调
上面我们说了这么多,其实已经完成了代理的创建,但是关于问题3(为什么around方法执行中才执行before方法?为什么around方法执行完才执行after方法?)即aop方法的执行顺序问题,我们一直没有谈到,篇幅所限,我们未放到3.3 章节中去讲,而是单独作为一个章节,值得注意的是:在aop的创建时已经完成了代理的方法拦截及方法回调的设置
,下面我们分别来介绍问题3的答案
3.4.1 JdkDynamicAopProxy方法拦截
在3.3.2.2 获取代理章节中,我们贴出了jdk动态代理的源码,其中有一行很关键部分
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
我们都知道,Proxy.newProxyInstance方法的第三个参数需要传一个InvocationHandler对象,而这里传的this,我们猜测当前类即JdkDynamicAopProxy一定实现了InvocationHandler接口,并重写了invoke方法
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
果真如此,那么也就是说核心逻辑都在invoke里面了,贴出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;
Class<?> targetClass = null;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
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;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// Get the interception chain for this method.
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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
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);
}
}
}
可以看到,代码很多,但其实核心就是两件事
获取拦截器链 List<Object> chain。
将拦截器链封装为ReflectiveMethodInvocation。
-
调用ReflectiveMethodInvocation.proceed 开始拦截器链的循环处理。
同时我们可以看到,上面的代码中有对我们之前所说的expose-proxy属性的处理,处理的方式就是将当前proxy设置到threadlocal中,用完再将之前oldproxy设置回去
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//省略很多代码
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
3.4.1.1 proceed 方法的调用
终于到了解开庐山真面目的时候了,proceed 方法最终实现了@Before方法执行前执行,@After在方法执行后执行。在说具体执行逻辑之前,有几个前提条件要预先了解
ReflectiveMethodInvocation 持有List<?> interceptorsAndDynamicMethodMatchers 的引用,这个list里装的是在创建代理前,提取到的Advisors。
interceptorsAndDynamicMethodMatchers 是按照固定顺序排序,排序的操作是在提取advisors的时候做的。按照索引从0-3分别为 ExposeInvocationInterceptor,AspectJAfterAdvice,InterceptorAndDynamicMethodMatcher(持有AspectJAroundAdvice引用),MethodBeforeAdviceInterceptor(持有AspectJMethodBeforeAdvice引用)。
-
ReflectiveMethodInvocation 定义了一个实例变量currentInterceptorIndex=-1,interceptorsAndDynamicMethodMatchers 最后执行的MethodInterceptor的索引。
了解以上几个前提条件。我们再来回顾下之前1.2 spring aop用法示范中的输出结果
around***********start****name:test
before***********
hello:moxieliunian
around***********end
after***************
可以得到如下结论
- 先执行around方法
- around执行中,且ProceedingJoinPoint.proceed()方法调用的时候执行before方法
- 继续执行完around方法
- 最后执行after方法
根据上面的结论,我们一步步来解释具体的执行流程,再次ReflectiveMethodInvocation.proceed 方法,先贴出源码
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
上面代码即是整个aop执行的最核心的部分实现,下面来分步骤解释上面的执行过程
首次进入ReflectiveMethodInvocation.proceed(),先取到interceptorOrInterceptionAdvice=list[0]=ExposeInvocationInterceptor,并将当前ReflectiveMethodInvocation做为参数调用传递,调用ExposeInvocationInterceptor.invoke(this)方法。此时currentInterceptorIndex = 0 。
++this.currentInterceptorIndex此时为0
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
ExposeInvocationInterceptor.invoke(this)方法又会再次调用ReflectiveMethodInvocation.proceed()
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
再次调用ReflectiveMethodInvocation.proceed()`
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
第二次进入ReflectiveMethodInvocation.proceed()方法,此时nterceptorOrInterceptionAdvice=list[1]=AspectJAfterAdvice,此时会调用AspectJAfterAdvice.invoke(this)方法。此时currentInterceptorIndex=1。
++currentInterceptorIndex 此时等于1
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
而AspectJAfterAdvice.invoke()的内部实现,又会调用ReflectiveMethodInvocation.proceed(),将其包再try/finally语句中,即所有的MethodInterector都执行完毕后,才会执行finally中的逻辑。而finally的逻辑,则是通过反射调用被@After标记的方法
,这样一来也就实现了after在最后执行的逻辑,即结论4
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
继续执行ReflectiveMethodInvocation.proceed(),第三次进入
return mi.proceed();
}
finally {
最终执行after
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
第三次进入ReflectiveMethodInvocation.proceed()方法,此时nterceptorOrInterceptionAdvice=list[2]=InterceptorAndDynamicMethodMatcher,此时会执行dm.interceptor.invoke(this)即AspectJAroundAdvice.invoke(this)方法。此时currentInterceptorIndex=2 。
++this.currentInterceptorIndex此时为2
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
而AspectJAroundAdvice.invoke()最终会通过反射调用,我们编写的切面类中被@Around标记的方法。而我们在编写@Around标记的方法的时候,总是会调用ProceedingJoinPoint.proceed(),这个方法最终还是会调用到步骤前面几部的ReflectiveMethodInvocation.proceed 方法,接着串联起来。
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
通过反射调用被@Aroud标记的切面方法
return invokeAdviceMethod(pjp, jpm, null, null);
}
public Object around(ProceedingJoinPoint joinPoint,String name){
第一个输出语句执行
System.out.println("around***********start****name:"+name);
name = "moxieliunian";
Object result=null;
try {
result=joinPoint.proceed(new Object[]{name});
System.out.println("1111");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("around***********end");
return result;
}
}
① 此时会执行第一个输出语句,输出
around***********start****name:test
接着执行joinPoint.proceed(new Object[]{name});
public Object proceed(Object[] arguments) throws Throwable {
Assert.notNull(arguments, "Argument array passed to proceed cannot be null");
if (arguments.length != this.methodInvocation.getArguments().length) {
throw new IllegalArgumentException("Expecting " +
this.methodInvocation.getArguments().length + " arguments to proceed, " +
"but was passed " + arguments.length + " arguments");
}
this.methodInvocation.setArguments(arguments);
第四次进入
return this.methodInvocation.invocableClone(arguments).proceed();
}
第四次进入ReflectiveMethodInvocation.proceed()方法,此时nterceptorOrInterceptionAdvice=list[3]=MethodBeforeAdviceInterceptor,此时会执行MethodBeforeAdviceInterceptor.invoke(this)方法。此时currentInterceptorIndex=3 。
public Object invoke(MethodInvocation mi) throws Throwable {
通过反射执行被before标记的方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
继续执行拦截器链,第五次进入
return mi.proceed();
}
而AspectJMethodBeforeAdvice.invoke最终会通过反射,执行切面中会@Before标记的方法
② 此时将执行第二个输出语句,输出before方法中的内容
before***********
第五次进入ReflectiveMethodInvocation.proceed()方法,此时 this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1。执行invokeJoinpoint()
currentInterceptorIndex等于3
this.interceptorsAndDynamicMethodMatchers.size()等于4
此时所有的方法拦截器都走完,则通过反射调用要被增强的方法,即TestServiceImpl.sayHello(String name)方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
protected Object invokeJoinpoint() throws Throwable {
return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
}
ReflectionUtils.makeAccessible(method);
return method.invoke(target, args);
通过反射调用到TestServiceImpl.sayHello(String name)方法
③ 此时将会执行sayHello方法,执行第三个输出语句,输出
hello:moxieliunian
到此为止,拦截器链循环结束,但是方法还未执行完。刚才我们是在调用MyAspectJ.around()里的joinPoint.proceed(new Object[]{name}) 语句进入的拦截器链,进行拦截器最后一次循环。那么接下来会继续顺序执行 未执行完代码
System.out.println("around***********start****name:"+name);
name = "moxieliunian";
Object result=null;
try {
这部分代码已经执行完毕
result=joinPoint.proceed(new Object[]{name});
} catch (Throwable throwable) {
throwable.printStackTrace();
}
未执行,继续往下执行
System.out.println("around***********end");
return result;
④ 此时顺序执行完around剩余的代码,输出第四条语句
around***********end
当所有ReflectiveMethodInvocation.proceed() 递归调用完毕后,执行 最初 AspectJAfterAdvice.invoke方法中的finally 逻辑,即通过反射调用@After标记的方法
public Object invoke(MethodInvocation mi) throws Throwable {
try {
递归调用
return mi.proceed();
}
finally {
通过反射最终执行被@After标记的方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
⑤ 此时输出第五条输出语句
after***************
可以看到整个执行过程比较复杂,而且具体的执行逻辑并不在ReflectiveMethodInvocation类中,而是委托给具体的MethodInterceptor 去执行
3.4.2 cglib 方法回调
上面我们详细的刨析了jdk动态代理的方法拦截,与之对应的是cglib的方法回调,这个也是cglib代理的关键所在,先上代码
private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
// Parameters used for optimization choices...
boolean exposeProxy = this.advised.isExposeProxy();
boolean isFrozen = this.advised.isFrozen();
boolean isStatic = this.advised.getTargetSource().isStatic();
// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
// Choose a "straight to target" interceptor. (used for calls that are
// unadvised but can return this). May be required to expose the proxy.
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<String, Integer>(methods.length);
// TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
List<Object> 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);
}
// Now copy both the callbacks from mainCallbacks
// and fixedCallbacks into the callbacks array.
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;
}
关键点在于Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised)。即将advisors封装进DynamicAdvisedInterceptor中。
我们都知道cglib拦截器必须实现自MethodInterceptor,可以推测DynamicAdvisedInterceptor必然实现了MethodInterceptor。查看类定义
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable
那么就必须实现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) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we
// "own" the target, in case it comes from a pool...
target = getTarget();
if (target != null) {
targetClass = target.getClass();
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// 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.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
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);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
是不是跟我们上面分析的JdkDynamicAopProxy类似,都是获取拦截器链,封装拦截器链,构造并串联调用。
区别就在于JdkDynamicAopProxy是直接构造ReflectiveMethodInvocation,而CglibAopProxy则是构造CglibMethodInvocation,CglibMethodInvocation继承自ReflectiveMethodInvocation,但未覆盖其proceed方法。
-
所以最终会走到跟JdkDynamicAopProxy一样的逻辑,即递归调用ReflectiveMethodInvocation.proceed()。
这里我们就不在重复去分析了。
4. 总结
这篇文章中,我们由两个aop失效及一个aop使用正常的例子,简单分析了spring aop的实现原理。其实用一句话概括就是:提取Advisors,以advisors创建代理。但是为了简单说清楚这个问题,我们先是演示了aop的使用方法及失效案例,再演示了java中的三种代理类型,接着才着重分析了aop的实现原理。可以看到,有的时候要说清楚一个问题,往往要以N个问题做铺垫。还是相对来说比较繁杂的,但是总结的过程往往也是升华的过程。
希望看到这篇文章的朋友都有些许收获,也希望自己的目标早日实现。因能力有限,文章难免会有错漏的地方,欢迎指正和探讨。我们下篇文章spring源码系列-事物的失效知多少见。。。。
参考文章
Spring 源码深度解析-郝佳