Aop Series III (agent) of spring source sharing

Posted by shiggins on Sun, 28 Jun 2020 06:22:28 +0200

Overall structure

For spring AOP Proxy objects, the main task is to create a ProxyFactory, and then create AopProxyFactory to create AopProxy, and then use AopProxy to create the corresponding Proxy.
The method call in the Proxy class Proxy created is to call MethodInvocation, which consists of MethodInterceptor interception chain obtained from AdvisedSupport and its target method.

Parents of ProxyFactory

ProxyConfig

You can see that this class is the base class of many classes. The AdvisedSupport used to create proxy proxy, the AbstractAutoProxyCreator used to automatically scan the Advisor and enhance the bean, and the two FA are introduced later ctoryBean:AbstractSingletonProxyFactoryBean And ScopedProxyFactoryBean, whose main function is to generate the desired proxy.

From the code point of view, it mainly deals with several parameters. And a copyFrom method for passing in classes that all inherit this class.

public class ProxyConfig implements Serializable {
    //Class proxy is mainly used to decide whether to use CglibAopProxy or JdkDynamicAopProxy as proxy
	private boolean proxyTargetClass = false;
    //Whether to optimize or not is mainly used in the DefaultAopProxyFactory to decide which type of AopProxy to create
	private boolean optimize = false;
    //Indicates whether the proxy class created under this configuration needs to be prevented from implementing the Advised interface
	boolean opaque = false;
    //Whether to expose the proxy to all invocation s, that is, whether to put the proxy into ThreadLocal before the call chain starts
	boolean exposeProxy = false;
    //Whether the corresponding advisor can be changed, and its subclass AdvisedSupport can be added to the advisor. If the configuration is set to frozon, the advisor and advice cannot be added
	private boolean frozen = false;
	
	public void copyFrom(ProxyConfig other) {
		Assert.notNull(other, "Other ProxyConfig object must not be null");
		this.proxyTargetClass = other.proxyTargetClass;
		this.optimize = other.optimize;
		this.exposeProxy = other.exposeProxy;
		this.frozen = other.frozen;
		this.opaque = other.opaque;
	}

}

Advised

The main function of this interface is to hold the information related to the advisor and advice of the corresponding proxy object in spring AOP, and all proxy objects generated by spring proxy implement this interface

public interface Advised extends TargetClassAware {
	boolean isFrozen();
	boolean isProxyTargetClass();
	Class<?>[] getProxiedInterfaces();
	boolean isInterfaceProxied(Class<?> intf);
	void setTargetSource(TargetSource targetSource);
	TargetSource getTargetSource();
	boolean isExposeProxy();
	void setPreFiltered(boolean preFiltered);
	boolean isPreFiltered();
	Advisor[] getAdvisors();
	void addAdvisor(Advisor advisor) throws AopConfigException;
	void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
	boolean removeAdvisor(Advisor advisor);
	void removeAdvisor(int index) throws AopConfigException;
	int indexOf(Advisor advisor);
	boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
	void addAdvice(Advice advice) throws AopConfigException;
	void addAdvice(int pos, Advice advice) throws AopConfigException;
	boolean removeAdvice(Advice advice);
	int indexOf(Advice advice);
	String toProxyConfigString();
}

AdvisedSupport

This class inherits the ProxyConfig and implements the Advised. The Advised interface implemented in the proxy finally implemented by AopProxy is actually implemented by this class. The main task of addAdvisor is to update the local cache, and add the interface that the introduction advisor needs to join to the interface that the agent object needs to implement. For addAdvice, these methods are ultimately to convert advice to DefaultPointcutAdvisor and defaultintroduction advisor for implementation.

This AdvisedSupport provides a very important method getInterceptorsAndDynamicInterceptionAdvice, which mainly obtains the corresponding call chain from the current advisor, but it only makes a cache, and the real call operation is delegated to DefaultAdvisorChainFactory

public class AdvisedSupport extends ProxyConfig implements Advised {
     
    //The targetSource corresponding to the proxy class is used to get the target of the proxy,
    //There are many types
	TargetSource targetSource = EMPTY_TARGET_SOURCE;
    
    //Whether class filtering has been done before
	private boolean preFiltered = false;
	
	//It is mainly to convert the advisor in this advisorSupport to the call chain of Interceptor
	AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();
	
	//Cache the relationship between methods and their corresponding call chains
	private transient Map<MethodCacheKey, List<Object>> methodCache;
	
	//The interface to be implemented by the corresponding agent using the AdvisedSupport (there is no method to modify the AdvisedSupport class)
	private List<Class<?>> interfaces = new ArrayList<Class<?>>();
	
