Spring AOP function usage details


AOP is both familiar and unfamiliar. Anyone who has known Spring knows the concept of AOP, that is, aspect oriented programming, which can be used to manage some peripheral businesses unrelated to the main business, such as logging, transaction management, etc; It is strange because it has not been used in work, and the related concepts of AOP are also in the clouds; I've been looking at the relevant source code of Spring recently, so let's first look at a usage of AOP in Spring.

Related concepts

Before learning the usage of Spring AOP, let's take a look at the related concepts of AOP,

For a detailed introduction to Spring AOP, please refer to the official website https://docs.spring.io/spring/docs/2.5.x/reference/aop.html

  1. Join point  : A connection point represents a point during program execution. In spring, AOP represents a method, that is, a method can be regarded as a join point

  2. pointcut  : The pointcut is the predicate that matches the join point. What does it mean? The join point that needs to execute Advice is the pointcut

  3. Advice  : Enhancement: the operations performed at the connection point can be divided into five types: pre, post, exception, final and surround enhancement

  4. Aspect  : Facet, which is composed of pointcut and Advice, can be simply regarded as the class annotated by @ aspect

  5. Target object  : Target object, that is, the target object woven into advice

  6. AOP proxy  : Proxy class. In Spring AOP, an AOP proxy is a JDK dynamic proxy object or CGLIB proxy object

  7. `Weaving`  : Weave in and apply Aspect to the target object

Note: among the above concepts, Join point is easy to be confused   And   pointcut, it can be understood that in Spring AOP, all executable methods are join points, and all join points can be embedded with Advice; pointcut can be regarded as a kind of descriptive information. It modifies the Join point to confirm which join points to execute Advice on,


After understanding the concept of AOP, let's take a look at how to use it   Spring Aop

  1. To use Spring   For AOP, first configure the following tags in the Spring configuration file:

1<aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true"/>

The tag has two properties,   expose-proxy   and   proxy-target-class  , The default values are   false;

expose-proxy  : Do you want to use the current proxy object   ThreadLocal   What does it mean to save? For example, Aop needs to intercept all methods under an interface, but some methods call themselves internally, as shown below:

1    public void test_1()
2    {   
3        this.test_2();
4    }
5    public void test_2()
6    {
7    }

Call test_1. Test at this time_ 2 will not be intercepted for enhancement because the AOP proxy object is called instead of the current object, but in test_1 method uses this internally, so test_2 will not be intercepted and enhanced, so the attribute expose proxy   It is used to solve this problem, that is, the acquisition of AOP agent.

proxy-target-class  : Whether to use CGLIB for proxy, because the underlying technology of Spring AOP uses dynamic proxy, which is divided into JDK proxy and CGLIB proxy. The default value of this attribute is false, which means that the underlying AOP uses JDK proxy by default. CGLIB will be used for proxy only when the class to be proxy does not implement any interface. If you want to use CGLIB for proxy, You can set this property to true.

  1. Define the method to be intercepted by aop, and simulate the addition, deletion and modification of a User:


