Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze the Spring AOP source code

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/01 Report--

This article shows you how to carry out Spring AOP source code analysis, the content is concise and easy to understand, absolutely can make your eyes bright, through the detailed introduction of this article, I hope you can get something.

1 main interface 1.1 Advice notification

This API defines the enhancement methods of aspects, such as pre-enhanced BeforeAdvice, post-enhanced AfterAdvice, abnormal enhanced ThrowsAdvice, etc. Let's take a look at the source code of the two main subinterfaces.

Public interface MethodBeforeAdvice extends BeforeAdvice {/ * before the target method method starts execution, AOP will call back this method * / void before (Method method, Object [] args, Object target) throws Throwable;} public interface AfterReturningAdvice extends AfterAdvice {/ * after the target method method executes, AOP will call back this method. Note that it also passes in the return value of method * / void afterReturning (Object returnValue, Method method, Object [] args, Object target) throws Throwable } 1.2 Cross section of the Pointcut method

This API is used to define a set of target methods that need to be enhanced. Regular expressions are generally used to match and filter all target methods that meet the criteria within the specified range. There are many implementations of the Pointcut interface. Let's take a look at the implementation principles of JdkRegexpMethodPointcut and NameMatchMethodPointcut. The former mainly matches the method name through regular expressions, while the latter matches the method name.

/ / the implementation source code of JdkRegexpMethodPointcut is private Pattern [] compiledPatterns = new Pattern [0]; protected boolean matches (String pattern, int patternIndex) {Matcher matcher = this.originedPatterns [SecretnIndex] .matcher (pattern); return matcher.matches ();} / NameMatchMethodPointcut source code private List mappedNames = new LinkedList () Public boolean matches (Method method, Class targetClass) {for (String mappedName: this.mappedNames) {if (mappedName.equals (method.getName ()) | | isMatch (method.getName (), mappedName)) {return true;}} return false;} 1.3 Advisor notifier

Effectively combine Pointcut and Advice. It defines which methods (Pointcut) and which actions (Advice) are performed. Let's take a look at the source implementation of DefaultPointcutAdvisor, which effectively combines the two by holding the Pointcut and Advice attributes.