	//The advisor s registered in the AdvisedSupprt can be used to generate call chains
	private List<Advisor> advisors = new ArrayList<Advisor>();
	
	//It's the replication of the advisors. The external acquisition is the advisor array. Adding or removing an advisor is to copy it from the advisors first and then to the advisor array (quick failure can be handled)
	private Advisor[] advisorArray = new Advisor[0];


    @Override
	public void addAdvisor(int pos, Advisor advisor) throws AopConfigException {
		if (advisor instanceof IntroductionAdvisor) {
			validateIntroductionAdvisor((IntroductionAdvisor) advisor);
		}
		addAdvisorInternal(pos, advisor);
	}
    
    private void addAdvisorInternal(int pos, Advisor advisor) throws AopConfigException {
		Assert.notNull(advisor, "Advisor must not be null");
		if (isFrozen()) {
			throw new AopConfigException("Cannot add advisor: Configuration is frozen.");
		}
		if (pos > this.advisors.size()) {
			throw new IllegalArgumentException(
					"Illegal position " + pos + " in advisor list with size " + this.advisors.size());
		}
		this.advisors.add(pos, advisor);
		//Copy data from the advisors list to the advisor array
		updateAdvisorArray();
		//Clear methodCache cache
		adviceChanged();
	}
    
    //Add the interfaces that need to be added in the introduction advisor to the interfaces for the proxy object to implement
    private void validateIntroductionAdvisor(IntroductionAdvisor advisor) {
		advisor.validateInterfaces();
		// If the advisor passed validation, we can make the change.
		Class<?>[] ifcs = advisor.getInterfaces();
		for (Class<?> ifc : ifcs) {
			addInterface(ifc);
		}
	}

    //Convert the registered advisor to the (Interceptor,MethodInterceptor,InterceptorAndDynamicMethodMatcher) in the call chain
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
		MethodCacheKey cacheKey = new MethodCacheKey(method);
		List<Object> cached = this.methodCache.get(cacheKey);
		if (cached == null) {
			cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
			this.methodCache.put(cacheKey, cached);
		}
		return cached;
	}
}

DefaultAdvisorChainFactory

The main method of this class is getInterceptorsAndDynamicInterceptionAdvice. Its main function is to convert the advisor into a call chain. For PointcutAdvisor, match the method after matching the class, For the introduction advisor, the advisor AdapterRegistry is used to convert it to the corresponding one after the class is matched. For other advisors, the corresponding Interceptor is obtained from the advisor AdapterRegistry. The function of the advisor AdapterRegistry is to adapt the original method before advice, Afterreturning these advice that does not implement MethodInterceptor are converted to their corresponding adaptation objects.

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

	@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, Class<?> targetClass) {

		List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
		//It is mainly to convert the advice of MethodBeforeAdvice,AfterReturning and other advice written above into the advice of MethodInterceptor
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

		for (Advisor advisor : config.getAdvisors()) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
						 chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}
	
	private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {
		for (Advisor advisor : config.getAdvisors()) {
			if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (ia.getClassFilter().matches(actualClass)) {
					return true;
				}
			}
		}
		return false;
	}

}

ProxyCreatorSupport

This class inherits the AdvisedSupport * * class. It does two things: one is to maintain an AopProxyFactory * * which is the same as creating AopProxy; the other is to maintain the listener AdvisedSupportListener, which mainly receives notification when it changes the Advisor. (however, it seems that spring does not provide an interface for external registration or internal registration, so the specific role of this listener is not clear to the author.).

public class ProxyCreatorSupport extends AdvisedSupport {

	private AopProxyFactory aopProxyFactory;

	private final List<AdvisedSupportListener> listeners = new LinkedList<AdvisedSupportListener>();
	
	private boolean active = false;
	
	public ProxyCreatorSupport() {
		this.aopProxyFactory = new DefaultAopProxyFactory();
	}
	public AopProxyFactory getAopProxyFactory() {
		return this.aopProxyFactory;
	}

	public void addListener(AdvisedSupportListener listener) {
		Assert.notNull(listener, "AdvisedSupportListener must not be null");
		this.listeners.add(listener);
	}
	
	public void removeListener(AdvisedSupportListener listener) {
		Assert.notNull(listener, "AdvisedSupportListener must not be null");
		this.listeners.remove(listener);
	}

	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}
	private void activate() {
		this.active = true;
		for (AdvisedSupportListener listener : this.listeners) {
			listener.activated(this);
		}
	}
	@Override
	protected void adviceChanged() {
		super.adviceChanged();
		synchronized (this) {
			if (this.active) {
				for (AdvisedSupportListener listener : this.listeners) {
					listener.adviceChanged(this);
				}
			}
		}
	}
	protected final synchronized boolean isActive() {
		return this.active;
	}

}

