Spring Source Reading-AOP Implementation Core Class AbstractAutoProxyCreator

Keywords: JDK Spring

The first two articles are mainly about registering the subclasses of AbstractAutoProxyCreator from two entries. Here is the implementation logic:

First, look at the class diagram to find the location of AbstractAutoProxyCreator in spring:

Indexed AbstractAutoProxyCreator is essentially BeanPostProcessor, which implements the logic of proxy creation in AbstractAutoProxyCreator. Its subclass AbstractAdvisorAutoProxyCreator mainly obtains Advisors, the core method getAdvicesAndAdvisorsForBean. The red implementation class in the diagram is the registration of the previous two sections, and they have some implementation logic based on their own scenarios.

2. debug code, tracking process:

In createBean, doCreateBean is the place where the object is actually created. Before creating the object, the postProcessBeforeInstantiation method is called to give the extension point an opportunity to create a proxy. If the proxy object return is not empty, createBean returns directly, and subsequent target objects are no longer instantiated.

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
	Object cacheKey = getCacheKey(beanClass, beanName);

	if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
		if (this.advisedBeans.containsKey(cacheKey)) {
			return null;
		}
		// 1. Some objects cannot be proxied, base class: Advices, Advisors and AopInfrastructure Beans; with aop annotation class: @Aspect
		// 2. Subclasses can duplicate this class, shouldSkip returns true if some situations do not require proxying
		if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return null;
		}
	}

	// Create proxy here if we have a custom TargetSource.
	// Suppresses unnecessary default instantiation of the target bean:
	// The TargetSource will handle target instances in a custom fashion.
	if (beanName != null) {
		//Get the targetSource and, if it exists, create the proxy directly before the object is initialized, avoiding unnecessary instantiation of the target object
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		
		//If you have a custom targetSource, create the proxy object here
		//The advantage of this is that the proxied object can change dynamically, not that the value is for a target object (objects in the object pool can be proxied, and new objects can be created each time the proxy is created)
		if (targetSource != null) {
			this.targetSourcedBeans.add(beanName);
			//Get Advisors, which is implemented by subclasses
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			//Return Proxy Object
			return proxy;
		}
	}

	return null;
}

If a custom TargetSource is obtained in postProcessBeforeInstantiation, the proxy object is created directly. Before creating the proxy object, call getAdvicesAndAdvisorsForBean to get the interceptor object Advisors, and then call createProxy to create the proxy object.

If there is no custom TargetSource, go to the postProcessAfterInitialization method to create the proxy. The logic is the same as above, except that a default TargetSource (SingletonTargetSource) is created, as follows:

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
	if (bean != null) {
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
		if (!this.earlyProxyReferences.contains(cacheKey)) {
			//Agent if not
			return wrapIfNecessary(bean, beanName, cacheKey);
		}
	}
	return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
	//targetSourcedBeans contains, indicating that it was created previously
	if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
		return bean;
	}
	if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
		return bean;
	}
	//Same judgment as before
	if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

	// Create proxy if we have advice.
	// Get Advisors, find Advisors, filter, and sort
	Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
	if (specificInterceptors != DO_NOT_PROXY) {
		this.advisedBeans.put(cacheKey, Boolean.TRUE);
		//This side is the same as the previous proxy object creation except that SingletonTargetSource is used by default
		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;
}

3. createProxy

Here are two important points: 1. How to get Advisor's, 2. How to create proxy objects, this first look at how to create proxy objects, the following is the implementation logic of createProxy:

protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors,
		TargetSource targetSource) {

	//Creating an agent is delegated to the ProxyFactory
	ProxyFactory proxyFactory = new ProxyFactory();
	// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
	
	// copy the configurations, which you'll see later when you use them
	proxyFactory.copyFrom(this);

	//Determine if you want to set proxyTargetClass=true based on some circumstances
	if (!proxyFactory.isProxyTargetClass()) {
		if (shouldProxyTargetClass(beanClass, beanName)) {
			proxyFactory.setProxyTargetClass(true);
		} else {
			evaluateProxyInterfaces(beanClass, proxyFactory);
		}
	}

	// Merge specified and generic intercept objects and adapt them to Advisor
	Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
	for (Advisor advisor : advisors) {
		proxyFactory.addAdvisor(advisor);
	}
	//Setting parameters
	proxyFactory.setTargetSource(targetSource);
	customizeProxyFactory(proxyFactory);
	proxyFactory.setFrozen(this.freezeProxy);
	if (advisorsPreFiltered()) {
		proxyFactory.setPreFiltered(true);
	}
	//Start creating the proxy when you are ready to do this
	return proxyFactory.getProxy(this.proxyClassLoader);
}

Then follow up in ProxyFactory:

public class ProxyFactory extends ProxyCreatorSupport {

	public Object getProxy(ClassLoader classLoader) {
		//Create AopProxy with ProxyFactory and Proxy with AopProxy, so it's important here to see what the obtained OpProxy object is. 
		// Then go in and see how to create a dynamic proxy with two options: jdk proxy, cglib
		return createAopProxy().getProxy(classLoader);
	}
}

public class ProxyCreatorSupport extends AdvisedSupport {
	private AopProxyFactory aopProxyFactory;
	
	public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}
	
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		//Get the factory that created the AopProxy, and create the AopProxy from there
		return getAopProxyFactory().createAopProxy(this);
	}
	
	public AopProxyFactory getAopProxyFactory() {
		return this.aopProxyFactory;
	}
}

The process is to create AopProxy with AopProxyFactory and then proxy object with AopProxy, where AopProxyFactory defaults to DefaultAopProxyFactory to see its createAopProxy method:

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
	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()) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		} else {
			return new JdkDynamicAopProxy(config);
		}
	}

	/**
	 * Determine whether the supplied {@link AdvisedSupport} has only the
	 * {@link org.springframework.aop.SpringProxy} interface specified (or no
	 * proxy interfaces specified at all).
	 */
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] interfaces = config.getProxiedInterfaces();
		return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.equals(interfaces[0])));
	}
}

This is to decide whether to use jdk proxy or cglib to create proxy objects. The simplest way to use it is to set proxyTargetClass=true to enforce cglib proxy. No parameters are set and the object class implements an interface. By default, jdk proxy is used, and cglib must be used if no interface is implemented.There are two steps: 1 to create a proxy object, 2 to call the target object method, the proxy class will find a matching Advisors to intercept, JdkDynamicAopProxy and Objenesis CglibAopProxy have a certain amount of logical description, to be analyzed separately.

IV. Advisor Acquisition

Advisor is implemented by the subclass AbstractAdvisorAutoProxyCreator, the entry method getAdvicesAndAdvisorsForBean:

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {

	protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
		//Find Advisors, filter, and sort
		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		//Finding candidate sets
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//Filtering candidate sets
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		//Extend to subclass implementation
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
			//sort
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
	}

	protected List<Advisor> findCandidateAdvisors() {
		//Inside is an object that gets all the Advisor interface types from the beanFactory
		return this.advisorRetrievalHelper.findAdvisorBeans();
	}
}

public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
	protected List<Advisor> findCandidateAdvisors() {
		// Add all the Spring advisors found according to superclass rules.
		//Call the parent class to get the object that implements the Advisor interface first
		List<Advisor> advisors = super.findCandidateAdvisors();
		// Build Advisors for all AspectJ aspects in the bean factory.
		// Next, get the AspectJ annotation modified
		advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
		return advisors;
	}
}

Advisor is acquired mainly in two cases: 1. Advisor interface is implemented, 2. Convert Advisor modified by @Aspect annotation.

 

The main point above is the overall situation. There are many details to explore inside, such as how @Aspect modifies the conversion to Advisor, how proxy objects are invoked, and so on.

Posted by winmastergames on Wed, 29 May 2019 09:46:04 -0700