1public interface IUserService {
2    void add(User user);
3    User query(String name);
4    List<User> qyertAll();
5    void delete(String name);
6    void update(User user);

Interface implementation:

 2public class UserServiceImpl implements IUserService {
 4    @Override
 5    public void add(User user) {
 6        System.out.println("User added successfully, user=" + user);
 7    }
 9    @Override
10    public User query(String name) {
11        System.out.println("according to name Query user succeeded");
12        User user = new User(name, 20, 1, 1000, "java");
13        return user;
14    }
16    @Override
17    public List<User> qyertAll() {
18        List<User> users = new ArrayList<>(2);
19        users.add(new User("zhangsan", 20, 1, 1000, "java"));
20        users.add(new User("lisi", 25, 0, 2000, "Python"));
21        System.out.println("Query all users succeeded, users = " + users);
22        return users;
23    }
25    @Override
26    public void delete(String name) {
27        System.out.println("according to name User deleted successfully, name = " + name);
28    }
30    @Override
31    public void update(User user) {
32        System.out.println("User updated successfully, user = " + user);
33    }


  1. Define AOP section

In Spring AOP, use  @ Aspect    The class identified by the annotation is a facet, and then the pointcut and advice are defined in the facet:

3.1 pre enhancement, @ Before(), is executed before the target method is executed

 3public class UserAspectj {
 5    //  Execute before method execution
 6    @Before("execution(* main.tsmyk.mybeans.inf.IUserService.add(..))")
 7    public void before_1(){
 8        System.out.println("log: stay add Method....");
 9    }

The above method is before_1() is a pre enhancement of the add() method of the interface, that is, it is executed before the add() method is executed,

 3public class TestBean {
 5    @Autowired
 6    private IUserService userServiceImpl;
 8    @Test
 9    public void testAdd() {
10        User user = new User("zhangsan", 20, 1, 1000, "java");
11        userServiceImpl.add(user);
12    }
14//  result:
15//  log:   stay   add   Method
16//  Successfully added user, user=User{name='zhangsan ',   age=20,   sex=1,   money=1000.0,   job='java'}

If you want to get the parameters of the target method, we can add parameters to the tangent method   JoinPoint  , Through it, you can obtain the relevant information of the target object:

1    @Before("execution(* main.tsmyk.mybeans.inf.IUserService.add(..))")
2    public void before_2(JoinPoint joinPoint){
3        Object[] args = joinPoint.getArgs();
4        User user = null;
5        if(args[0].getClass() == User.class){
6            user = (User) args[0];
7        }
8        System.out.println("log: stay add Method, Method parameters = " + user);
9    }

Re execute the above test code and the results are as follows:

1log: stay add Method, Method parameters = User{name='zhangsan', age=20, sex=1, money=1000.0, job='java'}
2 User added successfully, user=User{name='zhangsan', age=20, sex=1, money=1000.0, job='java'}

3.2 post enhancement, @ After() is executed after the target method is executed. It will be executed whether it is normal exit or exception throwing

1    //  Execute after method execution
2    @After("execution(* main.tsmyk.mybeans.inf.IUserService.add(..))")
3    public void after_1(){
4        System.out.println("log: stay add Method....");
5    }

Execute the test code of 3.1, and the results are as follows:

1 User added successfully, user=User{name='zhangsan', age=20, sex=1, money=1000.0, job='java'}
2log: ==== After method execution =====

3.3 return enhancement, @ AfterReturning(), is executed after the target method returns normally. If there is an exception, it will not be executed. You can get the return value:

1@AfterReturning(pointcut="execution(* main.tsmyk.mybeans.inf.IUserService.query(..))", returning="object")
2public void after_return(Object object){
3    System.out.println("stay query Method is executed after it returns, Return value= " + object);


2public void testQuery() {
3    userServiceImpl.query("zhangsan");
5//  result:
6//  Query user by name succeeded
7//  stay   query   Method is executed after it returns,   Return value=   User{name='zhangsan',   age=20,   sex=1,   money=1000.0,   job='java'}

When a method is enhanced by both @ After() and @ AfterReturning(), which one should be executed first?

1@AfterReturning(pointcut="execution(* main.tsmyk.mybeans.inf.IUserService.query(..))", returning="object")
2public void after_return(Object object){
3    System.out.println("===log: stay query Method is executed after it returns, Return value= " + object);
6@After("execution(* main.tsmyk.mybeans.inf.IUserService.query(..))")
7public void after_2(){
8    System.out.println("===log: stay query Method....");


1 according to name Query user succeeded
2===log: stay query Method....
3===log: stay query Method is executed after it returns, Return value= User{name='zhangsan', age=20, sex=1, money=1000.0, job='java'}

As you can see, even if @ After() is placed in  @ After AfterReturning(), it is also executed first, that is, @ After() is executed before @ AfterReturning().

3.4 exception enhancement, @ AfterThrowing, is executed when an exception is thrown. If an exception is not thrown, it is not executed.

1@AfterThrowing(pointcut="execution(* main.tsmyk.mybeans.inf.IUserService.query(..))", throwing = "ex")
2public void after_throw(Exception ex){
3    System.out.println("stay query Method is executed when an exception is thrown, abnormal= " + ex);

Now modify its enhanced query() method to throw an exception:

2public User query(String name) {
3    System.out.println("according to name Query user succeeded");
4    User user = new User(name, 20, 1, 1000, "java");
5    int a = 1/0;
6    return user;


2public void testQuery() {
3    userServiceImpl.query("zhangsan");
5//  result:
6//  stay   query   When the method throws an exception,   Abnormal=   java.lang.ArithmeticException:  /  by   zero
7// java.lang.ArithmeticException: / by zero ...........

3.5 surround enhancement, @ Around, before and after the target method is executed

1@Around("execution(* main.tsmyk.mybeans.inf.IUserService.delete(..))")
2public void test_around(ProceedingJoinPoint joinPoint) throws Throwable {
3    Object[] args = joinPoint.getArgs();
4    System.out.println("log : delete Before method execution, parameter = " + args[0].toString());
5    joinPoint.proceed();
6    System.out.println("log : delete After method execution");


2public void test5(){
3    userServiceImpl.delete("zhangsan");
6//  result:
7//  log  :  delete   Before the method is executed,   parameter  =  zhangsan
8//  The user is successfully deleted according to name,   name  =  zhangsan
9//  log  :  delete   After method execution

The above are several enhancements of Spring AOP.

In the chestnuts above, the tangent expression above each method needs to be written once, and can now be used  @ Pointcut   To declare a reusable pointcut expression, and then reference the pointcut expression above each method:

 1//  statement   pointcut
 2@Pointcut("execution(* main.tsmyk.mybeans.inf.IUserService.query(..))")
 3public void pointcut(){
 7public void before_3(){
 8    System.out.println("log: stay query Method");
11public void after_4(){
12    System.out.println("log: stay query Method....");


In the chestnuts above, the   execution   Indicator, which is used to match the connection point of method execution. It is also the main indicator used by Spring AOP. Wildcard () is used in pointcut expression   And   (..), where(  ) It can represent any method, any return value, (..) represents any parameter of the method. Next, let's look at other indicators.

1. within

Match all joinpoints (Methods) of all classes under a specific package, including sub packages. Note that all classes, not interfaces, will not take effect if interfaces are written, such as   within(main.tsmyk.mybeans.impl.*   Will match   main.tsmyk.mybeans.impl   All of the classes under the package   Join point;within(main.tsmyk.mybeans.impl..*   The two points will match all of the classes under the package and its sub packages   Join point.

2public void testWithin(){
6public void test_within(){
7    System.out.println("test within Execute before method execution.....");

Execute the delete method of class UserServiceImpl under the package. The results are as follows:

2public void test5(){
3    userServiceImpl.delete("zhangsan");
6//  result:
7//  test   within   Execute before method execution
8//  The user is successfully deleted according to name,   name  =  zhangsan

2. @within

Matches all methods that hold the specified annotation type, such as  @ within(Secure), any class method in which the target object holds a Secure annotation; the annotation must be declared on the target object, and the annotation declared on the interface has no effect on it.

3. target

The matching object is a target object, and the target(main.tsmyk.mybeans.inf.IUserService) matches all objects under the interface   Join point  :

 2public void anyMethod(){
 6public void beforeAnyMethod(){
 7    System.out.println("log: ==== Before method execution =====");
11public void afterAnyMethod(){
12    System.out.println("log: ==== After method execution =====");

After that, any method under the interface will be enhanced.

4. @target

Match a target object, which must have specific annotations, such as  @ target(org.springframework.transaction.annotation.Transactional)   Match any  @ Transactional   Annotation method

5. this

this(service.IPointcutService) is the execution method matching the current AOP proxy object type. The current AOP object implements   Any method of the IPointcutService interface

6. arg

Matching parameters,

 1    //  Match has only one parameter   name   Method of
 2    @Before("execution(* main.tsmyk.mybeans.inf.IUserService.query(String)) && args(name)")
 3    public void test_arg(){
 5    }
 7    //  The first matching parameter is   name   Method of
 8    @Before("execution(* main.tsmyk.mybeans.inf.IUserService.query(String)) && args(name, ..)")
 9    public void test_arg2(){
11    }
13    //  Matching the second parameter is   name   Method of
14    @Before("execution(* main.tsmyk.mybeans.inf.IUserService.query(String)) && args(*, name, ..)")
15    public void test_arg3(){
17    }

7. @arg

Match parameters. Parameters have specific annotations, @ args(Anno)), and method parameters are marked with Anno annotations.

8. @annotation

Match specific annotation
@annotation(org.springframework.transaction.annotation.Transactional)   Match any with  @ Transactional   Annotation method.

9. bean

Method that matches a specific bean name

 1    //  matching   bean   The name of the is   userServiceImpl   All methods of
 2    @Before("bean(userServiceImpl)")
 3    public void test_bean(){
 4        System.out.println("===================");
 5    }
 7    //  matching   bean   Name with   ServiceImpl   All methods at the end
 8    @Before("bean(*ServiceImpl)")
 9    public void test_bean2(){
10        System.out.println("+++++++++++++++++++");
11    }

Execute the methods under the bean:

2public void test5(){
3    userServiceImpl.delete("zhangsan");
6// ===================
7// +++++++++++++++++++
8//  The user is successfully deleted according to name,   name  =  zhangsan

The above is how to use all indicators of Spring AOP.

Spring AOP principle

The underlying layer of Spring AOP uses dynamic proxy. There are two ways to implement dynamic proxy: one is the dynamic proxy of JDK and the other is the dynamic proxy of CGLIB. The following two ways are used to implement the above functions, that is, when calling UserServiceImpl class methods, add logs before and after method execution.

JDK dynamic agent

To implement JDK dynamic proxy, you must implement   InvocationHandler   Interface, and override   invoke   method:

 1public class UserServiceInvocationHandler implements InvocationHandler {
 3    //  Target object of proxy
 4    private Object target;
 6    public UserServiceInvocationHandler(Object target) {
 7        this.target = target;
 8    }
10    @Override
11    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
13        System.out.println("log: Before the target method is executed, parameter = " + args);
15        //  Execution target method
16        Object retVal = method.invoke(target, args);
18        System.out.println("log: After the target method is executed.....");
20        return retVal;
21    }


 1public static void main(String[] args) throws IOException {
 3    //  Objects requiring proxy
 4    IUserService userService = new UserServiceImpl();
 5    InvocationHandler handler = new UserServiceInvocationHandler(userService);
 6    ClassLoader classLoader = userService.getClass().getClassLoader();
 7    Class[] interfaces = userService.getClass().getInterfaces();
 9    //  Proxy object
10    IUserService proxyUserService = (IUserService) Proxy.newProxyInstance(classLoader, interfaces, handler);
12    System.out.println("Type of dynamic proxy  = " + proxyUserService.getClass().getName());
13    proxyUserService.query("zhangsan");
15    //  Write bytecode to file
16    byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy", new Class[]{UserServiceImpl.class});
17    FileOutputStream fos =new FileOutputStream(new File("D:/$Proxy.class"));
18    fos.write(bytes);
19    fos.flush();


1 Type of dynamic proxy  = com.sun.proxy.$Proxy0
2log: Before the target method is executed, parameter = [Ljava.lang.Object;@2ff4acd0
3 according to name Query user succeeded
4log: After the target method is executed.....

You can see that the log has been printed before and after the execution of the target method. Just in the main method above, we wrote the bytecode of the proxy object to the file. Now let's analyze:

Decompile the & proxy.class file as follows:

You can see that it is implemented through the implementation interface.

JDK can only proxy classes that implement interfaces. If a class does not implement interfaces, it cannot create proxies for these classes. At this time, CGLIB can be used for proxy.

CGLIB dynamic proxy

Next, let's look at how CGLIB is implemented.

First, create a new class that needs proxy. It does not implement any interface:

1public class UserServiceImplCglib{
2    public User query(String name) {
3        System.out.println("according to name Query user succeeded, name = " + name);
4        User user = new User(name, 20, 1, 1000, "java");
5        return user;
6    }

Now you need to use CGLIB to add logs before and after the execution of method query:

Using CGLIB to implement dynamic proxy also needs to implement interface   MethodInterceptor, override   intercept   method:

 1public class CglibMethodInterceptor implements MethodInterceptor {
 3    @Override
 4    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
 6        System.out.println("log: Before the target method is executed, parameter = " + args);
 8        Object retVal = methodProxy.invokeSuper(obj, args);
10        System.out.println("log: After the target method is executed, Return value = " + retVal);
11        return retVal;
12    }


 1public static void main(String[] args) {
 3    //  Write proxy class to file
 4    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\");
 6    Enhancer enhancer = new Enhancer();
 7    enhancer.setSuperclass(UserServiceImplCglib.class);
 8    enhancer.setCallback(new CglibMethodInterceptor());
10    //  Create proxy object
11    UserServiceImplCglib userService = (UserServiceImplCglib) enhancer.create();
12    System.out.println("Type of dynamic proxy = " + userService.getClass().getName());
14    userService.query("zhangsan");


1 Type of dynamic proxy = main.tsmyk.mybeans.impl.UserServiceImplCglib$$EnhancerByCGLIB$$772edd85
2log: Before the target method is executed, parameter = [Ljava.lang.Object;@77556fd
3 according to name Query user succeeded, name = zhangsan
4log: After the target method is executed, Return value = User{name='zhangsan', age=20, sex=1, money=1000.0, job='java'}

You can see that the result is the same as that of using JDK dynamic proxy. In addition, you can see that the type of proxy class is   main.tsmyk.mybeans.impl.UserServiceImplCglib$$EnhancerByCGLIB$2edd85, which is a subclass of UserServiceImplCglib, that is, CGLIB is implemented through inheritance.


  1. JDK's dynamic proxy is implemented through the mechanism of reflection and interceptor. It will generate a proxy class for the proxy interface.

  2. The dynamic proxy of CGLIB is implemented by inheritance. The class file of the proxy class is loaded in and processed by modifying its bytecode to generate subclasses.

  3. JDK dynamic proxy can only generate proxy for classes that implement interfaces, not for classes.

  4. CGLIB implements proxy for classes. It mainly generates a subclass of the specified class and overrides the methods in it. However, because inheritance is adopted, final classes or methods cannot be proxy.

  5. In Spring AOP, if the interface is implemented, JDK proxy is used by default, or CGLIB proxy can be forced. If the class to be proxy does not implement any interface, CGLIB proxy will be used, and Spring will switch automatically.

The above chestnuts for implementing Spring AOP are implemented by annotation. In addition, the functions of AOP can also be realized through configuration files. The above is a detailed use process of Spring AOP.

Tags: Java Spring Back-end source code

Posted on Thu, 21 Oct 2021 03:27:50 -0400 by McChicken