Public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {private Pointcut pointcut = Pointcut.TRUE; public DefaultPointcutAdvisor () {} public DefaultPointcutAdvisor (Advice advice) {this (Pointcut.TRUE, advice);} / * defines the Pointcut property itself, while the Advice attribute uses the definition * / public DefaultPointcutAdvisor (Pointcut pointcut, Advice advice) {this.pointcut = pointcut; setAdvice (advice) in the parent class. }} public abstract class AbstractGenericPointcutAdvisor extends AbstractPointcutAdvisor {/ / this class is an abstract class that holds a reference to Advice, while a reference to Pointcut holds private Advice advice; public void setAdvice (Advice advice) {this.advice = advice;} public Advice getAdvice () {return this.advice in a concrete subclass. } @ Override public String toString () {return getClass () .getName () + ": advice [" + getAdvice () + "];}} 2 Spring AOP Design and implementation

In the implementation code of AOP, JDK dynamic proxy is mainly used, and CGLIB generation proxy object is also used in specific scenarios (the proxied object does not have the interface of implements). From the source design of AOP, we can see that it first establishes a proxy object for the target object, and the generation of this proxy object can be done using JDK dynamic proxy or CGLIB. Then start the interceptor configured for the proxy object, enhance the cross section (the set of target methods), combine the cross section design of AOP with the Proxy pattern organically, and realize all kinds of weaving modes defined in AOP.

2.1 ProxyFactoryBean

Here we mainly take the implementation of ProxyFactoryBean as an example to analyze the implementation principle of AOP. ProxyFactoryBean mainly holds the proxy object aopProxy and Advisor notifier of the target object target, while Advisor holds Advice and Pointcut, so that you can determine whether the method in aopProxy is a specified section Pointcut, and then weave the corresponding enhancement behavior Advice for it through reflection according to its configured weaving direction (pre-enhancement / post-enhancement). First take a look at the configuration and use of ProxyFactoryBean.

Com.shuitu.ProxyInterface myAdvisor 2.2 generates AopProxy proxy objects for configured target

The getObject () method of ProxyFactoryBean initializes the notifier chain, and then generates a proxy object according to the type of the proxied object.

/ * returns a proxy object, which is called when the user gets bean from FactoryBean, * create an instance of AOP proxy to be returned by this factory, which will be cached as a singleton * / public Object getObject () throws BeansException {/ / initialize the notifier chain initializeAdvisorChain () / / the types of Singleton and prototype are distinguished here to generate the corresponding proxy if (isSingleton ()) {return getSingletonInstance ();} else {if (this.targetName = = null) {logger.warn ("Using non-singleton proxies with singleton targets is often undesirable. "+" Enable prototype proxies by setting the 'targetName' property. ");} return newPrototypeInstance () Initialize the Advisor chain / * initialize the Advisor chain. It can be found that the configured advisor notifier * / private synchronized void initializeAdvisorChain () throws AopConfigException is obtained by calling the getBean () method of the IoC container, and BeansException {/ / if the initialization of the notifier chain has been completed, directly return if (this.advisorChainInitialized) {return } if (! ObjectUtils.isEmpty (this.interceptorNames)) {if (this.beanFactory = = null) {throw new IllegalStateException ("No BeanFactory available anymore (probably due to serialization)" + "- cannot resolve interceptor names" + Arrays.asList (this.interceptorNames)) } if (this.interceptorNames [this.interceptorNames.length-1] .endsWith (GLOBAL_SUFFIX) & & this.targetName = = null & & this.targetSource = = EMPTY_TARGET_SOURCE) {throw new AopConfigException ("Target required after globals") } / / the call to the Advisor chain is added here, and the following interceptorNames is configured in the configuration file / / through interceptorNames. Since each Advisor is configured as bean, / / the name obtained by traversing the interceptorNames is actually the id of bean. Through this name (id) / / we can get the corresponding instantiated bean for (String name: this.interceptorNames) {if (logger.isTraceEnabled ()) {logger.trace ("Configuring advisor or advice'" + name + "'") from the IoC container. } if (name.endsWith (GLOBAL_SUFFIX)) {if (! (this.beanFactory instanceof ListableBeanFactory)) {throw new AopConfigException ("Can only use global advisors or interceptors with a ListableBeanFactory") } addGlobalAdvisor ((ListableBeanFactory) this.beanFactory, name.substring (0, name.length ()-GLOBAL_SUFFIX.length () } else {/ / A determines the type of the current factoryBean, whether it belongs to singleton bean or prototype bean Object advice If (this.singleton | | this.beanFactory.isSingleton (name)) {/ / get advisor through the getBean () method of beanFactory. / / this name is the advice = this.beanFactory.getBean (name) obtained from interceptorNames. } else {/ / if it is a prototype bean advice = new PrototypePlaceholderAdvisor (name);} addAdvisorOnChainCreation (advice, name);} this.advisorChainInitialized = true;}

The proxy object that generates the singleton is done in the getSingletonInstance method, which is the invocation entry for ProxyFactoryBean to generate the AopProxy proxy object. The proxy object encapsulates the call to the target object, and the method call to the target object is intercepted by the proxy object generated here.

2.4 generate a singleton proxy object / * return a singleton instance of such a proxy object, if the instance has not been created, create it singleton * / private synchronized Object getSingletonInstance () {if (this.singletonInstance = = null) {this.targetSource = freshTargetSource () If (this.autodetectInterfaces & & getProxiedInterfaces (). Length = 0 & &! isProxyTargetClass ()) {/ / determine the interface that needs to be proxied according to the AOP framework Class targetClass = getTargetClass (); if (targetClass = = null) {throw new FactoryBeanNotInitializedException ("Cannot determine target class for proxy") } / / set the interface of the proxy object setInterfaces (ClassUtils.getAllInterfacesForClass (targetClass, this.proxyClassLoader));} super.setFrozen (this.freezeProxy); / / here you will get the proxy object this.singletonInstance = getProxy (createAopProxy ());} return this.singletonInstance through AopProxy } / * * get the proxy object through the aopProxy returned by the createAopProxy () method * / protected Object getProxy (AopProxy aopProxy) {return aopProxy.getProxy (this.proxyClassLoader);}

The createAopProxy () method above invokes the implementation in ProxyFactoryBean's parent class, ProxyCreatorSupport.

Public class ProxyCreatorSupport extends AdvisedSupport {private AopProxyFactory aopProxyFactory; public ProxyCreatorSupport () {/ / Note that a DefaultAopProxyFactory is instantiated here, so the following createAopProxy () method / / also calls the DefaultAopProxyFactory implementation this.aopProxyFactory = new DefaultAopProxyFactory ();} protected final synchronized AopProxy createAopProxy () {if (! this.active) {activate () } / / calls the implementation of DefaultAopProxyFactory return getAopProxyFactory () .createAopProxy (this);} public AopProxyFactory getAopProxyFactory () {return this.aopProxyFactory;} public AopProxyFactory getAopProxyFactory () {return this.aopProxyFactory;}}

Let's take a look at the createAopProxy (AdvisedSupport config) method of the implementation class DefaultAopProxyFactory of the AopProxyFactory interface.

Public AopProxy createAopProxy (AdvisedSupport config) throws AopConfigException {/ / AopProxy proxy object generation process: / / first obtain the type targetClass of the configured target target object from the AdvisedSupport object, / / and then adopt different policies to generate the proxy object if (config.isOptimize () | | config.isProxyTargetClass () | hasNoUserSuppliedProxyInterfaces (config)) {Class targetClass = config.getTargetClass () depending on whether the targetClass is for the interface. If (targetClass = = null) {throw new AopConfigException ("TargetSource cannot determine target class:" + "Either an interface or a target is required for proxy creation.");} / *! * if the target class is an interface, use the JDK dynamic proxy, otherwise use CGLIB *! * / if (targetClass.isInterface ()) {return new JdkDynamicAopProxy (config);} return CglibProxyFactory.createCglibProxy (config);} else {return new JdkDynamicAopProxy (config);}}

You can see that it decides whether to use JDK dynamic proxy or CGLIB to generate proxy objects based on whether the target object implements the interface, and the only two implementation classes of the AopProxy interface are JdkDynamicAopProxy and CglibAopProxy.

2.5 JDK dynamic proxy generates AopProxy proxy object / * it can be seen that it implements the InvocationHandler interface, so it must also define a method for dynamically generating proxy object using java.lang.reflect.Proxy * and weave enhanced methods * / final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {/ * * AdvisedSupport hold a List attribute * / private final AdvisedSupport advised for proxy object in the implemented invoke () method. 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 is an AdvisedSupport object, which can be used to get the proxied object target / / so that when the invoke () method is called by the proxy object aopProxy, the target method of target can be called. This.advised = config;} public Object getProxy () {return getProxy (ClassUtils.getDefaultClassLoader ()) } public Object getProxy (ClassLoader classLoader) {if (logger.isDebugEnabled ()) {logger.debug ("Creating JDK dynamic proxy: target source is" + this.advised.getTargetSource ());} / / get the interface to be implemented by the proxy class Class [] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces (this.advised); findDefinedEqualsAndHashCodeMethods (proxiedInterfaces) / / generate proxy object through java.lang.reflect.Proxy and return return Proxy.newProxyInstance (classLoader, proxiedInterfaces, this);}}

It is clear from the source code of JdkDynamicAopProxy that it generates proxy objects using JDK dynamic proxies. JdkDynamicAopProxy implements the InvocationHandler interface and generates a proxy object through the newProxyInstance () static method of java.lang.reflect.Proxy and returns.

2.6 CGLIB generates the AopProxy proxy object final class CglibAopProxy implements AopProxy, and Serializable {/ * * AdvisedSupport holds a List attribute * / protected final AdvisedSupport advised; public Object getProxy (ClassLoader classLoader) {if (logger.isDebugEnabled ()) {logger.debug ("Creating CGLIB proxy: target source is" + this.advised.getTargetSource ());} try {Class rootClass = this.advised.getTargetClass () Assert.state (rootClass! = null, "Target class must be available for creating a CGLIB proxy"); Class proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass (rootClass)) {proxySuperClass = rootClass.getSuperclass (); Class [] additionalInterfaces = rootClass.getInterfaces (); for (Class additionalInterface: additionalInterfaces) {this.advised.addInterface (additionalInterface) }} validateClassIfNecessary (proxySuperClass); / / create and configure Enhancer objects. Enhancer is the main operation class in CGLIB, Enhancer enhancer = createEnhancer (); if (classLoader! = null) {enhancer.setClassLoader (classLoader) If (classLoader instanceof SmartClassLoader & ((SmartClassLoader) classLoader) .isClassReloadable (proxySuperClass)) {enhancer.setUseCache (false);}} enhancer.setSuperclass (proxySuperClass); enhancer.setStrategy (new MemorySafeUndeclaredThrowableStrategy (UndeclaredThrowableException.class)); enhancer.setInterfaces (AopProxyUtils.completeProxiedInterfaces (this.advised)) Enhancer.setInterceptDuringConstruction (false); Callback [] callbacks = getCallbacks (rootClass); enhancer.setCallbacks (callbacks); enhancer.setCallbackFilter (new ProxyCallbackFilter (this.advised.getConfigurationOnlyCopy (), this.fixedInterceptorMap, this.fixedInterceptorOffset)); Class [] types = new Class [callbacks.length]; for (int x = 0; x < types.length) X class +) {types [x] = callbacks [x] .getClass ();} enhancer.setCallbackTypes (types); / / generate proxy object Object proxy; if (this.constructorArgs! = null) {proxy = enhancer.create (this.constructorArgTypes, this.constructorArgs) via enhancer } else {proxy = enhancer.create ();} return proxy } catch (CodeGenerationException ex) {throw new AopConfigException ("Could not generate CGLIB subclass of class [" + 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 class [" + this.advised.getTargetClass () + "]:" + "Common causes of this problem include using a final class or a non-visible class", ex) } catch (Exception ex) {/ / TargetSource.getTarget () failed throw new AopConfigException ("Unexpected AOP exception", ex);}

After the proxy object is generated for the target object target, when the target method of the proxy object is called, the target method makes an invoke () callback (JDK dynamic proxy) or a callbacks () callback (CGLIB), and then the target method of the target object can be intercepted and enhanced in the callback method.

3 implementation of Spring AOP interceptor call

When Spring AOP generates the proxy object through the Proxy class of JDK, the relevant interceptor has been configured in the invoke () method of InvocationHandler (that is, ProxyBeanFactory) held by the proxy object, and the interceptor finally works by triggering the invoke () callback of InvocationHandler in the proxy class when the target method of the proxy object is called. The principle of AOP implemented through CGLIB is similar.

3.1 invoke () interception of JdkDynamicAopProxy

Now that the AopProxy proxy object has been generated in two different ways, let's take a look at the implementation of the interceptor call in the invoke () callback method in JdkDynamicAopProxy.

Final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; / / the surrogate object TargetSource targetSource = this.advised.targetSource; Class targetClass = null; Object target = null can be obtained through targetSource Try {/ / if the target object calls the basic methods in the Obejct class, such as equals (), hashCode (), then deal with if (! this.equalsDefined & & AopUtils.isEqualsMethod (method)) {/ / if the target object does not override the basic methods of the Object class: equals (Object other) return equals (args [0]) } if (! this.hashCodeDefined & & AopUtils.isHashCodeMethod (method)) {/ / if the target object does not override the basic method of the Object class: hashCode () return hashCode () } if (! this.advised.opaque & & method.getDeclaringClass (). IsInterface () & & method.getDeclaringClass (). IsAssignableFrom (Advised.class)) {/ / use proxy configuration to make service calls to ProxyConfig return AopUtils.invokeJoinpointUsingReflection (this.advised, method, args);} Object retVal If (this.advised.exposeProxy) {/ / if necessary, you can invoke oldProxy = AopContext.setCurrentProxy (proxy); setProxyContext = true;} / / get the target object in preparation for the call to the target method target = targetSource.getTarget () If (target! = null) {targetClass = target.getClass ();} / / get the defined interceptor chain, that is, Advisor list List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice (method, targetClass) / / if no interceptor is configured, call the method object of the target object target directly through reflection and get the return value if (chain.isEmpty ()) {retVal = AopUtils.invokeJoinpointUsingReflection (target, method, args) } else {/ / if there is an interceptor chain, you need to call the interceptor in the interceptor chain first, and then call the corresponding method of the target / / here invocation = new ReflectiveMethodInvocation (proxy, target, method, args, targetClass, chain) is implemented by constructing ReflectiveMethodInvocation / / continue to process retVal = invocation.proceed () down the interceptor chain;} / / get the type Class returnType = method.getReturnType () of the method return value If (retVal! = null & & retVal = = target & & returnType.isInstance (proxy) & &! RawTargetAccess.class.isAssignableFrom (method.getDeclaringClass () {/ / Special reminder: it returns "this" and the return type of the method is compatible with the type. / Note that if target sets its own reference in another returned object, Spring will not be able to handle 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 come from TargetSource. TargetSource.releaseTarget (target);} if (setProxyContext) {/ / stores the old proxy. Intercept () interception of AopContext.setCurrentProxy (oldProxy);} 3.2 CglibAopProxy

The intercept () callback method implementation of CglibAopProxy is very similar to JdkDynamicAopProxy's invoke (), except that the CglibMethodInvocation object is constructed in CglibAopProxy to complete the interceptor chain call, while in JdkDynamicAopProxy it is done by constructing the ReflectiveMethodInvocation object.

Final class CglibAopProxy implements AopProxy, Serializable {public Object intercept (Object proxy, Method method, Object [] args, MethodProxy methodProxy) throws Throwable {Object oldProxy = null; boolean setProxyContext = false; Class targetClass = null; Object target = null; try {if (this.advised.exposeProxy) {oldProxy = AopContext.setCurrentProxy (proxy); setProxyContext = true } target = getTarget (); if (target! = null) {targetClass = target.getClass ();} / / get the configured interceptor chain from the adviced object, where advised is an AdvisedSupport object, and AdvisedSupport is one of the parent classes of ProxyFactoryBean. List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice (method, targetClass); Object retVal; / / if AOP notification is not configured, call the target method directly using the MethodProxy object of CGLIB (chain.isEmpty () & & Modifier.isPublic (method.getModifiers () {retVal = methodProxy.invoke (target, args) } else {/ / initiates advice notification through CglibMethodInvocation, / / CglibMethodInvocation is a subclass of ReflectiveMethodInvocation / / the proceed () method of the ReflectiveMethodInvocation object that is finally called retVal = new CglibMethodInvocation (proxy, target, method, args, targetClass, chain, methodProxy). Proceed () } retVal = processReturnType (proxy, target, method, retVal); return retVal;} finally {if (target! = null) {releaseTarget (target);} if (setProxyContext) {/ / Restore old proxy. AopContext.setCurrentProxy (oldProxy);} 3.3 invocation of the target method in the target object

The call to the target method in the target object is done by using the reflection mechanism in the AopUtils utility class. The specific code is as follows.

Public abstract class AopUtils {/ * uses spring's reflection mechanism to call the target method method's invoke method * / public static Object invokeJoinpointUsingReflection (Object target, Method method, Object [] args) throws Throwable {try {/ / if the method is private, set its access to public's ReflectionUtils.makeAccessible (method) / / finally use reflection to call return method.invoke (target, args);} catch (InvocationTargetException ex) {throw ex.getTargetException ();} catch (IllegalArgumentException ex) {throw new AopInvocationException ("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", ex) } catch (IllegalAccessException ex) {throw new AopInvocationException ("Could not access method [" + method + "]", ex);}} 3.4 calls to the AOP interceptor chain

Although JdkDynamicAopProxy and CglibAopProxy use different proxy objects, the handling of AOP interception is the same, both through the proceed () method of ReflectiveMethodInvocation.

The collection of public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {protected final Object proxy; protected final Object target; protected final Method method; protected Object [] arguments; private final Class targetClass; / * * MethodInterceptor and InterceptorAndDynamicMethodMatcher * / protected final List interceptorsAndDynamicMethodMatchers; private int currentInterceptorIndex =-1; protected ReflectiveMethodInvocation (Object proxy, Object target, Method method, Object [] arguments, Class targetClass, List interceptorsAndDynamicMethodMatchers) {this.proxy = proxy This.target = target; this.targetClass = targetClass; this.method = BridgeMethodResolver.findBridgedMethod (method); this.arguments = arguments; this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers } public Object proceed () throws Throwable {/ / calls the interceptor sequentially from the interceptor chain until all interceptors are called and starts calling the target method The call to the target method / / is done through the invokeJoinpointUsingReflection () method of AopUtils in invokeJoinpoint (). If (this.currentInterceptorIndex = = this.interceptorsAndDynamicMethodMatchers.size ()-1) {/ / invokeJoinpoint () calls the target method directly through AopUtils. } / / this is processed along the defined chain of interceptorsAndDynamicMethodMatchers interceptors, / / it is a List, and there are no generics defined, interceptorOrInterceptionAdvice is one of the elements Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get (+ + this.currentInterceptorIndex) If (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {/ / here method matching is done through the interceptor's method matcher methodMatcher, / / if the target method of the target class matches the configured Pointcut, then the enhanced behavior advice will be executed, / / Pointcut defines the aspect method (the method to be enhanced) Advice defines the enhanced behavior InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice / / whether the target method of the target class is the facet if (dm.methodMatcher.matches (this.method, this.targetClass, this.arguments) defined by Pointcut) {/ / execute the enhanced method return dm.interceptor.invoke (this) of the current interceptor interceptor } else {/ / if it does not match, the process () method will be called recursively until all interceptors have been run until return proceed () }} else {/ / if interceptorOrInterceptionAdvice is a MethodInterceptor / /, directly call its corresponding method return ((MethodInterceptor) interceptorOrInterceptionAdvice) .invoke (this);} 3.5 configure the notifier

The method of getting the interceptor chain is implemented in AdvisedSupport and the cache is used.

Public class AdvisedSupport extends ProxyConfig implements Advised {/ * * TargetSource holds an important attribute, targetClass * / TargetSource targetSource = EMPTY_TARGET_SOURCE; / * * cache the Method object and its corresponding interceptor chain list List * / private transient Map methodCache; / * * The AdvisorChainFactory to use * / AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory () / * get the interceptor chain. In order to improve efficiency, the cache * / public List getInterceptorsAndDynamicInterceptionAdvice (Method method, Class targetClass) {/ / if there is an interceptor chain corresponding to getting the Method object from the cache in the cache methodCache / / not, call the / / getInterceptorsAndDynamicInterceptionAdvice () method of (DefaultAdvisorChainFactory) advisorChainFactory to get it. And cached to methodCache MethodCacheKey cacheKey = new MethodCacheKey (method) List cached = this.methodCache.get (cacheKey); if (cached = = null) {/ / is not in the cache, then get it from AdvisorChainFactory and put it into the cache cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice (this, method, targetClass); this.methodCache.put (cacheKey, cached);} return cached;}}

The job of getting the interceptor chain is done by AdvisorChainFactory, which is a factory for generating interceptor chains. Since there is only one implementation class DefaultAdvisorChainFactory for the AdvisorChainFactory interface, let's just look at the implementation in this class.

Public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {public List getInterceptorsAndDynamicInterceptionAdvice (Advised config, Method method, Class targetClass) {/ / Advisor chain is already held in the incoming config, and can be used directly here. / Advisor holds two important attributes: section Pointcut and enhanced behavior Advice List interceptorList = new ArrayList (config.getAdvisors () .length); / / determines whether the Advisors in config meets the configuration requirements boolean hasIntroductions = hasMatchingIntroductions (config, targetClass); / / gets the registry, which is a singleton pattern implementation AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance () For (Advisor advisor: config.getAdvisors ()) {/ / advisor if it is an instance of PointcutAdvisor if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor If (config.isPreFiltered () | | pointcutAdvisor.getPointcut (). GetClassFilter (). Matches (targetClass)) {/ / the interceptor chain is added through the instance object registry of AdvisorAdapterRegistry, and / / AdvisorAdapterRegistry plays an important role in weaving advisor [] interceptors = registry.getInterceptors (advisor). / / the method matcher for getting sections from pointcutAdvisor MethodMatcher mm = pointcutAdvisor.getPointcut () .getMethodMatcher () / / use the matches () method of MethodMatchers to match and judge the target method of the target class if (MethodMatchers.matches (mm, method, targetClass) HasIntroductions) {if (mm.isRuntime ()) {for (MethodInterceptor interceptor: interceptors) {interceptorList.add (new InterceptorAndDynamicMethodMatcher (interceptor, mm)) }} else {interceptorList.addAll (Arrays.asList (interceptors)) } / / advisor if it is an instance of IntroductionAdvisor else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor If (config.isPreFiltered () | | ia.getClassFilter () .matches (targetClass)) {Interceptor [] interceptors = registry.getInterceptors (advisor); interceptorList.addAll (Arrays.asList (interceptors));}} else {Interceptor [] interceptors = registry.getInterceptors (advisor) InterceptorList.addAll (Arrays.asList (interceptors));}} return interceptorList;} / * determine whether the Advisors in config meets the configuration requirements * / private static boolean hasMatchingIntroductions (Advised config, Class targetClass) {for (int I = 0; I < config.getAdvisors (). Length; iTunes +) {Advisor advisor = config.getAdvisors () [I] If (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (ia.getClassFilter () .matches (targetClass)) {return true;} return false;}}

The advisor notifier here is obtained from AdvisedSupport, while the initialization of advisor is done in the getObject () method of ProxyFactoryBean.

Public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware {/ * return a proxy object, which is called when the user gets bean from FactoryBean. * create an instance of AOP proxy to be returned by this factory, which will be cached as a singleton * / public Object getObject () throws BeansException {/ / initialize the notifier chain initializeAdvisorChain () / / the types of Singleton and Prototype are distinguished here to generate the corresponding proxy if (isSingleton ()) {return getSingletonInstance ();} else {if (this.targetName = = null) {logger.warn ("Using non-singleton proxies with singleton targets is often undesirable. "+" Enable prototype proxies by setting the 'targetName' property. ");} return newPrototypeInstance () }} / * initialize the Advisor chain, you can find that the configured advisor notifier * / private synchronized void initializeAdvisorChain () throws AopConfigException is obtained by calling the getBean () method of the IoC container. BeansException {/ / if the initialization of the notifier chain has been completed, return if (this.advisorChainInitialized) {return directly. } if (! ObjectUtils.isEmpty (this.interceptorNames)) {if (this.beanFactory = = null) {throw new IllegalStateException ("No BeanFactory available anymore (probably due to serialization)" + "- cannot resolve interceptor names" + Arrays.asList (this.interceptorNames)) } if (this.interceptorNames [this.interceptorNames.length-1] .endsWith (GLOBAL_SUFFIX) & & this.targetName = = null & & this.targetSource = = EMPTY_TARGET_SOURCE) {throw new AopConfigException ("Target required after globals") } / / the call to the Advisor chain is added here, and the following interceptorNames is configured in the configuration file / / through interceptorNames. Since each Advisor is configured as bean, / / the name obtained by traversing the interceptorNames is actually the id of bean (Advisor) Through this name (id) / / we can get the corresponding instantiated bean (Advisor) for (String name: this.interceptorNames) {if (logger.isTraceEnabled ()) {logger.trace ("Configuring advisor or advice'" + name + "'") from the bean container. } if (name.endsWith (GLOBAL_SUFFIX)) {if (! (this.beanFactory instanceof ListableBeanFactory)) {throw new AopConfigException ("Can only use global advisors or interceptors with a ListableBeanFactory") } addGlobalAdvisor ((ListableBeanFactory) this.beanFactory, name.substring (0, name.length ()-GLOBAL_SUFFIX.length () } else {/ / determines the type of the current factoryBean, whether it belongs to singleton bean or prototype bean Object advice If (this.singleton | | this.beanFactory.isSingleton (name)) {/ / advisor is configured as bean in the file, so the advisor is obtained through the getBean () method / / of beanFactory. This name is the advice = this.beanFactory.getBean (name) obtained from interceptorNames. } else {/ / if it is a prototype bean advice = new PrototypePlaceholderAdvisor (name) } / / put the advice obtained from the IoC container into the advisors interceptor chain, which is the addAdvisorOnChainCreation (advice, name) held by the parent class AdvisedSupport of ProxyFactoryBean / /;} this.advisorChainInitialized = true;}}

Note that Advisor itself is configured as bean, so its acquisition is also obtained through the IoC container.

3.6 implementation of Advice Notification

From the getInterceptorsAndDynamicInterceptionAdvice () method in the DefaultAdvisorChainFactory class, we can see that it adapts and registers the interceptor using the configured advisor through the getInterceptors () method of the AdvisorAdapterRegistry instance object.

Public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {public List getInterceptorsAndDynamicInterceptionAdvice (Advised config, Method method, Class targetClass) {/ / Advisor chain is already held in the incoming config. Here you can directly use the reference List interceptorList = new ArrayList (config.getAdvisors (). Length) in / / Advisor that holds the aspect Pointcut and the enhanced behavior Advice. / / determine whether the Advisors in config meets the configuration requirements boolean hasIntroductions = hasMatchingIntroductions (config, targetClass); / / get the registry, which is a singleton mode implementation AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance () For (Advisor advisor: config.getAdvisors ()) {/ / advisor if it is an instance of PointcutAdvisor if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor If (config.isPreFiltered () | | pointcutAdvisor.getPointcut (). GetClassFilter (). Matches (targetClass)) {/ / the interceptor chain is added through the instance object registry of AdvisorAdapterRegistry, and / / AdvisorAdapterRegistry plays an important role in weaving advisor [] interceptors = registry.getInterceptors (advisor). / / the method matcher for getting sections from pointcutAdvisor MethodMatcher mm = pointcutAdvisor.getPointcut () .getMethodMatcher () / / use the matches () method of MethodMatchers to match and judge the target method of the target class if (MethodMatchers.matches (mm, method, targetClass) HasIntroductions) {if (mm.isRuntime ()) {for (MethodInterceptor interceptor: interceptors) {interceptorList.add (new InterceptorAndDynamicMethodMatcher (interceptor, mm)) }} else {interceptorList.addAll (Arrays.asList (interceptors)) } / / advisor if it is an instance of IntroductionAdvisor else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor If (config.isPreFiltered () | | ia.getClassFilter () .matches (targetClass)) {Interceptor [] interceptors = registry.getInterceptors (advisor); interceptorList.addAll (Arrays.asList (interceptors));}} else {Interceptor [] interceptors = registry.getInterceptors (advisor) InterceptorList.addAll (Arrays.asList (interceptors));}} return interceptorList;}}

The getInterceptors () method of DefaultAdvisorAdapterRegistry encapsulates the entry of the advice weaving implementation.

Public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {/ / hold the list of AdvisorAdapter, the AdvisorAdapter in this list corresponds to / / implement the advice enhancement of Spring AOP private final List adapters = new ArrayList (3); / * * add the implemented AdviceAdapter to list * / public DefaultAdvisorAdapterRegistry () {registerAdvisorAdapter (new MethodBeforeAdviceAdapter ()); registerAdvisorAdapter (new AfterReturningAdviceAdapter ()); registerAdvisorAdapter (new ThrowsAdviceAdapter ()) } / * if adviceObject is an instance of Advisor, convert adviceObject to Advisor type and return * / public Advisor wrap (Object adviceObject) throws UnknownAdviceTypeException {if (adviceObject instanceof Advisor) {return (Advisor) adviceObject;} if (! (adviceObject instanceof Advice)) {throw new UnknownAdviceTypeException (adviceObject);} Advice advice = (Advice) adviceObject If (advice instanceof MethodInterceptor) {return new DefaultPointcutAdvisor (advice);} for (AdvisorAdapter adapter: this.adapters) {if (adapter.supportsAdvice (advice)) {return new DefaultPointcutAdvisor (advice);}} throw new UnknownAdviceTypeException (advice);} public MethodInterceptor [] getInterceptors (Advisor advisor) throws UnknownAdviceTypeException {List interceptors = new ArrayList (3) / / get the configured Advice Advice advice = advisor.getAdvice () from the Advisor notifier; / / if the advice is of MethodInterceptor type, add it directly to the interceptors without adapting to if (advice instanceof MethodInterceptor) {interceptors.add ((MethodInterceptor) advice) } / / A pair of notifications are adapted to use the three AdvisorAdapter already configured Then take out the encapsulated interceptor of AOP weaving function for (AdvisorAdapter adapter: this.adapters) {/ / adapter.supportsAdvice (advice) method from the corresponding / / adapter to verify the type of advice if (adapter.supportsAdvice (advice)) {interceptors.add (adapter.getInterceptor (advisor)) }} if (interceptors.isEmpty ()) {throw new UnknownAdviceTypeException (advisor.getAdvice ());} return interceptors.toArray (new MethodInterceptor [interceptors.size ()]);}}

From the implementation of DefaultAdvisorAdapterRegistry, we can see that it uses a series of AdviceAdapter adapters, such as MethodBeforeAdviceAdapter, AfterReturningAdviceAdapter, ThrowsAdviceAdapter, which completely correspond to the type of Advice. They all implement the same level of AdviceAdapter interface, undertake different adaptation tasks, and serve different Advice implementations one-to-one. Let's take MethodBeforeAdviceAdapter as an example and take a look at its source implementation.

Class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {public boolean supportsAdvice (Advice advice) {return (advice instanceof MethodBeforeAdvice);} public MethodInterceptor getInterceptor (Advisor advisor) {MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice (); return new MethodBeforeAdviceInterceptor (advice);}}

You can see that the getInterceptor () method takes the Advice out of the Advisor, creates a MethodBeforeAdviceInterceptor object, and returns, which holds a reference to the Advice. Let's take a look at the source implementation of the MethodBeforeAdviceInterceptor interceptor.

Public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {private MethodBeforeAdvice advice; / * create the corresponding MethodBeforeAdviceInterceptor object * / public MethodBeforeAdviceInterceptor (MethodBeforeAdvice advice) {Assert.notNull (advice, "Advice must not be null") for the specified advice; this.advice = advice } / * this invoke () method is the callback method of the interceptor The callback * / public Object invoke (MethodInvocation mi) throws Throwable {/ / first triggers the callback / / of the before () method of the advice object and then the callback this.advice.before (mi.getMethod (), mi.getArguments (), mi.getThis ()) of the process () method of MethodInvocation when the proxy object's method is called. Return mi.proceed ();}}

As you can see, the invoke () method of MethodBeforeAdviceInterceptor first triggers the before () method of advice, and then the proceed () method call of MethodInvocation.

Looking back at the previous code, in proceed () of the ReflectiveMethodInvocation triggered by the AopProxy proxy object, its invoke () method is called after getting the interceptor interceptor. According to the configuration rules of AOP, the interceptor invoke () callback triggered by ReflectiveMethodInvocation will eventually trigger the interceptor wrapper encapsulation of different Advice by Spring depending on the type of Advice. For example, MethodBeforeAdvice will eventually trigger the invoke () callback of MethodBeforeAdviceInterceptor, and so on, so we will not analyze them one by one here.

The above content is how to carry out Spring AOP source code analysis, have you learned the knowledge or skills? If you want to learn more skills or enrich your knowledge reserve, you are welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report