Spring AOP核心源码 ProxyFactory

Spring AOP源码目录

Spring AOP源码01:Jdk动态代理底层源码
Spring AOP源码02:ProxyFactory
Spring AOP源码03:JdkDynamicAopProxy
Spring AOP源码04:MethodInvocation 拦截器调用
Spring AOP源码05:DefaultAdvisorAutoProxyCreator
Spring期末考压轴题:当Spring AOP遇上循环依赖
git注释源码地址:https://github.com/chaitou/spring-framework-master.git

前言

本篇将重点剖析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 adviceAfter 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继承关系

ProxyFactory
我们重点关心一下类,忽略接口

  • ProxyConfig:用于保存Proxy的相关基础配置,比如是否使用激进模式optimize、强制开起cglib代理proxyTargetClass、是否暴露代理exposeProxy等,在xml配置中十分常见,例如<aop:aspectj-autoproxy proxy-target-class="true"/>强制开启Cglib代理
  • AdvisedSupport:AOP的配置管理类,比起ProxyConfig,其还保存了targetSource、切面的集合advisors、接口集合interfaces
  • ProxyCreatorSupport:代理工厂的基础类,提供对可配置AopProxyFactory的便捷访问

源码分析

  1. 创建代理工厂,直接调用默认空构造器
  2. 设置代理目标对象,将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);
	}
  1. 设置接口数组,同样保存到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();
		}
	}
  1. 设置Advice,前面我们说过Advice只是增强,因此我们要封装成Advisor切面才能加到AdvisedSupportadvisors集合中。而需要注意的是因为没有配置任何的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);
}
  1. 创建代理,这才是本篇的重头戏
	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,因此继续跟踪DefaultAopProxyFactorycreateAopProxy方法

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(),结合Jdk动态代理底层源码的内容,可以预想到有2个需要特别关注的方法。getProxyinvoke方法

// 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);
	}
// 上述代码
Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

// 第一篇[Jdk动态代理底层源码]中学习的代码是一模一样的
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);

可以看出,其实每个知识点都是关联在一起的,ProxyFactory作为Spring AOP的核心,使用的也是我们学习过的Jdk动态代理来实现的。结合第一篇Jdk动态代理底层源码的内容,最最重要的便是getProxyinvoke方法,下一节我们将进行JdkDynamicAopProxygetProxyinvoke方法的源码剖析

发布了42 篇原创文章 · 获赞 43 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/chaitoudaren/article/details/105277908