ProxyFactory

This class is inherited from ProxyCreatorSupport. It is the class that spring finally uses to create the proxy. Its proxyfactory ා getProxy() is used by AbstractAutoProxyCreator to create the proxy object and put it in the container. However, there are not many specific things. It mainly provides a getproxy () which is the same as creating a proxy class. Its main logic is to create an AopProxy and use AopProxy to create the corresponding proxy class. For AopProxy, from the top class diagram, we can see that there are mainly three implementation classes. For AopProxy, we use AopProxyFactory to create it.

public class ProxyFactory extends ProxyCreatorSupport {

	
	public Object getProxy() {
		return createAopProxy().getProxy();
	}

	public Object getProxy(ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}

}

DefaultAopProxy

This class is mainly used in proxycreator support to create AopProxy. It is mainly used to decide whether to use JdkDynamicAopProxy or objeenesiscgliboaoproxy according to the configuration and whether the class to be proxy is an interface or not. You can see that the parameter it passed in is AdvisedSupport

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() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}

	
	private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
		Class<?>[] ifcs = config.getProxiedInterfaces();
		//Spring proxy is an interface that spring proxy classes will implement
		return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
	}

}

AopProxy family

This interface only needs two methods getProxy(), and is overloaded. Its main function is to produce a proxy class.

public interface AopProxy {
	Object getProxy();
	Object getProxy(ClassLoader classLoader);
}

JdkDynamicAopProxy

JdkDynamicAopProxy implements two interfaces, AopProxy and InvocationHandler. Its getProxy() method uses the Proxy provided by jdk to get the Proxy class. In this way, the corresponding interface methods call the invoke method of InvocationHandler, and the corresponding invoke method mainly does these things:

