Application and Research of AOP technology -- SpringAop implementation principle, aop -- springaop
Spring's AOP implementation complies with the conventions of the AOP alliance. At the same time, Spring has extended it and added some interfaces such as Pointcut and Advisor to make it more flexible. The Spring AOP module includes the basic concepts, notifications, and entry points of AOP, as well as the generation of the core AopProxy proxy object and the implementation of Spring AOP interceptor calls.
1. Basic concepts of Spring Aop
We have defined the basic concepts of AOP theoretically in the previous sections. Now we use the basic concepts of Spring AOP as an example to illustrate the basic concepts of AOP, in this way, we can better understand the basic concepts of AOP. In addition, we will briefly introduce the specific implementation of Spring AOP.
LAspect (Aspect): Modularization of a focus, which may cross multiple objects. 3.3.2 The Transaction processing class (Transaction) is a plane.
LJoin point (Joinpoint): A specific point in the program execution process, such as when a method is called or when an exception is handled. In Spring AOP, a connection pointAlwaysIndicates the execution of a method. In 3.3.2, proxy. updatePerson (); is the connection point.
L Advice: defines what is done at the connection point and provides the weaving interface for the aspect enhancement. In the above dynamic proxy example, the intransaction () and commit () Methods of the cross-section Transaction are pre-notifications and post-notifications respectively. In fact, the notification here is the method in the aspect. In Spring AOP, it mainly describes the face behavior injected by Spring AOP around method calls. Advice is an interface defined by the AOP Alliance. The specific interface is defined in org. aopalliance. aop. Advice. In the implementation of Spring AOP, this unified interface is used and more details and extensions are made for the enhanced weaving function of the AOP aspect, for example, more specific notification types are provided, such as BeforeAdvice, AfterAdvice, and ThrowsAdvice.
As an interface class defined by Spring AOP, the specific aspect enhancement can be integrated into the AOP framework through these interfaces. For these interface classes, we will take BeforeAdvice as an example. First, understand its class hierarchy. The 3.8, BeforeAdvice class hierarchy chart
In the inheritance relationship of BeforeAdvice, the interface MethodBeforeAdvice for the pre-notification set for the target Method to be enhanced is defined. To use this interface, you need to implement a callback function: void before (method Method, object [] args, Object target) throwsThrowable is used as the callback function. After the before () method is configured in Advice to the target method, it is called back during the target method. The specific call parameters include the Mehod Object, which is the reflection Object of the target method. The Object [] Object array contains the input parameters of the target Object method.
Pointcut): Determines which connection point the Advice notification should act on. A notification is associated with an entry expression and runs on the connection point that meets the entry expression (for example, when a method with a specific name is executed ). In dynamic proxy, if ("saveUser". equals (methodName) | "updateUser". equals (methodName) | ......) Is the entry point. When the method name matches the saveUser and updateUser, the corresponding notification is executed. Spring AOP provides specific cutting points for users. The starting point is shown in Spring AOP class inheritance system 3.9:
In Spring AOP, AnnotationMatchingPointcut for annotation configuration, JdkRegexpMethodPointcut for regular expressions, and so on. The actual call process is
LTarget Object): Since Spring AOP is implemented in the runtime era, this object will always beProxied)Object. That is, UserDaoImpl target = newUserDaoImpl (); target is the target object.
LTarget Object): Since Spring AOP is implemented in the runtime era, this object will always beProxied)Object. That is, UserDaoImpl target = newUserDaoImpl (); target is the target object.
L AOP Proxy: in Spring AOP, the AOP Proxy can be JDK dynamic Proxy or CGLIB Proxy. 3.3.2 In the example, proxy is the proxy object. We can easily find that the proxy object method = the target method + notification of the target object.
L-Weaving (Weaving): SpringAOP is similar to other pure Java AOP frameworks and is completed at runtime. Weaving is actually the process of forming a proxy.
L Advisor: Advisor is an extension of Spring AOP. After the Advisor completes the Advice and Pointcut design for the target method, it needs an object to combine them. The Advisor is used to accomplish this. Through Advisor, you can define which notification should be used and which focus should be used. That is to say, through Advisor, you can combine Advice and Pointcut to configure the AOP application using IoC containers. In Spring AOP, the implementation classes of Advisor have two attributes: advice and pointcut. You can configure the Advice and Pointcut attributes respectively.
2. Generate a proxy object
From the above dynamic proxy, we can know that the primary task of AOP is to generate proxy objects. For Spring applications, we can see that this task is completed by configuring and calling Spring's ProxyFactoryBean. During this generation process, JDK Proxy and cglib can be used for generation.
In the design center of ProxyFactory, we can see the related class inheritance relationship 3.10:
To analyze the underlying implementation of Spring AOP, you must first start with the ProxyConfig class. ProxyConfig is the base class for all Spring AOP proxy objects. It is a data class, it mainly provides configuration attributes for its AOP proxy object factory implementation class. According to the inheritance system of ProxyConfig, the role of creating common classes of AOP proxy is as follows:
L AdvisedSupport is a subclass of ProxyConfig. It encapsulates operations related to the Advice and Advisor in AOP, these operations are the same for the generation of different AOP proxy objects, but for the creation of specific AOP proxy objects, AdvisedSupport will hand it over to the subclass for implementation.
L ProxyCreatorSupport is a subclass of AdvisedSupport. It is an auxiliary class for its subclass to create an AOP proxy object. It provides general operations for generating different AOP proxy objects and generates specific AOP proxy objects, completed by the subclass of ProxyCreatorSupport.
L create a class for the AOP proxy object:
ProxyCreatorSupport has three sub-classes to create different AOP proxy objects, as shown below:
AspectJProxyFactory: it is mainly used to create AspectJ AOP applications and to integrate Spring and AspectJ. ProxyFactory: Create a programmatic Spring AOP application.
ProxyFactoryBean: Create a declarative Spring AOP application.
Since ProxyFactoryBean is the underlying method for creating an AOP application in Spring IoC environment, it is also the most flexible method. Spring uses it to encapsulate the use of AOP. The following describes the implementation of the AopProxy object through the implementation of ProxyFactoryBean.
In ProxyFactoryBean, the Proxy object is generated through the target object, so as to prepare for the cross-section AOP knitting. The specific Proxy object generation work is completed through jdk Proxy or cglib. The specific AopProxy generation process is shown in 3.11:
Public class ProxyFactoryBean extends ProxyCreatorSupportimplements FactoryBean <Object>, BeanClassLoaderAware, BeanFactoryAware {// The annotator is the global universal notifier public static final String GLOBAL_SUFFIX = "*"; // indicates whether the notification chain has completed initialization of private boolean advisorChainInitialized = false; // single-State mode Object private Object singletonInstance ;...... // ProxyFactoryBean the entry method for creating the AOPProxy proxy public Object getObject () throws BeansException {// initialize the notification chain initializeAdvisorChain (); // if the target object is in the single-State mode if (isSingleton () {// call the method for obtaining the single-State mode object to generate AOPProxy proxy return getSingletonInstance ();} // if the target object is in the prototype mode else {if (this.tar getName = null) {logger. warn ("Using non-singleton proxies with singleton targets is often undesirable. "+" Enable prototype proxies by setting the 'targetname' property. ") ;}// call the prototype object method to create a new AOPProxy proxy object return newPrototypeInstance ();}}
Through source code analysis, we know that ProxyFactoryBean implements the FactoryBean interface, so it is also a Spring factory Bean. The main functions of the AOP proxy factory are as follows:
A. initialize the notification chain and add the configured Notification chain to the Collection where the container stores the notification/notification chain.
B. Obtain AopProxy to generate the AopProxy proxy object based on the single-State mode/prototype mode.
The following is the source code of the getSingletonInstance () method of ProxyFactoryBean:
Private synchronized Object getSingletonInstance () {if (this. singletonInstance = null ){... // Omit this. singletonInstance = getProxy (createAopProxy ();} return this. singletonInstance;} source code of the red part getProxy (): protected Object getProxy (AopProxy aopProxy) {return aopProxy. getProxy (this. proxyClassLoader );}
It can be seen from the above that ProxyFactoryBean is an AopProxy object created through the createAopProxy () method to create an AopProxy proxy object (the AopProxy object and AopProxy proxy object are not the same concept, the AopProxy proxy object is created by the AopProxy object, and the AopProxy is an interface that declares the method getProxy () for creating the AopProxy proxy object ()). The getSingletonInstance () and newPrototypeInstance () Methods of pipeline get the AopProxy object by calling the createAopProxy () method of ProxyCreatorSupport (ProxyFactoryBean obtains the createAopProxy () method by inheriting ProxyCreatorSupport ), the source code of the createAopProxy () method of ProxyCreatorSupport is as follows:
protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);}
As shown in the source code above, AopProxyFactory is used to create an AopProxy object.
public AopProxyFactory getAopProxyFactory() {return this.aopProxyFactory;}public ProxyCreatorSupport() {this.aopProxyFactory = new DefaultAopProxyFactory();}
Obviously, this AopProxyFactory is DefaultAopProxyFactory. The following describes how DefaultAopProxyFactory generates the AopProxy proxy object.
Public AopProxy createAopProxy (AdvisedSupport config) throws AopConfigException {if (config. isOptimize () | config. isProxyTargetClass () | hasNoUserSuppliedProxyInterfaces (config )){... // The non-core part is omitted. // if the configured AOP target class is an interface, the dynamic JDK proxy mechanism is used to generate the if (targetClass. isInterface () {return new JdkDynamicAopProxy (config);} // if the target class configured by AOP is not an interface, use CGLIB to generate the AOP proxy if (! CglibAvailable) {throw new AopCongifgException ("Cannot proxy target class because CGLIB2 is not available. "+" Add CGLIB to the class path or specify proxy interfaces. ");} return CglibProxyFactory. createCglibProxy (config);} else {// The JdkDynamicAopProxy object return new JdkDynamicAopProxy (config) is generated by default );}}
Through the above analysis, we know that the AopProxy proxy object is generated by the AopProxy object. The AopProxy proxy object can be generated by jdk or cglib, while the JdkDynamicAopProxy and Cglib2AopProxy both implement the AopProxy interface and 3.12. Jdk corresponds to JdkDynamicAopProxy and cglib corresponds to Cglib2AopProxy.
Jdk generates the AopProxy proxy object
The list of proxies used by JdkDynamicAopProxy to generate proxy objects is as follows: public Object getProxy (ClassLoader classLoader) {if (logger. isDebugEnabled () {logger. debug ("Creating JDK dynamic proxy: target source is" + this. advised. getTargetSource ();} Class [] proxiedInterfaces = AopProxyUtils. completeProxiedInterfaces (this. advised); findDefinedEqualsAndHashCodeMethods (proxiedInterfaces); return Proxy. newProxyInstance (classLoader, proxiedInterfaces, this );}
Obviously, it calls the newProxyInstance () method of Proxy to generate the AopProxy Proxy object,
As we can see from the previous jdk dynamic proxy, This is the jdk dynamic proxy used. Proxy must specify three parameters when generating Proxy objects. One is the class loader, the other is the Proxy interface, and the other is the object where the Proxy callback method is located, this object needs to implement the InvocationHandler interface. JdkDynamicAopProxy implements the InvocationHandler interface and the invoke () method. This is the whole process in which Spring AOP uses jdk dynamic proxy to generate the AopProxy proxy object.
Cglib generates the AopProxy proxy object
Jdk's dynamic proxy can only generate proxy objects for interfaces. For target objects that do not implement interfaces, you must generate proxy objects through CGLIB of the third party. The main source code for creating an AopProxy proxy using CglibProxyFactory is as follows: // create the AOP proxy Object public Object getProxy (ClassLoader classLoader) {if (logger. isDebugEnabled () {logger. debug ("Creating CGLIB2 proxy: target source is" + this. advised. getTargetSource ();} try {// obtain the target object Class rootClass = this configured in the IoC container from the auxiliary Class created by the proxy. advised. getTargetClass (); Assert. state (rootClass! = Null, "Target class must be available for creating a CGLIB proxy"); // use the Target object as its own base Class class proxySuperClass = rootClass; // check whether the obtained target class is the if (AopUtils. isCglibProxyClass (rootClass) {// if the target class is generated by CGLIB, obtain the base class proxySuperClass = rootClass of the target class. getSuperclass (); // obtain the interface Class of the target Class [] additionalInterfaces = rootClass. getInterfaces (); // Add the interface of the target Class to the configuration of the auxiliary Class created by the container AOP proxy. for (Class additionalInterface: additionalInterfac Es) {this. advised. addInterface (additionalInterface) ;}}// verify the Proxy Base Class validateClassIfNecessary (proxySuperClass); // configure the CGLIB Enhancer class. 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) ;}/// sets the enhancer base class. setSuperclass (proxySuperClass); enhancer. setStrategy (new UndeclaredThrowableStrategy (UndeclaredThrowableException. class); // set the enhancer interface enhancer. setInterfaces (AopProxyUtils. completeProx IedInterfaces (this. advised); enhancer. setInterceptDuringConstruction (false); // sets the enhancer Callback method Callback [] callbacks = getCallbacks (rootClass); enhancer. setCallbacks (callbacks); // use the enhancer method configured in the notification server to filter the 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 ++) {types [x] = callbacks [x]. getClass ();} // sets the enhancer callback type. setCallbackTypes (types); // create the proxy Object proxy; if (this. constructorArgs! = Null) {proxy = enhancer. create (this. constructorArgTypes, this. constructorArgs);} else {proxy = enhancer. create ();} return proxy;} catch (CodeGenerationException ex) {throw new AopConfigException ("cocould 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 ("cocould 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 () failedthrow new AopConfigException ("Unexpected AOP exception", ex) ;}// gets the Callback notification of the given Class private Callback [] getCallbacks (Class rootClass) throws Exc Eption {// Optimization Parameter boolean exposeProxy = this. advised. isExposeProxy (); boolean isFrozen = this. advised. isFrozen (); boolean isStatic = this. advised. getTargetSource (). isStatic (); // create a dynamic notification Interceptor Based on the AOP configuration, the dynamic proxy created by CGLIB automatically calls the/DynamicAdvisedInterceptor class intercept method to intercept the target object. Callback aopInterceptor = new DynamicAdvisedInterceptor (this. advised); Callback targetInterceptor; // create a notification if (exposeProxy) {targe TInterceptor = isStatic? New Topology (this. advised. getTargetSource (). getTarget (): new DynamicUnadvisedExposedInterceptor (this. advised. getTargetSource ();} else {targetInterceptor = isStatic? New StaticUnadvisedInterceptor (this. advised. getTargetSource (). getTarget (): new DynamicUnadvisedInterceptor (this. advised. getTargetSource ();} // create the target distributor Callback targetDispatcher = isStatic? New StaticDispatcher (this. advised. getTargetSource (). getTarget (): new SerializableNoOp (); Callback [] mainCallbacks = new Callback [] {aopInterceptor, // general notification targetInterceptor, // If optimization is performed, the configuration notification new SerializableNoOp () is not taken into account. // The method targetDispatcher, this. advisedDispatcher, new EqualsInterceptor (this. advised), new HashCodeInterceptor (this. advised)}; Callback [] callbacks; // if the target is static and the notification chain is frozen, use the optimized AOP call, directly use // fixed notification chain if (isStatic & isFrozen) {Method [] methods = rootClass. getMethods (); Callback [] fixedCallbacks = new Callback [methods. length]; this. fixedInterceptorMap = new HashMap <String, Integer> (methods. length); for (int x = 0; x <methods. length; x ++) {List <Object> chain = this. advised. getInterceptorsAndDynamicInterceptionAdvice (methods [x], rootClass); fixedCallbacks [x] = new FixedChainStaticTargetInterceptor (chain, this. advised. getTargetSource (). getTarget (), this. advised. getTargetClass (); this. fixedInterceptorMap. put (methods [x]. toString (), x);} // copy the fixed Callback and main Callback to the Callback array. callbacks = new Callback [mainCallbacks. length + fixedCallbacks. length]; System. arraycopy (mainCallbacks, 0, callbacks, 0, mainCallbacks. length); System. arraycopy (fixedCallbacks, 0, callbacks, mainCallbacks. length, fixedCallbacks. length); this. fixedInterceptorOffset = mainCallbacks. length;} // if the target is not static or the notification chain is not frozen, use the main notification else {callbacks = mainCallbacks;} return callbacks;} of AOP ;}
From the code list above, we can see the use of specific cglib, such as the configuration of the Enhancer object and the process of generating the proxy object by the Enhancer object. During the process of generating proxy objects, you must note the callback settings of the Enhancer object. These callbacks encapsulate the implementation of Spring AOP, just like the invoke callback method of the jdkproxy object. In the callback settings of Enhancer, you can set the DynamicAdvisedInterceptor Interceptor to implement the AOP function. We can see the setting of the callback DynamicAdvisedInterceptor in the getCallBacks () method.
CallBack aopInterceptor = new DynamicAdvisedInterceptor (this. advised );
DynamicAdvisedInterceptor implements the MethodInterceptor class. In this way, after the target object is encapsulated by the AopProxy object, the getObject () method of ProxyFactoryBean is not a common object, but an AopProxy proxy object. In the target object configured in ProxyFactoryBean, the application will not directly call its method implementation, but is part of the AOP implementation. The method call to the target object is first intercepted by the AopProxy proxy object. For different AopProxy proxy object generation methods, different interception callback entries are used. For example, for the jdk AopProxy proxy object, the InvocationHandler callback entry is used; for the cglib AopProxy object, the set callback is used, this is determined by the use of cglib. In these callback callbacks, the implementation of AOP is completed through DynamicAdvisedInterceptor. The callback entry of DynamicAdvisedInterceptor is the intecepr () method. Through this series of preparations, we have already laid the foundation for implementing the cross-cutting mechanism of AOP. On this basis, the AOP advisor can use the AopProxy proxy object interception mechanism, the target object that needs to be enhanced has the powerful power of aspect.
3. Implementation of Spring AOP interceptor call
DynamicAdvisedInterceptor to complete the callback. The interception process of the two methods will be analyzed in detail below.
3.1. invoke interception of JdkDynamicAopProxy
Let's review that newProxyInstance (classLoader, proxiedInterface, this) is used to generate the Proxy object in JdkDynamicAopProxy. Here, this parameter corresponds to the InvocationHandler object, invocationHandler is an interface of the jdk-defined reflection class. InvocationHandler interface is implemented in JdkDynamicAopProxy. That is to say, when the Proxy object Proxy method is called, The invoke method of JdkDynamicAopProxy is triggered as the callback function of the Proxy object, so as to pass the specific implementation of invoke, to intercept the method call of the target object. The invoke of JdkDynamicAopProxy completes the Proxy object settings, including obtaining the target object, interceptor chain, and using these objects as input to create a ReflectiveMethodInvocation object, encapsulate the AOP function through the ReflectiveMethodInvocation object. The running sequence diagram is as follows:
3.2 Cglib2AopProxy intercept when analyzing the generation of the AopProxy proxy object of Cglib2AopProxy, we learned that the interception call to AOP is implemented in the DynamicAdvisedInterceptor object, the implementation of this callback is in the intercept method. The intercept callback Implementation of Cglib2AopProxy is very similar to that of JdkDynamicAopProxy, except that CglibMethodInvocation object is constructed in Cglib2AopProxy to call the interceptor chain, in JdkDynamicAopProxy, this function is implemented through the ReflectiveMethodInvocation object.
Application and Research of AOP technology in a series of blogs
Java programming. How ioc and aop in spring are implemented
It is cool to use java reflection technology;
Based on the given parameters (mainly strings)
Create a bean and access the corresponding method or constructor and member variables;
For more information about the application, see Constructor, Method, Field/java. lang. Class in the java. lang. reflect package.
Principles of declarative transactions using Spring AOP proxy
First, inject sessionFactory into HibernateTransactionManager, and then inject the HibernateTransactionManager object into the TransactionProxyFactoryBean object ~ There should be another definition of sessionFactory.
AOP is a proxy-oriented model. Originally, an application must operate on an object, but this object contains a lot of business logic unrelated to itself, not as good as logs and locks. So we need to find a way to extract all these irrelevant things out. The extracted object is the proxy object.
When the application calls the proxy object again, it will call the proxy object, which contains the call to the proxy object and the unrelated business logic method that is extracted. Proxy objects are purely business logic.
As for the trigger, when the container is up, for example, tomcat or jboss, the specified xml file will be defined and the injected content will be automatically identified.