概要
本篇将重点剖析ProxyFactory类的源码,很多人不理解为什么要将大部分精力花在讲解ProxyFactory上,毕竟没有人会使用这么底层的Spring AOP实现方式?
ProxyFactory实现代理需要手动设置Traget(目标对象)、Interface(代理接口)、Advice(增强),然后调用getProxy生成代理对象。而使用注解形式的Spring AOP并没有想象中的复杂,不过是寻找所有@Aspect注解的类以及所有@Before等增强,再通过@Pointcut上的匹配条件进行匹配,最后获取到所有匹配的Advice(增强)进行生成代理。因此,注解形式的AOP并不深奥,只不过是帮我们自动寻找匹配增强,并在Spring Ioc创建Bean的过程中寻找合适的时机,调用getProxy生成代理,仅此而已。因此,如果我们将手动硬编码的方式(ProxyFactory)学透了,基本上也就掌握了Spring AOP了,至于注解的形式,我们只需要再探究一下Advice如何获取以及匹配就可以了
剖去注解与Xml的配置,Spring AOP的核心就是ProxyFactory,抓住主线,才能更好的把握源码脉络,不至于被边角的细节所干扰
ProxyFactory
代码示例
我们将会写一个UserService接口,定义findUser方法,同时在before跟after使用Advice(增强)对方法进行增强,最后使用ProxyFactory进行代理的生成。
在这里有必要先大致介绍一下Advice(增强)和Advisor(切面),2个单词长的有点像,但是他们是聚合的关系。
- 增强(Advice):常见的有Before advice、After returning advice,也就是在连接点进行扩展操作
- 切点(Pointcut):也就是连接点,用于判断当前方法或者类是否需要增强
- 切面(Advisor):可以看做的增强和切点的结合。假设一个方法需要进行增强,则遍历所有切面,调用Pointcut进行判断当前切面是否适用,如果适用,则调用当前Advice进行增强
接口:
public interface UserService {
public void findUser();
}
实现类:
public class UserServiceImpl implements UserService {
@Override
public void findUser() {
System.out.println("findUser...");
}
}
2个增强:
// 前置增强
public class LogBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("before log...");
}
}
// 后置增强
public class LogAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("after log...");
}
}
测试:
public class UserServiceImplImplTest {
@Test
public void findUser() {
// 1. 创建代理工厂
ProxyFactory factory = new ProxyFactory();
// 2. 设置代理目标对象
factory.setTarget(new UserServiceImpl());
// 3. 设置接口
factory.setInterfaces(new Class[]{UserService.class});
// 4. 设置增强
factory.addAdvice(new LogBeforeAdvice());
factory.addAdvice(new LogAfterAdvice());
// 5. 获取代理对象
UserService userService = (UserService) factory.getProxy();
userService.findUser();
}
}
运行结果:
before log...
findUser...
after log...
Process finished with exit code 0
ProxyFactory的结构图如下:
我们重点关心一下类,忽略接口
ProxyConfig:用于保存Proxy的相关基础配置,比如是否使用激进模式optimize、强制开起cglib代理proxyTargetClass、是否暴露代理exposeProxy等,在xml配置中十分常见,例如<aop:aspectj-autoproxy proxy-target-class="true"/>强制开启Cglib代理
AdvisedSupport:AOP的配置管理类,比起ProxyConfig,其还保存了targetSource、切面的集合advisors、接口集合interfaces等
ProxyCreatorSupport:代理工厂的基础类,提供对可配置AopProxyFactory的便捷访问
源码分析
创建代理工厂,直接调用默认空构造器
设置代理目标对象,将target对象封装成TargetSource对象,为什么要多此一举呢?其实TargetSource的目的是为了做对象池和多例用的,也就是说每次代理都从池中获取对象。而这里我们只使用SingletonTargetSource,关于TargetSource留到后面讲解。刚刚提到这些属性都是保存在AdvisedSupport中的
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
@Override
public void setTargetSource(@Nullable TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
设置接口数组,同样保存到AdvisedSupport的属性中
public void setInterfaces(Class<?>... interfaces) {
Assert.notNull(interfaces, "Interfaces must not be null");
// 先清空再添加
this.interfaces.clear();
for (Class<?> ifc : interfaces) {
addInterface(ifc);
}
}
public void addInterface(Class<?> intf) {
Assert.notNull(intf, "Interface must not be null");
// 校验如果不是接口则抛出异常
if (!intf.isInterface()) {
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
}
if (!this.interfaces.contains(intf)) {
this.interfaces.add(intf);
adviceChanged();
}
}
设置Advice,前面我们说过Advice只是增强,因此我们要封装成Advisor切面才能加到AdvisedSupport的advisors集合中。而需要注意的是因为没有配置任何的Pointcut,因此将使用DefaultPointcutAdvisor进行创建
@Override
public void addAdvice(Advice advice) throws AopConfigException {
int pos = this.advisors.size();
addAdvice(pos, advice);
}
@Override
public void addAdvice(int pos, Advice advice) throws AopConfigException {
Assert.notNull(advice, "Advice must not be null");
if (advice instanceof IntroductionInfo) {
// We don't need an IntroductionAdvisor for this kind of introduction:
// It's fully self-describing.
// 单独处理引介增强
addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
}
else if (advice instanceof DynamicIntroductionAdvice) {
// We need an IntroductionAdvisor for this kind of introduction.
// DynamicIntroductionAdvice只能作为IntroductionAdvisor的一部分
throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
}
else {
// 普通增强
addAdvisor(pos, new DefaultPointcutAdvisor(advice));
}
}
而DefaultPointcutAdvisor的意思就是无论什么方法都匹配,因此可以看到Pointcut使用的是Pointcut.TRUE,无论匹配什么方法都是true
new DefaultPointcutAdvisor(advice)
// Pointcut.TRUE
// 也就是说该Advisor的匹配均为true,匹配任何的方法,不做任何限制!
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
创建代理,这才是本篇的重头戏
public Object getProxy() {
return createAopProxy().getProxy();
}
代码就createAopProxy().getProxy()一句,在调用getProxy()之前,我们得弄清楚是什么对象调用的getProxy(),换句话说,也就是createAopProxy()到底创建了什么对象
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
----------------------------------------------------------------
public AopProxyFactory getAopProxyFactory() {
// 返回的是类中的成员变量aopProxyFactory
return this.aopProxyFactory;
}
----------------------------------------------------------------
// 成员变量的实例化则是在默认构造器中
private AopProxyFactory aopProxyFactory;
// 构造器,调用了DefaultAopProxyFactory进行实例化,因此aopProxyFactory真正的类型是DefaultAopProxyFactory
public ProxyCreatorSupport() {
this.aopProxyFactory = new DefaultAopProxyFactory();
}
跟踪发现createAopProxy()返回的是属性aopProxyFactory,而属性aopProxyFactory又是在ProxyCreatorSupport构造器时进行实例化的,真正的类是DefaultAopProxyFactory,因此继续跟踪DefaultAopProxyFactory的createAopProxy方法
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// isOptimize开启激进模式 || proxyTargetClass=true(强制开启cglib代理) || 接口集合为空
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);
}
// 没有接口,只能选择cglib代理
return new ObjenesisCglibAopProxy(config);
}
else {
// 使用JDK代理
return new JdkDynamicAopProxy(config);
}
}
...
}
可以看到,当config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)为真时才会使用Cglib代理,而当代理对象有实现接口,并且没有强制开启cglib代理时默认使用的是JDK代理,也就是JdkDynamicAopProxy类。
也就是说,最后将调用的其实是new JdkDynamicAopProxy(config).getProxy(),可以预想到有2个需要特别关注的方法。getProxy和invoke方法
// JdkDynamicAopProxy.java
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// 获取代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
// 判断接口是否又hashCode和equals方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// 使用JDK代理(classLoader, 接口, 当前JdkDynamicAopProxy对象:用于回调invoke和target对象方法)
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
JdkDynamicAopProxy
我们看可以很清楚的看到,代理对象的生成直接使用了jdk动态代理:Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);而代理逻辑是通过实现了InvocationHandler接口的invoke方法实现的。而这里用到的实现了InvocationHandler接口的类就是JdkDynamicAopProxy自身。JdkDynamicAopProxy自身实现了InvocationHandler接口,完成了Spring AOP拦截器链拦截等一系列逻辑,我们看一下JdkDynamicAopProxy的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 {
//没有重写equals方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
//没有重写hashCode方法
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
//代理的类是Advised,这里直接执行,不做任何代理
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.
//拦截器链是空的,直接执行需要代理的方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
else {
// We need to create a method invocation...
//这里是调用拦截器链的地方,先创建一个MethodInvocation对象,然后调用该对象的proceed方法完成拦截器链调用
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.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);
}
}
}
拦截器链的调用
从上面的代码和注释中我们可以看到spring实现aop的主要流程,具体如何调用拦截器链,我们来看一下MethodInvocation的proceed方法
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// currentInterceptorIndex是从-1开始的,所以拦截器链调用结束的时候index是 this.interceptorsAndDynamicMethodMatchers.size() - 1
// 调用链结束后执行目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获得当前处理到的拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 这里判断是否是InterceptorAndDynamicMethodMatcher,如果是,这要判断是否匹配methodMatcher,不匹配则此拦截器不生效
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);
}
}
proceed()方法是一个递归方法,我们可以根据代码的注释知道大体逻辑,InterceptorAndDynamicMethodMatcher的代码如下,我们可以看到,InterceptorAndDynamicMethodMatcher 持有一个MethodInterceptor 对象和一个MethodMatcher 对象,在拦截器链调用过程中,如果拦截器是InterceptorAndDynamicMethodMatcher ,则会先根据MethodMatcher 判断是否匹配,匹配MethodInterceptor 才会生效。
class InterceptorAndDynamicMethodMatcher {
final MethodInterceptor interceptor;
final MethodMatcher methodMatcher;
public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
this.interceptor = interceptor;
this.methodMatcher = methodMatcher;
}
}
至于MethodInterceptor 是什么,MethodInterceptor 的逻辑是怎么样的,我们可以看一下MethodInterceptor 的一个子类AfterReturningAdviceInterceptor的实现:
public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {
private final AfterReturningAdvice advice;
/**
* Create a new AfterReturningAdviceInterceptor for the given advice.
* @param advice the AfterReturningAdvice to wrap
*/
public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
}
AfterReturningAdviceInterceptor的作用是在被代理的方法返回结果之后添加我们需要的处理逻辑,其实现方式我们可以看到,先调用MethodInvocation 的proceed,也就是先继续处理拦截器链,等调用完成后执行我们需要的逻辑:this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());