AOP concept
-
What is AOP?
Aspect oriented programming, AOP can isolate all parts of business logic, so as to reduce the coupling between all parts of business logic, improve the reusability of programs, and improve the development efficiency.
Generally speaking, it is to enhance the main functions without modifying the source code
-
AOP underlying principle
The underlying AOP uses dynamic proxies
-
The first case: there are interfaces and JDK dynamic agent technology is used
Create interface implementation class proxy object
-
The second case: without interface, CGLIB dynamic agent technology is used
Creates a proxy object for a subclass of the current class
-
-
AOP underlying principle (JDK dynamic agent technology)
Scenario simulation: we already have a UserDaoImpl class that implements the methods of the UserDao interface. Now we want to enhance these two methods without changing the source code
public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; } @Override public String update(String username) { return username; } }
The first thing to use is the Proxy class. Call the Proxy.newProxyInstance method to create a Proxy object of the UserDao interface
Looking at the Java 8 documentation, this method requires three parameters
- First parameter: class loader
- The second parameter: the interface of the implementation class
- The third parameter is an interface object. We can use anonymous internal classes or create an implementation class of the interface. The methods in the implementation class are used to enhance the code
public class MyProxy { public static void main(String[] args) { Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), interfaces, new UserProxy(userDao)); int add = dao.add(10, 20); System.out.println("After enhancement, the results are:" + add);//60 } } class UserProxy implements InvocationHandler { //The UserDao Object could have been written here. For the sake of generality, it is written out as an Object object private Object obj; public UserProxy(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //Explain the parameters. Method represents the method name we call externally, and args represents the parameters in the method //Enhanced code before method execution System.out.println(method.getName() + "Before the method, the parameters are:" + Arrays.toString(args)); //Enhanced method execution Object result = method.invoke(obj, args); //Enhanced code after method execution System.out.println("The result of the original method is:" + result);//30 //This code is only applicable to the add method. I want to test whether I can modify the return value int result1 = (int)result * 2; return result1; } }
-
AOP related terms
- Join point: which methods in the class can be enhanced. These methods are called join points
- Pointcuts: methods that are really enhanced are called pointcuts
- Notification (enhancement): the logical part of the actual enhancement, called notification, has five notification types
- Pre notification: executed before the enhanced method
- Post notification: executed after the enhanced method
- Surround notification: executed before and after the enhanced method
- Exception notification: the enhanced method executes after throwing an exception
- Final notice: final execution
- Aspect: the process of applying notifications to pointcuts is called aspect
-
Some preparations for using AOP
-
Spring frameworks generally implement AOP operations based on AspectJ
AspectJ is not a part of Spring. It is an independent AOP framework. Generally, AspectJ and Spring framework are used together for AOP operation
-
Implementation of AOP operation based on AspectJ
- Implementation of configuration file based on xml
- Annotation based implementation (use)
-
In addition to the related jar packages imported earlier, we also need to import AOP related dependencies
-
Pointcut expression
Writing method: execution([permission modifier], [return type], [class full path], [method name] ([parameter list]))
For example, enhance the add method under the com.yellowstar.dao.UserDao class
The return value type can be ignored and not written. The parameter list is replaced by
excution(* com.yellowstar.dao.UserDao.add(...))
-
-
AOP operations (annotation based implementation)
-
Create an enhanced class and a proxy class for an enhanced class
//Enhanced class public class User { //Enhanced method public void add(){ System.out.println("user add......"); } } //Enhanced proxy class public class UserProxy { public void before(){ System.out.println("before......"); } }
-
Configure the xml file and create two class objects using annotation
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--Scan annotation--> <context:component-scan base-package="com.yellowstar"></context:component-scan> </beans>
//Enhanced class @Component public class User { //Enhanced method public void add(){ System.out.println("user add......"); } } //Enhanced proxy class @Component public class UserProxy { public void before(){ System.out.println("before......"); } }
-
Add the @ Aspect annotation for the enhanced class and configure the generation proxy object in the xml file
//Enhanced proxy class @Component @Aspect public class UserProxy { public void before(){ System.out.println("before......"); } }
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
Before enhancing the notification method of the class, set the corresponding notification annotation and use the pointcut expression
//Enhanced proxy class @Component @Aspect public class UserProxy { //Before advice @Before(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void before() { System.out.println("before......"); } //Final notice @After(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void after() { System.out.println("after......"); } //Post notification @AfterReturning(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void afterReturning() { System.out.println("afterReturning......"); } //Exception notification @AfterThrowing(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing......"); } //Around Advice @Around(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void around(ProceedingJoinPoint point) throws Throwable { System.out.println("add before around......"); //The code on this statement is before the method is executed, and the following code is after the method is executed point.proceed(); System.out.println("add after around......"); } } Execution results: add before around...... before...... user add...... add after around...... after...... afterReturning......
The above AOP operations have been completed. There are two more details about the above operations that can be optimized
-
Extract the same pointcut
We find that the entry points of these notices are the same, so we can extract them
Create a method, configure the Pointcut annotation, configure the Pointcut expression, and call the method where the same Pointcut is required
//Enhanced proxy class @Component @Aspect public class UserProxy { @Pointcut(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void point(){} //Before advice @Before(value = "point()") public void before() { System.out.println("before......"); } }
-
There are multiple enhancement methods. How to set the order of execution
Use the annotation order (numeric value). The smaller the value, the higher the priority
//Enhanced agent class 1 @Component @Aspect @Order(3) public class UserProxy { @Pointcut(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void point(){} //Before advice @Before(value = "point()") public void before() { System.out.println("before......"); } } //Enhanced agent class 2 @Component @Aspect @Order(0) public class UserProxyMax { @Before(value = "execution(* com.yellowstar.spring5.AopAnnocation.User.add(..))") public void before(){ System.out.println("UserProxyMax before..."); } } //Set the order of the two enhanced proxy classes as above, and the enhanced method in UserProxyMax will be executed first
-
-
AOP operation (based on xml configuration file)
-
Create an enhanced class and an enhanced class
//Enhanced class public class Book { public void buy(){ System.out.println("book buy..."); } } //Enhancement class public class BookProxy { public void before(){ System.out.println("BookProxy before..."); } }
-
Configure the following in the xml file
<!--Create objects of two classes--> <bean id="book" class="com.yellowstar.spring5.AopXml.Book"></bean> <bean id="bookProxy" class="com.yellowstar.spring5.AopXml.BookProxy"></bean> <!--to configure AOP Enhancement point--> <aop:config> <!--Configure pointcuts--> <aop:pointcut id="p" expression="execution(* com.yellowstar.spring5.AopXml.Book.buy(..))"/> <!--Configure section--> <aop:aspect ref="bookProxy"> <!--Configuration method--> <aop:before method="before" pointcut-ref="p"></aop:before> </aop:aspect> </aop:config>