Dynamic agent
There are two common ways to implement dynamic Proxy: using JDK Proxy and generating Proxy through CGLIB.
The role of dynamic agents:
- Enhance the function without changing the source code of the target class
- Reduce code duplication
- Focus on business logic code
- Decouple your business functions from logs, transactions and non business functions.
JDK dynamic agent
jdk dynamic proxy requires that the target object must implement the interface, which is the requirement of java design.
From jdk1 Since 3, the java language has passed java The lang.reflect package provides three classes to support the Proxy mode Proxy, Method and inovationhandler.
CGLIB dynamic proxy
CGLIB(Code Generation Library) is an open source project. It is a powerful, high-performance and high-quality code generation class library. It can extend Java classes and implement Java interfaces at run time. It is widely used by many AOP frameworks, such as Spring AOP.
cglib is a third-party tool library for creating proxy objects.
The principle of cglib is inheritance. Cglib creates its subclass by inheriting the target class, and rewrites the method with the same name in the parent class in the subclass to modify the function.
The generation principle of CGLIB proxy is to generate the subclass of the target class, and the subclass is enhanced. This subclass object is the proxy object. Therefore, using CGLIB to generate dynamic proxy requires that self labeled classes must be inherited, that is, they cannot be final classes.
contrast:
- Using JDK Proxy to implement Proxy requires that the target class and Proxy class implement the same interface. If the target class does not have an interface, it cannot be implemented in this way
- To create a dynamic proxy for a class without an interface, you need to use CGLIB to implement it.
- cglib is often used in frameworks, such as Spring, Hibernate, mybatis, etc.
- The proxy efficiency of cglib is higher than that of jdk. Cglib is not used in general development.
AOP overview
AOP introduction
AOP (aspect oriented programming), aspect oriented programming. Aspect oriented programming is to consider the program running process from a dynamic point of view.
The bottom layer of AOP is realized by dynamic agent mode. Two kinds of agents are used: dynamic agent of JDK and dynamic agent of CGLIB.
AOP is the abbreviation of Aspect Oriented Programming, which means: Aspect Oriented Programming, which can realize the unified maintenance of program functions through runtime dynamic agents.
AOP is an important part of the Spring framework. AOP can isolate each part of business logic, reduce the coupling between each part of business logic, improve the reusability of program, and improve the efficiency of development.
Aspect oriented programming is to encapsulate the cross business logic into aspects, and weave the aspects into the main business logic by using the function of AOP container. The so-called cross business logic refers to the common code independent of the main business logic, such as security check, transaction, log, cache, etc.
If AOP is not used, code entanglement will occur, that is, cross business logic and main business logic are mixed together. In this way, the main business logic will become confused. For example, before and after the real transfer business logic, transfer requires cross business logic such as permission control, logging, loading transactions and ending transactions, which are not directly related to the main business logic. However, their code volume can account for half or even more of the total code volume. Their existence not only produces a large number of "redundant" codes, but also greatly interferes with the main business logic - transfer.
Benefits of aspect oriented programming
- Reduce duplication;
- Focus on business;
- Note: aspect oriented programming is only a supplement to object-oriented programming.
AOP programming terminology
-
Aspect
Aspect generally refers to cross business logic. Transaction processing and log processing can be understood as aspects.
The commonly used aspect is Advice, which is actually an enhancement to the main business logic.
-
Join point
Connection point refers to the specific method that can be woven by cutting.
Generally, the methods in the business interface are connection points.
-
Pointcut
A pointcut is a collection of one or more declared join points. Specify a set of methods through pointcuts.
Methods marked final cannot be used as join points and pointcuts. Because the final can not be modified, can not be enhanced.
-
Target object
The target object is the object to be enhanced. That is, the object of the class containing the main business logic.
-
Advice
The notification indicates the execution time of the aspect, and Advice is also called enhancement.
In other words, notification defines the time point when the enhanced code cuts into the target code, whether it is executed before or after the execution of the target method.
Different notification types lead to different cut in times. The pointcut defines the position of the pointcut and notifies the time of the pointcut.
Implementation of AOP by AspectJ
For the programming idea of AOP, many frameworks have been implemented. Spring is one of them, which can complete aspect oriented programming. However, AspectJ also implements the function of AOP, and its implementation method is simpler, more convenient to use, and also supports annotated development. Therefore, spring also introduces AspectJ's implementation of AOP into its own framework.
When using AOP development in Spring, the implementation of AspectJ is generally used.
Introduction to AspectJ
AspectJ is an excellent aspect oriented framework, which extends the Java language and provides a powerful aspect implementation.
The full name of AspectJ is Eclipse AspectJ
Official website address: http://www.eclipse.org/aspectj/
a seamless aspect-oriented extension to the Javatm programming language(A method based on Java Aspect oriented programming language for platform) Java platform compatible(compatible Java Platform, which can be expanded seamlessly) easy to learn and use(Easy to learn and use)
The AspectJ framework implements AOP in two ways:
- Using xml configuration files: configuring global transactions
- Using annotations: AOP functions are generally used in projects. AspectJ often uses five annotations.
Use of AspectJ framework
Notification type for AspectJ
The execution time of the aspect, which is called Advice in the specification.
There are five types of notifications commonly used in AspectJ: (annotation or xml is often used)
- Advance notice: @ Before
- Post notification: @ AfterReturning
- Surround notification: @ Around
- Exception notification: @ AfterThrowing
- Final notification: @ After
See implementation steps for usage
Pointcut expression for AspectJ
AspectJ defines special expressions for specifying pointcuts.
The prototype of the expression is:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?) Explanation: modifiers-pattern] Access type ret-type-pattern return type declaring-type-pattern Package name class name name-pattern(param-pattern) Method name(Parameter type and number) throws-pattern Throw exception type ?Represents an optional part The above expression consists of four parts. Syntax: execution(Access rights? Method return value package name class name?.Method declaration(parameter) Exception type?)
The object to be matched by the pointcut expression is the method name of the target method. The signature of the method is obvious in the execution expression.
The following symbols can be used:
give an example:
execution(public * *(..)) The specified pointcut is: any public method. execution(* set*(..)) Specify the pointcut as: any one with“ set"How to start. execution(* com.xyz.service.*.*(..)) The specified pointcut is: defined in service Any method of any class in the package. execution(* com.xyz.service..*.*(..)) The specified pointcut is: defined in service Any method of any class in a package or sub package. “.."When it appears in the class name, it must be followed by“*",Represents all classes under package and sub package. execution(* *..service.*.*(..)) Specify all packages serivce All methods in all classes (interfaces) under the sub package are pointcuts
aop implementation steps of AspectJ
The purpose of using aop is to add additional functions to some existing classes and methods without changing the original classes and codes.
Basic steps:
-
New maven project
-
Add dependencies: spring dependency, aspectj dependency, Junit unit test dependency
-
Create target class: interface and implementation class (will add functionality to the methods of the class)
-
Create facet class: normal class
- Add @ Aspect to the class
- Define the method in the class. The method is the functional code to be executed
- Add the advice annotation in aspect to the method, such as @ Before, and specify that the pointcut expression is execution()
-
Create spring configuration file: declare objects and hand them over to container management.
(the declared object can be annotated or the < bean > tag of the xml file)
- Declare target object
- Declare facet class objects
- Declare the automatic proxy generator tag in the aspect framework. (automatic proxy generator: used to complete the automatic creation of proxy objects)
Supplement:
- After defining the Aspect aspect, you need to notify the Spring container to generate the proxy object of "target class + Aspect". This agent is automatically generated by the container. Just register an aspectj based automatic proxy generator in the Spring configuration file, and it will automatically scan the @ Aspect annotation, weave it in according to the notification type and pointcut, and generate the proxy.
- The underlying layer of < AOP: AspectJ AutoProxy / > is implemented by AnnotationAwareAspectJAutoProxyCreator. As can be seen from its class name, it is an automatic proxy generator for annotation adaptation based on AspectJ.
- The working principle is that < AOP: AspectJ AutoProxy / > scan to find the facet class defined by @ Aspect, and then
The face class finds the target method of the target class according to the pointcut, and then finds the pointcut time by the notification type.
- The working principle is that < AOP: AspectJ AutoProxy / > scan to find the facet class defined by @ Aspect, and then
- Create a test class, obtain the target object (actually the proxy object) from the spring container, and implement the method through the proxy to enhance the function of aop.
Example:
Import dependency:
<!-- unit testing --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- spring Framework dependency --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- aspect rely on --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.5.RELEASE</version> </dependency>
Create a target class interface and target implementation class:
package com.maj.ba01; // Target class interface public interface SomeService { void doSome(String name, Integer age); }
package com.maj.ba01; // Target class public class SomeServiceImpl implements SomeService { @Override public void doSome(String name, Integer age) { System.out.println("-------Target method doSome()-------"); } }
Create a facet class:
package com.maj.ba01; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import java.util.Date; @Aspect // This is an annotation in the aspect framework. It is used to indicate that the current class is an aspect class and an enhanced class public class MyAspect { /* * Definition method: the method used to realize the section function * Requirements for determination method: * 1.Public method public * 2.Method has no return value void * 3.Method name customization * 4.Methods can have no parameters or parameters * If there are parameters, which are not user-defined, several parameters can be used * * */ /* * @Before: Pre notification annotation * Attribute: value="execution(...)" Pointcut expression * */ @Before(value = "execution(public void com.maj.ba01.SomeServiceImpl.doSome(String, Integer))") public void myBefore(){ // Function code to be executed System.out.println("Pre notification, output the execution time before the target method:"+ new Date()); } }
spring configuration file:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- Declare target class object --> <bean id="someService" class="com.maj.ba01.SomeServiceImpl" /> <!-- Declare facet class objects --> <bean id="myAspect" class="com.maj.ba01.MyAspect" /> <!-- Declare automatic agent producer: use aspect Functions within the framework to create proxy objects for target objects. Creating a proxy object is implemented in memory and modifying the structure of the target object in memory. Therefore, the target object is the modified proxy object. aspectj-autoproxy: Will put spring All target objects in the container generate proxy objects at once --> <aop:aspectj-autoproxy /> <!-- <aop:aspectj-autoproxy proxy-target-class="true" /> --> <!-- proxy-target-class Properties: If it is not written by default, it is used by the implementation class with interface jdk Dynamic proxy, use without interface cglib Dynamic agent proxy-target-class The attribute value is true,Is mandatory cglib Dynamic agent --> </beans>
Test class:
package com.maj; import com.maj.ba01.SomeService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyText01 { @Test public void text01(){ String config = "applicationContext.xml"; ApplicationContext ac = new ClassPathXmlApplicationContext(config); // Obtain the target object from the container (although it looks like the target object is obtained here, it is actually a proxy object) SomeService proxy = (SomeService) ac.getBean("someService"); // Through the proxy object execution method, the function is enhanced when the target method is executed proxy.doSome("He dingdong",3); } }
Operation results:
Pre notification, output the execution time before the target method: Wed Jul 14 22:23:18 CST 2021 -------Target method doSome()-------
Before advice
Comments: @ Before
- Execute before the target method executes.
- Methods annotated as pre notification can contain a JoinPoint type parameter.
- It is used to obtain the target method to add the slice function (for example, doSome(String name, Integer age) method, which can obtain all relevant information)
- An object of this type is itself a pointcut expression.
- With this parameter, you can obtain the pointcut expression, method signature (definition), target object, etc.
- The value of the JoinPoint parameter is given by the framework and must be placed in the first position in the parameter.
- Not only the pre notification method, it can contain a JoinPoint type parameter, which can be included in all notification methods.
package com.maj.ba01; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import java.util.Date; @Aspect public class MyAspect { @Before(value = "execution(public void com.maj.ba01.SomeServiceImpl.doSome(String, Integer))") public void myBefore(JoinPoint jp){ // Gets the complete definition of the method System.out.println("Signature (definition) of method:" + jp.getSignature()); System.out.println("Name of method:" + jp.getSignature().getName()); // Gets the argument of the method Object[] args = jp.getArgs(); for (Object arg:args){ System.out.println("Parameter value:" + arg); } // Function code to be executed System.out.println("Pre notification, output the execution time before the target method:"+ new Date()); } }
Post notification
Comments: @ afterReturning
-
After the target method is executed.
-
Since it is executed after the target method, the return value of the target method can be obtained.
-
The returning attribute of this annotation is used to specify the variable name to receive the return value of the method.
-
Methods annotated as post notifications can contain variables for receiving return values in addition to the JoinPoint parameter. This change
It is best to use the Object type as the return value of the target method may be of any type.
Example:
package com.maj.ba02; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; @Aspect // This is an annotation in the aspect framework. It is used to indicate that the current class is an aspect class and an enhanced class public class MyAspect { /* * Post notification definition method: * Requirements for method definition: * 1. Public method public * 2. Method has no return value * 3. Method name customization * 4. If the method has parameters, Object is recommended, and the parameter name is user-defined */ /** * @AfterReturning: Post notification * Attribute: 1 Value pointcut expression * 2. returning Defined variables * Location: above the method definition * Features: 1 Executed after the target method. * 2. The return value of the target method can be obtained, and different processing can be done according to the return value * 3. You can modify the return value */ @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))", returning = "res") public void myAfterReturning(JoinPoint joinPoint, Object res){ /* Object res: Is the return value of the target method after execution. Do the function processing of your section according to the return value The parameter name here must be the same as the value of returning. */ System.out.println("Post notification: executed after the target method, The return value of the target method obtained is:" + res); } }
Around Advice
Comments: @ Around
- Surround notification is equivalent to jdk dynamic proxy (InvocationHandler interface)
- Before and after the target method is executed.
- Methods annotated as surround enhancement should have return values and Object types. And the method can contain a parameter of type ProceedingJoinPoint
- Interface ProceedingJoinPoint, which has a processed () method to execute the target method. If the target method has a return value, the return value of the method is the return value of the target method.
- ProceedingJoinPoint is an inherited JoinPoint, so the latter method can also be used
- Surround the enhancement method and return its return value.
- The enhancement method actually intercepts the execution of the target method.
- Surround notifications are often used to do business
Example:
package com.maj.ba03; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import java.util.Date; @Aspect // This is an annotation in the aspect framework. It is used to indicate that the current class is an aspect class and an enhanced class public class MyAspect { /* * Surround notification: used to realize the aspect function * Requirements for determination method: * 1.Public method public * 2.Method must have a return value. Object is recommended * 3.Method name customization * 4.Method has parameters. Fixed parameters: ProceedingJoinPoint * * */ /** * @Around: Around Advice * Attribute: value = "pointcut expression" * characteristic: * 1.The most powerful notification * 2. Enhancements can be made before and after the target method * 3.Controls whether the target method is called and executed * 4.You can modify the execution result of the original target method, affecting the result of the last call. * * The function of the parameter ProceedingJoinPoint is to execute the target method * Return value: it is the execution result of the target method and can be modified. */ @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { Object result = null; System.out.println("Surround notification: do things before the target method"); // Execution target method result = pjp.proceed(); System.out.println("Surround notification: do things after the target method"); // Return the return value of the target method (this can be the modified value) return result; } }
Exception notification
Comment: @ myAfterTrowing
Execute after the target method throws an exception.
The throwing property of this annotation is used to specify the exception class object that occurs.
The method annotated as exception notification can contain a parameter Throwable. The parameter name is the name specified by throwing, indicating the exception object.
package com.maj.ba04; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; @Aspect // This is an annotation in the aspect framework. It is used to indicate that the current class is an aspect class and an enhanced class public class MyAspect { /* * Exception notification: used to realize the section function * Requirements for determination method: * 1.Public method public * 2.Method has no return value void * 3.Method name customization * 4.Method has parameters Exception, and JoinPoint * * */ /** * @myAfterTrowing: Exception notification * Attribute: 1 Value = "pointcut expression" * 2.throwing A custom variable that represents the exception object thrown by the target method * The variable name must be the same as the parameter name * characteristic: * 1.Executed when the target method throws an exception * 2.An exception monitoring program can be used to monitor whether there are exceptions during the execution of the target method * @param ex */ @AfterThrowing(value = "execution(* *..SomeServiceImpl.doSecond(..))", throwing = "ex") public void myAfterTrowing(Exception ex){ System.out.println("Exception notification: executed when a method exception occurs"); System.out.println("Send information or e-mail to developers. The program is abnormal,Exception information:"+ex.getMessage()); } }
Final notice
Comments: @ After
- This enhancement is performed whether or not the target method throws an exception.
package com.maj.ba05; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; @Aspect // This is an annotation in the aspect framework. It is used to indicate that the current class is an aspect class and an enhanced class public class MyAspect { /* * Final notification: used to implement the section function * Requirements for determination method: * 1.Public method public * 2.Method has no return value void * 3.Method name customization * 4.Method does not have its own unique parameters, only JoinPoint parameters * * */ /** * doThird:Final notice * Attribute: value = "pointcut expression" * Location: above the method * Features: 1 Always execute * 2. Execute after target method * 3.Generally, it is used to clear resources */ @After(value = "execution(* *..SomeServiceImpl.doThird(..))") public void myAfter(){ System.out.println("Execute final notification: it will always be executed whether there are exceptions or not"); } }
@Pointcut defines the pointcut
This is similar to aliasing pointcuts
When more notification enhancement methods use the same execution pointcut expression, it is troublesome to write and maintain.
AspectJ provides the @ Pointcut annotation to define the execution Pointcut expression.
Usage:
- Annotate @ Pointcut on a method
- In the future, the method name can be used as the pointcut for all the value attribute values of execution.
- Represents the Pointcut defined by @ Pointcut.
This method using @ Pointcut annotation generally uses the private identification method, that is, the method that has no practical effect.
Example:
package com.maj.ba06; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect // This is an annotation in the aspect framework. It is used to indicate that the current class is an aspect class and an enhanced class public class MyAspect { /** * doThird:Final notice * Attribute: value = "pointcut expression" * Location: above the method * Features: 1 Always execute * 2. Execute after target method * 3.Generally, it is used to clear resources */ @After(value = "mypt()") public void myAfter(){ System.out.println("Execute final notification: it will always be executed whether there are exceptions or not"); } @Before(value = "mypt()") public void myBefore(){ System.out.println("Pre notification: executed before the target method"); } /** *@Pointcut: Define and manage entry points * Attribute: 1 Value = "pointcut expression" * Location: on a custom method * Features: 1 Alias pointcut representations * 2.In other notifications, if you want to use this pointcut expression, call the secondary method directly on the value of the value attribute */ @Pointcut(value = "execution(* *..SomeServiceImpl.doThird(..))") private void mypt(){ // No code required } }