Note: only the equals, hashcode and toString() methods of the 7 types of methods of the Object object Object can enter the invoke() method, but the notify, notifyall(), wait and getclass() methods will not enter the invoke method

  • Provides a default implementation for proxy objects that do not implement the equals and hashcode proxy methods (indicating that if there is no target and toString is not processed in the call chain, printing the proxy object directly will explode the null pointer exception)
  • For decorating proxy, the method call of the Advised interface directly calls the corresponding implementation object for processing
  • Expose yourself to ThreadLocal
  • Get target from targetSource
  • Create call chain
  • Build the ReflectiveMethodInvocation object with target, call chain and target method and delegate it to proceed for calling.
  • Convert the return value of target type in the return value to the corresponding proxy object
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

	private final AdvisedSupport advised;
	private boolean equalsDefined;
	private boolean hashCodeDefined;

	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
	}


	@Override
	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}

	@Override
	public Object getProxy(ClassLoader classLoader) {
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		//Find out whether there are methods of equals and hashcode from all methods of all interfaces, and set the identity bits of equals defined and hashCodeDefined
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}
   
	@Override
	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 {
		      //utilize Proxy.newProxyInstance Among the generated objects, three of the seven methods of the Object, hashcode,equals and toString(), will enter this
             //In the invoke method, there is a default implementation for both equals and hashcode methods,
             //There is no default implementation for toString, so the call chain will be enhanced for toString()
            //Finally, the toString() method of its target is called
			if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
				return equals(args[0]);
			}
			else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
				return hashCode();
			}
		    //For the getDecoratedClass() method in the DecoratingProxy, you can find it directly from the targetSource of AdvisedSupport
			else if (method.getDeclaringClass() == DecoratingProxy.class) {
				return AopProxyUtils.ultimateTargetClass(this.advised);
			}
			//For the Advised interface, directly call AdvisedSupport for implementation
			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 the proxy is configured to be exposed, put it directly into ThreadLocal
			if (this.advised.exposeProxy) {
				oldProxy = AopContext.setCurrentProxy(proxy);
				setProxyContext = true;
			}
			//Get target from targetSource
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}
			//Generating call chain of Advisor by registering in AdvisedSupport
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            //Call chain is empty direct call target method
			if (chain.isEmpty()) {
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			//If the call chain has data, it will be converted to reflective method invocation for calling
			else {
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
				retVal = invocation.proceed();
			}
            //For the return type of its own, convert it to a proxy object, but if the return value will be self wrapped in another object, it cannot be converted to a proxy object
            //The object obtained in that way is not enhanced
			Class<?> returnType = method.getReturnType();
			if (retVal != null && retVal == target &&
					returnType != Object.class && returnType.isInstance(proxy) &&
					!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
				retVal = proxy;
			}
			//If the basic type returns null, throw the exception directly
			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 the target is not static, the resource will be returned, which may be pooled data
			if (target != null && !targetSource.isStatic()) {
				targetSource.releaseTarget(target);
			}
			if (setProxyContext) {
				AopContext.setCurrentProxy(oldProxy);
			}
		}
	}


	@Override
	public boolean equals(Object other) {
		if (other == this) {
			return true;
		}
		if (other == null) {
			return false;
		}
		JdkDynamicAopProxy otherProxy;
		if (other instanceof JdkDynamicAopProxy) {
			otherProxy = (JdkDynamicAopProxy) other;
		}
		//Finally, the proxy object compares its corresponding JdkDynamicAopProxy
		else if (Proxy.isProxyClass(other.getClass())) {
			InvocationHandler ih = Proxy.getInvocationHandler(other);
			if (!(ih instanceof JdkDynamicAopProxy)) {
				return false;
			}
			otherProxy = (JdkDynamicAopProxy) ih;
		}
		else {
			return false;
		}
         
        //You can see whether the comparison between the two agent classes is equal, and the final comparison is their AdvisedSupport 
		return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);
      
      /*
      //This is the equalInProxy method it calls. You can see that the interface it implements is the same comparison between the two proxy classes,
      //Its woven advisor and its corresponding targetSource
      public static boolean equalsInProxy(AdvisedSupport a, AdvisedSupport   b) {
		return (a == b ||
				(equalsProxiedInterfaces(a, b) && equalsAdvisors(a, b) && a.getTargetSource().equals(b.getTargetSource())));
	}
  *   
	}
	@Override
	public int hashCode() {
		return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
	}

}

CglibAopProxy

This class inherits the AopProxy interface, and its main function is to generate proxy objects. However, it uses Cglib to generate corresponding objects, and its main operation is to use ProxyCallbackFilter to determine which callback its corresponding method should use, except for several special ones like hashcode(), For the methods under equals and Advised interfaces, other methods are mainly optimized for performance. For the methods with advice in the call chain and the data will not change, the call chain will be cached directly and then built into FixedChainStaticTargetInterceptor for processing. The constant judgment condition is that there is advice and it is configured as frozon, that is, it is exposed The Advised interface cannot modify the advisor, and the data obtained in its targetSource will not change, that is, static and other operations. However, if there is no call chain and there is no call chain, it will be called directly with target, and whether to expose the proxy and other operations is considered to choose the configuration of exposeProxy to select the callback.

method With advice frozon exposeProxy targetSource is static Interceptor or Dispatcher effect
final type method O O O O SerializableNoOp No operation
Methods under the Advised interface O O O O AdvisedDispatcher Call directly with AdvisedSupport
equals method O O O O EqualsInterceptor Compare AdvisedSupport
hashcode method O O O O HashCodeInterceptor Using target to calculate hashcode
O yes yes no yes FixedChainStaticTargetInterceptor Using fixed call chain and target call
O no yes yes yes StaticUnadvisedExposedInterceptor Call directly with target and expose proxy
O no yes yes no DynamicUnadvisedExposedInterceptor Get target from targetSource, call and expose proxy
O no yes no yes StaticUnadvisedInterceptor Call directly with target
O no yes no no DynamicUnadvisedInterceptor Get target from targetSource and call
O X X X X DynamicAdvisedInterceptor Generate target and call chain execution
@Override
	public Object getProxy(ClassLoader classLoader) {
		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Class<?> proxySuperClass = rootClass;
			if (ClassUtils.isCglibProxyClass(rootClass)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}
			//Check whether the non privite method defined by final is header, etc
			validateClassIfNecessary(proxySuperClass, classLoader);
			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));
			//Get various types of callback s
			Callback[] callbacks = getCallbacks(rootClass);
			//Create the corresponding callback for each location, mainly using ProxyCallbackFilter to decide which callback to call
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			
			//Register ProxyCallbackFilter to decide which callback to call
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

ObjenesisCglibAopProxy

This class inherits CglibAopProxy, and its main function is to generate corresponding objects when there is no nonparametric construction method in the target class. The main idea is to override the createProxyClassAndInstance method and try to instantiate the proxy object with springobjective first.

class ObjenesisCglibAopProxy extends CglibAopProxy {
	private static final SpringObjenesis objenesis = new SpringObjenesis();
	@Override
	@SuppressWarnings("unchecked")
	protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
		Class<?> proxyClass = enhancer.createClass();
		Object proxyInstance = null;

		if (objenesis.isWorthTrying()) {
			try {
				proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
			}
			catch (Throwable ex) {
				logger.debug("Unable to instantiate proxy using Objenesis, " +
						"falling back to regular proxy construction", ex);
			}
		}

		if (proxyInstance == null) {
			// Regular instantiation via default constructor...
			try {
				proxyInstance = (this.constructorArgs != null ?
						proxyClass.getConstructor(this.constructorArgTypes).newInstance(this.constructorArgs) :
						proxyClass.newInstance());
			}
			catch (Throwable ex) {
				throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
						"and regular proxy instantiation via default constructor fails as well", ex);
			}
		}

		((Factory) proxyInstance).setCallbacks(callbacks);
		return proxyInstance;
	}

}

MethodInvocation family

MethodInvocation is an interface defined by aopalliance. It inherits JoinPoint and represents method call. spring defines the ProxyMethodInvocation interface under it, and defines some methods that need to be invoked in Advice.

ProxyMethodInvocation

ProxyMethodInvocation inherits the MethodInvocation interface. Its main function is to provide some corresponding methods needed in the implementation of the corresponding Advice.

public interface ProxyMethodInvocation extends MethodInvocation {
    //Get the current proxy object, and return to the enhancement method of introduction if it is the object corresponding to the implementation that needs to enhance the interface
    //You need to convert it to this proxy object
	Object getProxy();
    
	MethodInvocation invocableClone();
    //Get the clone object of this object. The clone object is mainly copied by argument, but the corresponding
    //The index of attribute, call chain and call chain are all public, so the call chain called by clone object is used
    //It's going to keep going
    //Its main reference is the method invocationproceedingjoinpoint, which is used when the joinPoint is called to around and other enhanced self calls
	MethodInvocation invocableClone(Object... arguments);
	
	void setArguments(Object... arguments);

    //The attributes, current JoinPoint, JoinPointMatch and other information stored in a map during the call cycle are all stored in this map
	void setUserAttribute(String key, Object value);

	Object getUserAttribute(String key);

}

ReflectiveMethodInvocation

Reflective method invocation implements the proxymethod invocation interface, which is the method invocation finally called by JdkDynamicAopProxy, while its implementation of the proceedmethod is realized by recursively calling and then advancing the index of the call chain.

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { 
    //Proxy object
	protected final Object proxy;
    //Target object
	protected final Object target;
    //Target method
	protected final Method method;
    //Target parameters
	protected Object[] arguments;
    //Target class
	private final Class<?> targetClass;
    //Store the properties of this call cycle
	private Map<String, Object> userAttributes;
    //Call chain
	protected final List<?> interceptorsAndDynamicMethodMatchers;
    //Call chain index
	private int currentInterceptorIndex = -1;
    ...
	@Override
	public Object proceed() throws Throwable {
	    //Call the target method when the call chain goes to the last
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}
		//Call the corresponding advice. Each time advice is called, the index of the call chain is advanced one time
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		//For InterceptorAndDynamicMethodMatcher, match dynamically, and call the corresponding advice if the match is successful, otherwise
	   //Then the call chain is directly advanced 1 by using the procedure
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				return proceed();
			}
		}
		else {
		    //If it is not InterceptorAndDynamicMethodMatcher, it will pass itself to the corresponding advice to determine the specific
		    //When to call proceed
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}
	//Reflection call target method
	protected Object invokeJoinpoint() throws Throwable {
		return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
	}

    //Get the clone object and find that the clone object is the same as the current object except for the parameters
	@Override
	public MethodInvocation invocableClone(Object... arguments) {
		if (this.userAttributes == null) {
			this.userAttributes = new HashMap<String, Object>();
		}
		try {
			ReflectiveMethodInvocation clone = (ReflectiveMethodInvocation) clone();
			clone.arguments = arguments;
			return clone;
		}
		catch (CloneNotSupportedException ex) {
			throw new IllegalStateException(
					"Should be able to clone object of type [" + getClass() + "]: " + ex);
		}
	}

}

CglibMethodInvocation

This is the method invocation used by CglibAopProxy. It inherits the reflective method invocation and mainly rewrites the method calling the target method. For public, it is implemented by calling the invoke method of methodProxy.

private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

		private final MethodProxy methodProxy;

		private final boolean publicMethod;

		public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
				Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

			super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
			this.methodProxy = methodProxy;
			this.publicMethod = Modifier.isPublic(method.getModifiers());
		}
		@Override
		protected Object invokeJoinpoint() throws Throwable {
			if (this.publicMethod) {
				return this.methodProxy.invoke(this.target, this.arguments);
			}
			else {
				return super.invokeJoinpoint();
			}
		}
	}

Topics: Spring JDK Attribute