Spring AOP core source ProxyFactory

Spring AOP source directory

Spring AOP Source 01: Jdk dynamic proxy for the underlying source
Spring AOP Source 02: the ProxyFactory
Spring AOP Source 03: JdkDynamicAopProxy
Spring AOP Source 04: MethodInvocation call interceptor
Spring AOP Source 05: The DefaultAdvisorAutoProxyCreator
the Spring finale final exam question: When Spring AOP met circular dependencies
Notes git source address: https: //github.com/chaitou/spring-framework-master.git

Foreword

This article deals focus on analysis of ProxyFactorythe class source code, many people do not understand why you want to explain most of the energy is spent ProxyFactoryon, after all, no one would use such a low-level Spring AOP implementations?

ProxyFactory need to manually set the proxy to achieve Traget(the target object), Interface(interface), Advice(enhanced), then call getProxygenerates a proxy object. The use of annotations in the form of Spring AOP did not imagine the complex, but is looking for all @Aspectannotated classes and all @Beforeand other enhancements, and then through the @Pointcutmatching conditions on the match, and finally get to all matching the Advice(enhanced) were generated proxy. Therefore, the comment form AOP not esoteric, just to help us automatically 寻找匹配增强and create Bean in Spring Ioc the process of looking for 合适的时机, call getProxy generating agent, nothing more. So, if we manually hard-coded ( ProxyFactory) and thoroughly, and basically also mastered Spring AOP, as to the form of notes, we just have to explore about Advicehow to obtain and match it

Notes cutaway Xml configuration, the core Spring AOP is to ProxyFactoryseize the main line, in order to better grasp the context of the source code, and will not be disturbed by the details of the corner

ProxyFactory

The sample code

We will write an UserServiceinterface that defines findUsermethods while before with after using the Advicemethod of enhanced (enhanced), last used ProxyFactorywere generated proxy.

Here it is necessary to broadly introduce Advice (enhanced) and Advisor (section), two words a bit like a long, but they are the aggregation relationship.

  • Enhanced ( Advice): a common Before advice, After returning advicethat is to expand operations at the connection point
  • Cut Point ( Pointcut): i.e. connection point, for determining whether the current method or class enhanced
  • Section ( Advisor): can be seen in 增强and 切点binding. Suppose a method needs to be enhanced, then cut through all the calls Pointcutto judge whether the current section applies, if applicable, is called the current Adviceenhanced

interface:

public interface UserService {
	public void findUser();
}

Implementing Classes:

public class UserServiceImpl implements UserService {
	@Override
	public void findUser() {
		System.out.println("findUser...");
	}
}

2 enhancements:

// 前置增强
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...");
	}
}

test:

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();
    }
}

operation result:

before log...
findUser...
after log...

Process finished with exit code 0

ProxyFactory inheritance

ProxyFactory
We care about the focus of the class, ignoring Interface

  • ProxyConfig: Proxy configuration for saving related infrastructure, such as whether to use aggressive mode, optimize, forcibly opened cglib agent proxyTargetClass, if exposed to the agent exposeProxy etc., is very common in the xml configuration, such as <aop:aspectj-autoproxy proxy-target-class="true"/>forced on Cglib agent
  • AdvisedSupport: AOP configuration management class, compared ProxyConfig, which also holds targetSourcea collection of cut advisors, set of interfaces interfaces, etc.
  • ProxyCreatorSupport: Agent base class facilities, which provide for a configurable AopProxyFactoryand easy access

Source code analysis

  1. Create a proxy factory, calling the default constructor direct air
  2. Set up a proxy target object, the targetobject is encapsulated into TargetSourcean object, why should we bother? In fact, TargetSourcethe purpose is to make use object pooling and more cases, that each agent will get the object from the pool. And here we use only SingletonTargetSource, on TargetSourceleave back to explain. Just mentioned these attributes are stored in AdvisedSupportthe
	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. Setting an array of interfaces, also stored to AdvisedSupportthe properties
	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. Set Advice, as we said Advicejust increased, so we have to package into a Advisorsection added to AdvisedSupportthe advisorscollection. And because there is no need to pay attention to the configuration of any Pointcut, so we will use DefaultPointcutAdvisorcreated
	@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));
		}
	}

And DefaultPointcutAdvisormeans that no matter what methods are matched, so you can see Pointcut using Pointcut.TRUEwhatever method matches are true

new DefaultPointcutAdvisor(advice)
// Pointcut.TRUE
// 也就是说该Advisor的匹配均为true,匹配任何的方法,不做任何限制!
public DefaultPointcutAdvisor(Advice advice) {
	this(Pointcut.TRUE, advice);
}
  1. Create an agent, this is the highlight of Benpian
	public Object getProxy() {
		return createAopProxy().getProxy();
	}

Code createAopProxy().getProxy()one, calling getProxy()before, we have to figure out what the object is called getProxy(), in other words, createAopProxy()in the end what the object is created

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();
}

Tracking found createAopProxy()returns attribute aopProxyFactory, the attribute aopProxyFactoryis on ProxyCreatorSupportfor constructing an instantiated class is real DefaultAopProxyFactory, and therefore continue to follow DefaultAopProxyFactorythe createAopProxymethod of

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);
		}
	}
  ...
}

It can be seen as config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)is true only use Cglib agent, and when there is a proxy object implements the interface, and not forced on the default proxy is used when cglib JDK proxy, that is JdkDynamicAopProxyclass.

In other words, the final call is actually a new JdkDynamicAopProxy(config).getProxy()combination Jdk dynamic proxy for the underlying source content, it is expected to have two methods require special attention. getProxyAnd invokemethods

// 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);

As can be seen, in fact, each knowledge point are associated together, ProxyFactoryas the core of Spring AOP, we also studied the use of Jdk动态代理to achieve. Combining the first chapter Jdk dynamic proxy for the underlying source content, it is the most important getProxyand invokemethod, the next section we will be JdkDynamicAopProxyin getProxyand invokesource code analysis methods

Published 42 original articles · won praise 43 · views 40000 +

Guess you like

Origin blog.csdn.net/chaitoudaren/article/details/105277908