[Copyright notice] Without the consent of the blogger, declined to reprint! (please respect the original, blogger, maintain) blog.csdn.net/javazejian/… From zejian’s blog

Everything you need to know about Spring AOP (AspectJ)

This is the first blog post, years later by bloggers with a lot of time at this blog design, add a little busy recently, so this paper write longer, also got the different time periods in the writing, has the best ability to the contents of the coherent post, trying to present a simple text meaning, if there are mistakes please leave a message, thank you.

  • The new life of OOP
    • The eve of OOP’s new life
    • The god-like aspectJ-AOP frontrunner
    • AspectJ weaving and its principles
  • Based on Aspect Spring AOP development
    • Quick introduction to simple cases
    • Back to Spring AOP terminology
  • Annotation-based Spring AOP development
    • Defining pointcut functions
    • Pointcut indicator
      • The wildcard
      • Type signature expression
      • Method signature expression
      • Other indicators
    • Notifying functions and passing parameters
      • Five notification functions
      • Notification transfer parameter
    • The Aspect priority
    • Xml-based development
    • Spring AOP simple application scenarios
  • The implementation principles of Spring AOP are outlined
    • JDK dynamic proxy
    • CGLIB dynamic proxy

The new life of OOP

The eve of OOP’s new life

OOP is object-oriented program design, talked about OOP, we have to know about the POP process oriented programming, it was based on the function of the center for thinking and organization of a programming mode, emphasizes the system of data processing and processing process, namely pay attention to the implementation of functional, achieved good, while the OOP pay attention to packaging, Emphasizing the concept of wholeness, centering on the object, distinguishing the internal organization of the object from the external environment. I saw a good explanation earlier, and the blogger drew it as a picture like this:

Here we are compared the program design for the layout of the house, a house layout, need to all sorts of function of furniture and sanitary ware (similar to method), such as toilet, bathtub, gas stove, bed, table, etc., to pay more attention to process oriented programming is a function of the implementation of the (i.e., the realization of the function method), it is good effect in line with expectations, Therefore, process-oriented programming would prefer to set up the structure in Figure 1, and the various functions would be implemented and the house would be habitable. But for the object-oriented program design is unbearable, in such a setting give house puts scattered between all kinds of furniture and sanitary ware and greatly increase the risk of exposure, each all kinds of smells mixed each other, obviously is very bad, so in order to set the layout of the building to the more elegant, object-oriented program design and use the position of the figure 2, For object-oriented programming such set advantage is obvious, every room in the house have their own names and the corresponding function (in the Java programming generally called the room like this class, each class represents a room of abstract body), such as toilet is size bath solution and dressing, is rest in the bedroom, the kitchen is cooking, Every small room do their job without time exposed to the world of internal structure, the whole room structure is clear, the only need to know the room and use the functions can be provided in the room (method invocation), at the same time also more conducive to later expanded, which room, after all, you need to add the function, its scope has a limit, This makes responsibilities clearer (the principle of single responsibility). The emergence of OOP to POP does exist a lot of disruptive, but does not say POP has no value, after all, is the product of different times, from methodology, prefer to process oriented and object oriented as the two aspects of things – local and whole (you have to notice the local and overall is relative), so in practice, Both methods are equally important. After understanding the characteristics of OOP and POP, we look at OOP applications in the Java programming process. In the Java programming process, we almost enjoy the benefits brought by OOP design ideas, so that in this world where everything is an object and everyone is equal, we are in a carnival. OOP, however, does adhere to its purpose of putting data and actions on it together as an interdependent, indivisible whole, which is nicely named: Object, using the definitions for the same type of object classification, abstract, it is concluded that common features, thus formed the class, the class is a class in Java program design, because the class (object), the basic concept of the existence of the real world affairs (such as in front of different small room) so much closer to people’s understanding of objective things, At the same time, the data and method (algorithm) encapsulated in a class (object), which is more conducive to data security, under normal circumstances, attributes and algorithms only belong to a separate class, so that the program design is simpler, but also easier to maintain. Based on this theory, in the actual software development, the whole software system is actually composed of a series of interdependent objects, and these objects are also abstracted classes. I believe you have some experience in the actual development (this document assumes that readers have object-oriented development ideas including encapsulation, inheritance, polymorphic knowledge). But as the software grows and applications upgrade, OOP slowly begins to show some problems. There is no need to know about them now. Through the cases, we slowly feel:

public class A {
    public void executeA() {// Other service operations are omitted......
        recordLog();
    }

    public void recordLog() {/ /... Record logs and report them to the log system}}Copy the code

Class B:

public class B {
    public void executeB() {// Other service operations are omitted......
        recordLog();
    }

    public void recordLog() {/ /... Record logs and report them to the log system}}Copy the code

Class C:

public class C {
    public void executeC() {// Other service operations are omitted......
        recordLog();
    }

    public void recordLog() {/ /... Record logs and report them to the log system}}Copy the code

Suppose there are three classes A, B, and C, and they need to log their method access, and there are various recordLog methods in the code to log and report. It is probably impossible for engineers today to write such bad code, but OOP writing is allowed. And there was a lot of this code at the beginning of OOP, and it wasn’t until engineers were digging around for the recordLog that they decided to fix it. In order to solve the problem of too much redundant code between programs, engineers started using the following code

/ / A class
public class A {
    public void executeA() {// Other service operations are omitted...... The args parameter, usually passing the class name, method name, or information (such information is not easily changed)
        Report.recordLog(args ...);
    }
}

/ / class B
public class B {
    public void executeB() {// Other service operations are omitted......
        Report.recordLog(args ...);
    }
}

/ / C
public class C {
    public void executeC() {// Other service operations are omitted......
        Report.recordLog(args ...);
    }
}

//record
public class Report {
    public static void recordLog(args ...) {/ /... Record logs and report them to the log system}}Copy the code

After this operation, we are glad to find that the problem seems to be solved. When the internal method of reporting information needs to be adjusted, we only need to adjust the recordLog method body in the Report class, which avoids the problem of digging graves everywhere and greatly reduces the complexity of software maintenance in the later stage. This is true, and in addition to the above solution, there is another way to solve this problem by inheritance. In this way, you simply put the code that is communicated into a class (usually a parent of another class), and the other classes (subclasses) obtain the code that is communicated by inheriting the parent, as follows:

// Generic parent class
public class Dparent {
    public void commond() {// Common code}}/ / A Dparent inheritance
public class A extends Dparent {
    public void executeA() {// Other service operations are omitted......commond(); }}/ / B Dparent inheritance
public class B extends Dparent{
    public void executeB() {// Other service operations are omitted......commond(); }}/ / C Dparent inheritance
public class C extends Dparent{
    public void executeC() {// Other service operations are omitted......commond(); }}Copy the code

Obviously, code redundancy has also been resolved, and this method of extracting common code through inheritance is also known as vertical scaling, as opposed to horizontal scaling (don’t be too quick to understand now, it will be everywhere in the analysis that follows). In fact, with these two solutions, the problem of code redundancy in most business scenarios is actually solved, as shown in the following figure

However, as the software development system becomes more and more complex, engineers realize that traditional OOP programs often exhibit some unnatural phenomena. The core business is always mixed with some unrelated special business, such as logging, permission verification, transaction control, performance detection, error message detection, etc. These special businesses can be said to have no fundamental relationship with the core business and the core business does not care about them. For example, in the user management module, the module itself only cares about the business information processing related to the user, and the other businesses can be completely ignored. Let’s look at a simple example to help understand this problem

/ * * * Created by zejian on 2017/2/15. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
public interface IUserService {

    void saveUser();

    void deleteUser();

    void findAllUser();
}
/ / implementation class
public class UserServiceImpl implements IUserService {

    // Core data member

    // Log operation object

    // Permission managed objects

    // Transaction control object

    @Override
    public void saveUser() {

        // Permission validation (assuming permission validation is dropped here)

        // Transaction control

        // Log operations

        // Perform Dao layer operations
        userDao.saveUser();

    }

    @Override
    public void deleteUser() {}@Override
    public void findAllUser() {}}Copy the code

We noticed that some problems in the code above, permissions, logging, transactions are not user management core business, which means the user management module in addition to deal with its core business, also need to deal with authority, logging, transaction wait for these assorted the outside of the relevant business operations, and the peripheral operation will also appear in other business modules, This leads to the following problems

  • Code clutter: The core business module may have to take care of other unrelated business peripheral operations that may clutter the code for the core operation and affect the core module when significant changes are made to the peripheral module, which is obviously unreasonable.

  • Code dispersion and redundancy: The same functional code can be seen almost everywhere in other modules, resulting in high code dispersion and redundancy.

  • Low code quality Difficult to expand: The core business code cannot be focused on because the irrelevant business code is mixed together. When similar unrelated business extension is carried out, the code of the core business will be directly involved, resulting in low extensibility.

Obviously, the two solutions analyzed above are no longer available, so what is the solution? In fact we know such as log, permissions, transactions, such as performance monitoring business covers almost all of the core module, if these special business code directly into the core business of the module code will cause the above problem, the engineers more hope these modules can realize the hotplug features without code invasion of peripheral to the core module, Such maintenance and extension in the future also will have a better performance, assuming that now we have logs, permissions, transaction, performance monitoring, and other peripheral business as a separate concern (can also be interpreted as a separate module), each focus can in time to need them is applied in time and need not integrated into the core module in advance, this form is below:

Can be seen from the figure, each separation of concerns and core business module as a separate function, crosscutting several core business modules, such doing is obvious, the benefits of each function code is no longer alone into the core business class code, namely the core modules focus on relevant business, when you need to peripheral business (log, permissions, Performance monitoring and transaction control), the peripheral business would automatically through a special technology is applied to the core module, these concerns have a special name, called “crosscutting concerns,” above is also very good showing this concept, the level of abstraction technology also called AOP (aspect oriented programming), as is shown above, crosscutting core modules of the whole face, So the concept of AOP emerged, and the so-called special technology is also oriented to the implementation of faceted programming technology, AOP implementation technology has a variety of, with Java seamless docking is a technology called AspectJ. So how does this aspect technology (AspectJ) apply to Java? There is no need to worry or understand AspectJ completely, and this post will not do so. We will cover AspectJ in a very brief way that will provide a good foundation for understanding AOP in Spring. (Spring AOP and AspectJ are not exactly implemented in principle, but are functionally similar. This will be discussed later), after all, AOP’s main functionality is already implemented in Spring, so we can simply use the AOP functionality provided in Spring for development, unless we want to use AspectJ’s other capabilities alone. It is also important to note that the advent of AOP does solve the problem of separating peripheral business code from core business code, but it does not replace OOP. Whereas OOP is about modularizing coding problems, AOP is about unifying the management of a class of problems involving many modules. So it’s no surprise that AOP and OOP exist together in real development, as we’ll see later. Ok, can’t wait, let’s start learning about AspectJ like the Gods.

The god-like aspectJ-AOP frontrunner

I’ll start with a simple case study, then introduce some of the arcane abstractions of AOP, and rest assured that this blog will make it very easy to understand and master them. Write a HelloWord class and then use AspectJ technology to dive into the execution of that class.

/ * * * Created by zejian on 2017/2/15. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
public class HelloWord {

    public void sayHello(){
        System.out.println("hello world !");
    }
    public static void main(String args[]){
        HelloWord helloWord =newHelloWord(); helloWord.sayHello(); }}Copy the code

Write an AspectJ class. Note that the keyword is aspect(myAspectjdemo. aj, where aj is the suffix for AspectJ), meaning the same as class, that is, defining an AspectJ class

/ * * * Created by zejian on 2017/2/15. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * * / cut class
public aspect MyAspectJDemo {
    /** * defines the pointcut, logging pointcut */pointcut recordLog():call(* HelloWord.sayHello(..) );/** * Define pointcuts, permissions validation (in real development, logs and permissions are usually placed in different sections, just for demonstration purposes) */pointcut authCheck():call(* HelloWord.sayHello(..) );/** * define pre-notification! * /
    before():authCheck(){
        System.out.println("Verify permission before sayHello method executes");
    }

    /** * defines the post-notification */
    after():recordLog(){
        System.out.println("Log sayHello method after execution"); }}Copy the code

Ok ~, run the helloWorld main function:

Don’t be too surprised by the results, they are completely predictable. AspectJ is responsible for the authentication and logging of sayHello before and after the main function is run. Now that you have an emotional understanding of aspectJ, what is aspectJ? AspectJ is a Java implementation of an AOP framework that enables AOP compilation of Java code (typically at compile time) and gives Java code AspectJ’s AOP capabilities (requiring a special compiler, of course). AspectJ is arguably the most mature AOP framework currently implemented. The most featured-rich language, and fortunately, AspectJ is fully compatible with Java programs and is almost seamless, making it easy for engineers with Java programming roots to get started and use. In our case, we use the aspect keyword to define a class that is an aspect, which can be a separate logging aspect (feature), a permission aspect, or something else. Within the aspect, we use the Pointcut to define two pointcuts, one for permission validation and one for logging. The so-called tangent point is the need to use of the method of cross section, such as authentication is carried out on the sayHello method before and after the execution and logging, you will need to capture, the method and the pointcut method is to define the need to capture the (often more than one method), these methods are also known as the target method, finally also defines two notification, Notifications are functions that need to be executed before and after the target method, such as before(), which means pre-notifications are executed before the target method, which means permission validation is performed before sayHello(), and after(), which means post-notifications are executed after sayHello(), such as logging. From this point, it can be determined that a section is a combination of pointcuts and notifications, forming a single structure for subsequent use.

The keyword is pointcut, the pointcut is defined, followed by the function name, and the matching expression is written. Call () or execution() is used to match the pointcut.

The pointcut function name: match expression

Example: recordLog() is the function name, custom, * denotes any return value, followed by the target function to intercept, sayHello(..) The.. Represents any parameter type. Use pointcut to define a recordLog pointcut function that intercepts the sayHello method of the HelloWord class with any parameters.

 pointcut recordLog():call(* HelloWord.sayHello(..) );Copy the code

There are five types of notification:

  • Before The target method is executed before it is notified
  • After The target method is executed after execution, followed by notification
  • Executed when the After RETURNING target method returns, with post-return notification
  • The After Throwing target method performs exception notification when it throws an exception
  • Around is executed in the execution of the object function, controlling whether the object function is executed or not, and surrounding the notification

Grammar:

[returning value type] Returning function name (parameter)

In the following example, note that the around advice is the surround advice, and you can control whether the object function executes with the proceed() method.

/** * defines the pre-notification ** before(argument): join point function {* body *} */
 before():authCheck(){
     System.out.println("Verify permission before sayHello method executes");
 }

 /** * defines a post-notification * after(argument): join point function {* body *} */
 after():recordLog(){
     System.out.println("Log sayHello method after execution");
 }


 /** * defines a return value * after(parameter)returning(return value type): join point function {* function body *} */
 after()returning(int x): get(){
     System.out.println("Return value :"+x);
 }

 /** * exception notification * after(argument) throwing(return value type): join point function {* function body *} */
 after() throwing(Exception e):sayHello2(){
     System.out.println("Throw exception :"+e.toString());
 }



 /** * The surround notification controls whether the Object function executes the * Object around(argument) with proceed() : join point function {* body * Object result=proceed(); // Execute target function * return result; *} * /
 Object around():aroundAdvice(){
     System.out.println("Execute before sayAround executes");
     Object result=proceed();// Execute the target function
     System.out.println("SayAround executes after execution");
     return result;
 }Copy the code

Pointcut and advice are fairly well defined, while sections define combinations of pointcuts and advice such as MyAspectJDemo defined above using the aspect keyword. The process of applying cuts to target functions is called weaving. In addition to the sayHello function, there is a main function in the HelloWord class defined above, and there may be other functions defined in the future, and these functions can be called the target function, that is, these functions can also be executed before and after the notification code, these target functions are collectively called join points. It is from these join points that the definition of pointcuts is filtered, as illustrated below.

AspectJ weaving and its principles

After a brief introduction to AspectJ, we have grasped some of its syntax and concepts, but this is not enough. We still need to understand the process by which AspectJ is applied to Java code (a process called weaving). It can be simply understood as the process of applying an aspect(aspect) to an objective function (class). For the process, generally divided into dynamic and the static and weave weave, dynamic weaving way is dynamically at run time will enhance the code weave to the target class, this is often done through dynamic agent technology, such as Java JDK dynamic proxies (Proxy, the underlying by reflection) or additional dynamic Proxy (the underlying through inheritance), Spring AOP uses proxy based on runtime enhancement, which will be discussed later, with a focus on static weaving, which ApectJ uses. ApectJ mainly uses compile-time weaving, in which AspectJ’s ACJ compiler (similar to JavAC) is used to compile aspect classes into class bytecode and then at Java target class compilation time, that is, compile the aspect classes first and then the target classes.

The AJC compiler is a compiler that recognizes aspect syntax. It is written in the Java language. Since Javac does not recognize aspect syntax, there is an AJC compiler. Note that ajC compilers also compile Java files. To get a better idea of how aspects are woven, open the helloWord.class file that was compiled in the previous example and decompile the Java code as follows:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.zejian.demo;

import com.zejian.demo.MyAspectJDemo;
// Compile the HelloWord bytecode decompiled class into the aspect class
public class HelloWord {
    public HelloWord() {}public void sayHello() {
        System.out.println("hello world !");
    }

    public static void main(String[] args) {
        HelloWord helloWord = new HelloWord();
        HelloWord var10000 = helloWord;

   try {
        //MyAspectJDemo section class pre-notification weaving
        MyAspectJDemo.aspectOf().ajc$before$com_zejian_demo_MyAspectJDemo$1$22c5541();
        // Call the target class function
           var10000.sayHello();
        } catch (Throwable var3) {
        MyAspectJDemo.aspectOf().ajc$after$com_zejian_demo_MyAspectJDemo$2$4d789574();
            throw var3;
        }

        //MyAspectJDemo post-notification weaving for the section class
        MyAspectJDemo.aspectOf().ajc$after$com_zejian_demo_MyAspectJDemo$2$4d789574(); }}Copy the code

The principle of AspectJ weaving is pretty clear. In addition to compile-time weaving, there is also link-time (post-compile) weaving, which means that aspect classes and Java object classes are compiled into bytecode files at the same time and then woven into them. This method is more convenient for weaving into third-party JARS and Class files that have already been compiled. Since this is not the focus of this article, without further analysis, a knowledge of AspectJ above is sufficient to help you understand Spring AOP. Some students may want to write their own aspect program for testing practice, the blogger in this simple introduction to the construction of the running environment, first of all, the blogger uses the IDEA IDE, so only idea is introduced (Eclipse, ha ha). First download the toolkit AspectJTools-1.8.9.jar from the Maven repository, which contains the AJC core compiler, and then open IDEA to check if the aspectJ plug-in is installed:

The configuration project uses the AJC compiler (instead of javAC) as shown below:

If you’re developing using Maven (or importing jars in the libs directory yourself), add aspectJ’s core dependencies to the POM file, which contains the core library files for the aspectJ runtime:

<dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.5.4</version>
</dependency>Copy the code

Create the aspectJ file at the new file, and then you can manipulate the aspect file just as you would a Java file.

Ok, that’s all for AspectJ.

Based on Aspect Spring AOP development

Spring AOP has the same goal as ApectJ in addressing crosscutting business uniformly, but unlike AspectJ, Spring AOP does not attempt to provide full AOP functionality (even if it is fully implementable), Spring AOP is more focused on integrating with the Spring IOC container and combining this advantage to solve crosscutting business problems, so AspectJ has a greater advantage in terms of AOP functionality. At the same time,Spring has noticed that AspectJ relies on a special compiler (ajC compiler) for the way AOP is implemented, so Spring wisely sidesteps this and turns to the implementation principles of dynamic proxy technology to build Spring AOP’s internal mechanisms (dynamic weaving). This is the most fundamental difference from AspectJ (static weaving). The development of the annotation style in the @aspect form was introduced after AspectJ 1.5, and Spring followed this approach very quickly, so Spring 2.0 uses the same annotations as AspectJ. Note that Spring only uses the same annotations as AspectJ 5, but it still doesn’t use AspectJ’s compiler. The underlying implementation is dynamic proxy technology, so it doesn’t rely on AspectJ’s compiler. Let’s start with a simple example to demonstrate the basics of Spring AOP

Quick introduction to simple cases

Define the target class interface and implementation class

/ * * * Created by zejian on 2017/2/19. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
 / / interface
public interface UserDao {

    int addUser();

    void updateUser();

    void deleteUser();

    void findUser();
}

/ / implementation class
import com.zejian.spring.springAop.dao.UserDao;
import org.springframework.stereotype.Repository;

/ * * * Created by zejian on 2017/2/19. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
@Repository
public class UserDaoImp implements UserDao {
    @Override
    public int addUser() {
        System.out.println("add user ......");
        return 6666;
    }

    @Override
    public void updateUser() {
        System.out.println("update user ......");
    }

    @Override
    public void deleteUser() {
        System.out.println("delete user ......");
    }

    @Override
    public void findUser() {
        System.out.println("find user ......"); }}Copy the code

Writing Spring AOP’s aspect classes using annotations introduced in Spring 2.0:

@Aspect
public class MyAspect {

    /** ** */
    @Before("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
    public void before(){
        System.out.println("Pre-notification....");
    }

    /** * post-notification * returnVal, the return value of the pointcut method */
    @AfterReturning(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )",returning = "returnVal")
    public void AfterReturning(Object returnVal){
        System.out.println("Post notification...."+returnVal);
    }


    /** * surround notification * @paramJoinPoint can be used to perform a pointcut class * @return
     * @throws Throwable
     */
    @Around("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Surround notification before....");
        Object obj= (Object) joinPoint.proceed();
        System.out.println("Surround notification after....");
        return obj;
    }

    /** * throws notification * @param e
     */
    @AfterThrowing(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )",throwing = "e")
    public void afterThrowable(Throwable e){
        System.out.println("Error: MSG ="+e.getMessage());
    }

    /** * the method that will be executed no matter what */
    @After(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
    public void after(){
        System.out.println("Final notice...."); }}Copy the code

Write configuration files to be managed by the Spring IOC container

<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"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <! Enable automatic proxy support for @AspectJ -->
    <aop:aspectj-autoproxy />

    <! -- Define target object -->
    <bean id="userDaos" class="com.zejian.spring.springAop.dao.daoimp.UserDaoImp" />
    <! -- Define aspect class -->
    <bean name="myAspectJ" class="com.zejian.spring.springAop.AspectJ.MyAspect"/>
</beans>Copy the code

Writing test classes

/ * * * Created by zejian on 2017/2/19. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= "classpath:spring/spring-aspectj.xml")
public class UserDaoAspectJ {
    @Autowired
    UserDao userDao;

    @Test
    public void aspectJTest(){ userDao.addUser(); }}Copy the code

To clarify, a target class UserDaoImpl is defined. The aspect class MyAspect is defined using the aspect annotation development feature introduced in Spring2.0. In this aspect class, five annotation notification functions are written. They are @before, @afterreturning, @around, @afterthrowing, and @After. These five types of notification are almost the same as those in AspectJ. The value attribute can be omitted if there is only one execution parameter, and the value attribute must be specified if there is a return value if there is more than one execution parameter. In addition to passing pointcut expressions directly to the notification annotation type, you can also define pointcut matching expressions using @pointcut, which is the same as AspectJ using the keyword pointcut, as discussed below. After the target and aspect classes are defined, they are finally configured in an XML configuration file. The creation of all the same classes is handled by the SpringIOC container. Note that when using Spring AOP’s aspectJ functionality, you need to start the aspect’s annotation support with the following code:

<aop:aspectj-autoproxy />Copy the code

Ok ~, run the program, the result is as expected:

Back to Spring AOP terminology

From a simple case study, it is also easy to see that The implementation of Spring AOP follows the AOP specification, especially with AspectJ (seamless integration with Java) as a reference, and therefore the terminology of AOP is conceptually the same as that of AspectJ in the previous analysis. For example, pointcuts define object functions that need to be applied to, and advice is the body of the function that needs to be applied to, while aspects are the combination of advice and pointcuts. Weaving is the process of applying aspect classes to target functions (classes) that Spring AOP underlies through dynamic proxy techniques.

Annotation-based Spring AOP development

Defining pointcut functions

In the case where the filter pointcut function is defined, the execution defined match expression is passed directly as a value to the notification type as follows:

@After(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
  public void after(){
      System.out.println("Final notice....");
  }Copy the code

In addition to the above, pointcut expressions can be defined in a manner similar to the way the pointcut keyword is used in ApectJ, using the @pointcut annotation:

/** * use Pointcut to define pointcuts */
@Pointcut("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
private void myPointcut() {}/** * apply the pointcut function */
@After(value="myPointcut()")
public void afterDemo(){
    System.out.println("Final notice....");
}Copy the code

MyPointcut () is the function name that passes the Pointcut expression when afterDemo() is applied.

Pointcut indicator

To apply method notification to the target method of the corresponding filtering, SpringAOP provides matching expressions, also known as pointcut indicators, which have appeared several times in the previous cases.

The wildcard

When defining matching expressions, wildcards are almost everywhere, such as *,.. +, their meanings are as follows:

  • . Matches any number of parameters in the method definition, in addition to any number of packages in the class definition

    // Public method with any return value, any name, and any argument
    execution(public* * (..) ) // Matches all methods in all classes in the com.zejian.dao package and its subpackageswithin(com.zejian.dao.. *)Copy the code
  • + : matches any subclass of the given class

    // match methods that implement all subclasses of the DaoUser interface
    within(com.zejian.dao.DaoUser+)Copy the code
  • * : Matches any number of characters

    // Matches all methods of all classes in the com.zejian.service package and its subpackageswithin(com.zejian.service.. *)// Matches methods that start with set and take an int and return any value
    execution(* set*(int))Copy the code

Type signature expression

To facilitate type (interface, class name, package name) filtering methods, Spring AOP provides the within keyword. The syntax is as follows:

within(<type name>)Copy the code

Replace type name with package name or class name.

// Matches all methods in all classes in the com.zejian.dao package and its subpackages
@Pointcut("within(com.zejian.dao.. *)")

// Matches all methods in the UserDaoImpl class
@Pointcut("within(com.zejian.dao.UserDaoImpl)")

// Matches all methods in the UserDaoImpl class and its subclasses
@Pointcut("within(com.zejian.dao.UserDaoImpl+)")

// Match all methods of all classes that implement the UserDao interface
@Pointcut("within(com.zejian.dao.UserDao+)")Copy the code

Method signature expression

If you want to filter by method signature, the keyword execution can help you with this syntax

//scope: method scope, such as public,private,protect
//returnt-type: indicates the return value type of the method
//fully qualified-class-name: the fully qualified name of the class in which the method resides
//parameters method parameters
execution(<scope> <return-type> <fully-qualified-class-name>.*(parameters))Copy the code

For a given scope, return value type, fully qualified class name, and parameter matching method, the advice specified by the pointcut function will be applied. Here is a model example:

// Matches all methods in the UserDaoImpl class
@Pointcut("execution(* com.zejian.dao.UserDaoImpl.*(..) )")

// Matches all common methods in the UserDaoImpl class
@Pointcut("execution(public * com.zejian.dao.UserDaoImpl.*(..) )")

// Matches all public methods in the UserDaoImpl class and returns an int value
@Pointcut("execution(public int com.zejian.dao.UserDaoImpl.*(..) )")

// Matches all public methods in the UserDaoImpl class whose first argument is int
@Pointcut("execution(public * com.zejian.dao.UserDaoImpl.*(int , ..) )")Copy the code

Other indicators

  • Beans: Spring AOP extended, AspectJ has no execution methods for designators that match bean objects with specific names;

    // Matches beans with the suffix Service in their names.
    @Pointcut("bean(*Service)")
    private void myPointcut1() {}Copy the code
  • This: Execution method used to match the current AOP proxy object type; Note that there is a type match for the AOP proxy object, which may include importing interfaces as well as type matches

    // Match methods of any proxy object implementing the UserDao interface
    @Pointcut("this(com.zejian.spring.springAop.dao.UserDao)")
    private void myPointcut2() {}Copy the code
  • Target: the execution method used to match the current target object type;

    // Matches any method of the target object that implements the UserDao interface
    @Pointcut("target(com.zejian.spring.springAop.dao.UserDao)")
    private void myPointcut3() {}Copy the code
  • @within: matches all methods held within the specified annotation type; Note that it differs from within, which matches method execution within a specified type;

    // Match classes that use the MarkerAnnotation annotation.
    @Pointcut("@within(com.zejian.spring.annotation.MarkerAnnotation)")
    private void myPointcut4() {}Copy the code
  • @ the annotation (com zejian. Spring. MarkerMethodAnnotation) : according to the annotation by application of method of filtration

    // match methods that use the MarkerAnnotation annotation.
    @Pointcut("@annotation(com.zejian.spring.annotation.MarkerAnnotation)")
    private void myPointcut5() {}Copy the code

Ok ~, about the expression indicator is introduced here, we mainly care about the first few commonly used just, not commonly used impression can be. Here finally clear, tangent point indicator can use operator syntax expression of mix, such as and, or, not (or &&, | |,!) Here is a simple example:

// Matches any method that implements the target object of the UserDao interface and that interface is not under the com.zejian.dao package and its subpackages
@Pointcut("The target (com. Zejian. Spring. SpringAop. Dao. UserDao)! within(com.zejian.dao.. *)")
private void myPointcut6() {}// Matches any method that implements the target object of the UserDao interface and is named addUser
@Pointcut("target(com.zejian.spring.springAop.dao.UserDao)&&execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
private void myPointcut7() {}Copy the code

Notifying functions and passing parameters

Five notification functions

You’ve seen advice in the previous introduction to aspectJ and Spring AOP. In Spring, as in aspectJ, there are five main types of advice: pre-notification, post-notification, exception notification, final notification, and wrap notification, which are described below.

  • Pre-notification @before

    This notification is executed Before the object function is executed. Note that JoinPoint is a static variable provided by Spring. Using the JoinPoint parameter, you can obtain information about the target object, such as the class name, method parameter, method name, etc. This parameter is optional.

/** ** @paramJoinPoint This parameter can obtain information about the target object, such as class name, method parameter, method name, etc. */
@Before("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )")
public void before(JoinPoint joinPoint){
    System.out.println("This is pre-notification.");
}Copy the code
  • AfterReturning is annotated by the @AfterRETURNING annotation. This function is executed after the target function has completed and returns the final value of the target function, returnVal. If the target function does not return a value, returnVal will return NULL. Parameter names must be specified by RETURNING = “returnVal” and must be the same as those of the notification function. Please note that these parameters are optional in any notification and can be filled in if needed or not. The following
/** * after notification, you can not provide */ when no parameter is required
@AfterReturning(value="execution(* com.zejian.spring.springAop.dao.UserDao.*User(..) )")
public void AfterReturning(){
   System.out.println("I'm postnotification...");
}Copy the code
/** * post-notification * returnVal, the return value of the pointcut method */
@AfterReturning(value="execution(* com.zejian.spring.springAop.dao.UserDao.*User(..) )",returning = "returnVal")
public void AfterReturning(JoinPoint joinPoint,Object returnVal){
   System.out.println("I'm a post notification... returnVal+"+returnVal);
}Copy the code
  • Exception notification @afterThrowing

This notification is only raised when an exception is thrown and is declared by Throwing a variable that receives exception information. The same exception notification is also used for the Joinpoint parameter, which is added as needed:

/** * throws notification * @paramE Throws an exception */
@AfterThrowing(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..) )",throwing = "e")
public void afterThrowable(Throwable e){
  System.out.println("Error: MSG ="+e.getMessage());
}
Copy the code
  • Final notification @after

This notification is a bit like a finally code block, and will be executed no matter what if it is applied.

/** * Method that will be executed in any case * joinPoint argument */
@After("execution(* com.zejian.spring.springAop.dao.UserDao.*User(..) )")
public void after(JoinPoint joinPoint) {
    System.out.println("Final notice....");
}Copy the code
  • Surrounding the notification @ Around surrounding the notification can be performed in front of the target method can also be performed after the target method, more important is Around to inform whether can control the target method to perform, but even so, we should try to meet the requirements in the most simple way, before only in the target method executes, surrounded by prior notification should be used instead of notice. The case code, such as the first argument, must be ProceedingJoinPoint, executes the target function via the object’s proceed() method, whose return value is the return value of the surrounding advice. Similarly, the ProceedingJoinPoint object can retrieve information about the target object, such as class name, method parameters, method name, and so on.
@Around("execution(* com.zejian.spring.springAop.dao.UserDao.*User(..) )")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("I am surround notification before....");
    // Execute the target function
    Object obj= (Object) joinPoint.proceed();
    System.out.println("I am surround notification post....");
    return obj;
}Copy the code

Notification transfer parameter

In Spring AOP, with the exception of execution and bean designators that cannot pass parameters to a notification method, all designators can automatically pass matching method parameters or objects to the notification method. The argNames attribute is used to specify the matching method parameters. Note that the names of the args(indicator) and argNames arguments must be the same as those in the before() method (param).

@Before(value="args(param)", argNames="param") // Explicitly specified
public void before(int param) {    
    System.out.println("param:" + param);    
}  Copy the code

It is also possible to declare arguments directly using the args indicator without argNames as follows:

@Before("execution(public * com.zejian.. *.addUser(..) ) && args(userId,..) ")  
public void before(int userId) {  
    // The method of addUser is passed in if it matches the arguments of addUser
    System.out.println("userId:" + userId);  
}  Copy the code

args(userId,..) This expression ensures that only methods that receive at least one argument of the same type as the userId must be matched. Remember that the argument passed can be a simple type or object, and that values will only be passed in if the argument and target method also match. To a

The Aspect priority

In different aspects, if there are multiple notifications need to filter the target method specified in the same tangent point function to perform, those who perform in front of the target method (” to “) the notification function, the highest priority notification will perform first, the executed after the target method (” exit “) notification function, the highest priority will be the last. Notification functions defined on the same plane are executed in the order they are declared in the class. As follows:

package com.zejian.spring.springAop.AspectJ;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/ * * * Created by zejian on 2017/2/20. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
@Aspect
public class AspectOne {

    /** * Pointcut defines the Pointcut function */
    @Pointcut("execution(* com.zejian.spring.springAop.dao.UserDao.deleteUser(..) )")
    private void myPointcut() {}@Before("myPointcut()")
    public void beforeOne(){
        System.out.println("Pre-notification.... Execution sequence 1");
    }

    @Before("myPointcut()")
    public void beforeTwo(){
        System.out.println("Pre-notification.... Execution sequence 2");
    }

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningThree(){
        System.out.println("Post notification.... Execution sequence 3");
    }

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningFour(){
        System.out.println("Post notification.... Execution sequence 4"); }}Copy the code

To define multiple notification responses to the same pointcut function in the same aspect, execute in declarative order:

If define multiple notification response in different aspects of the same point of tangency, enter, inform the function of the cut surface of the high priority class priority, exits, and finally executed, the following definitions AspectOne classes and class AspectTwo and implement org. Springframework. Core. Ordered interface, This interface is used to control the priority of the aspect class and override getOrder to customize the return value. The smaller the return value (int type), the higher the priority. The return value of AspectOne is 0 and that of AspectTwo is 3, indicating that AspectOne has a higher priority than AspectTwo.

/ * * * Created by zejian on 2017/2/20. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
@Aspect
public class AspectOne implements Ordered {

    /** * Pointcut defines the Pointcut function */
    @Pointcut("execution(* com.zejian.spring.springAop.dao.UserDao.deleteUser(..) )")
    private void myPointcut() {}@Before("myPointcut()")
    public void beforeOne(){
        System.out.println("Pre-notification.. AspectOne.. Execution sequence 1");
    }

    @Before("myPointcut()")
    public void beforeTwo(){
        System.out.println("Pre-notification.. AspectOne.. Execution sequence 2");
    }

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningThree(){
        System.out.println("Post notification.. AspectOne.. Execution sequence 3");
    }

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningFour(){
        System.out.println("Post notification.. AspectOne.. Execution sequence 4");
    }

    /** * defines the priority, the lower the value, the higher the priority * @return* /
    @Override
    public int getOrder() {
        return 0; }}// The aspect class aspectTwo-java
@Aspect
public class AspectTwo implements Ordered {

    /** * Pointcut defines the Pointcut function */
    @Pointcut("execution(* com.zejian.spring.springAop.dao.UserDao.deleteUser(..) )")
    private void myPointcut() {}@Before("myPointcut()")
    public void beforeOne(){
        System.out.println("Pre-notification.... Execution order 1--AspectTwo");
    }

    @Before("myPointcut()")
    public void beforeTwo(){
        System.out.println("Pre-notification.... Execution order 2--AspectTwo");
    }

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningThree(){
        System.out.println("Post notification.... Execution order 3--AspectTwo");
    }

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningFour(){
        System.out.println("Post notification.... Execution order 4--AspectTwo");
    }

    /** * defines the priority, the lower the value, the higher the priority * @return* /
    @Override
    public int getOrder() {
        return 2; }}Copy the code

The running results are as follows:

Although only pre-notification and post-notification are demonstrated in this case, other notifications follow the same rules and you can test them yourself if you are interested. This is the end of annotation-based Spring AOP analysis, but note that after @aspect support is enabled in the configuration file, the Spring container will only attempt to automatically recognize beans with @aspect, provided that any defined Aspect classes have been declared as beans in the configuration file.

<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"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <! --<context:component-scan base-package=""-->
    <! Enable automatic proxy support for @AspectJ -->
    <aop:aspectj-autoproxy />

    <! -- Define target object -->
    <bean id="userDaos" class="com.zejian.spring.springAop.dao.daoimp.UserDaoImp" />
    <! -- Define aspect class -->
    <bean name="myAspectJ" class="com.zejian.spring.springAop.AspectJ.MyAspect"/>

    <bean name="aspectOne" class="com.zejian.spring.springAop.AspectJ.AspectOne"  />

    <bean name="aspectTwo" class="com.zejian.spring.springAop.AspectJ.AspectTwo" />
</beans>Copy the code

Xml-based development

Even though annotation-based development is the most common in everyday applications, it is important to take a look at Spring AOP development in XML form. Here we will briefly examine the form of XML development in the form of a case study, defining a facet class

/ * * * Created by zejian on 2017/2/20. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
public class MyAspectXML {

    public void before(){
        System.out.println("MyAspectXML==== Pre-notification");
    }

    public void afterReturn(Object returnVal){
        System.out.println("Postnotification --> return value :"+returnVal);
    }

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("MyAspectXML===== surround before notification");
        Object object= joinPoint.proceed();
        System.out.println("MyAspectXML===== after surround notification");
        return object;
    }

    public void afterThrowing(Throwable throwable){
        System.out.println("MyAspectXML====== Exception notification :"+ throwable.getMessage());
    }

    public void after(){
        System.out.println("MyAspectXML===== final notification.. To the"); }}Copy the code

The following is declared as a configuration file (spring-aspectj-xml.xml) :

<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"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <! --<context:component-scan base-package=""-->

    <! -- Define target object -->
    <bean name="productDao" class="com.zejian.spring.springAop.dao.daoimp.ProductDaoImpl" />

    <! -- Define the section -->
    <bean name="myAspectXML" class="com.zejian.spring.springAop.AspectJ.MyAspectXML" />
    <! Configure the AOP aspect -->
    <aop:config>
        <! Define pointcut function -->
        <aop:pointcut id="pointcut" expression="execution(* com.zejian.spring.springAop.dao.ProductDao.add(..) )" />

        <! Define other pointcut functions -->
        <aop:pointcut id="delPointcut" expression="execution(* com.zejian.spring.springAop.dao.ProductDao.delete(..) )" />

        <! Notification order specifies the priority, the smaller the value, the higher the priority.
        <aop:aspect ref="myAspectXML" order="0">
            <! Pointcut specifies the pointcut function in MyAspectXML -->
            <aop:before method="before" pointcut-ref="pointcut" />

            <! Definition return value must be the same as the name declared in the class -->
            <aop:after-returning method="afterReturn" pointcut-ref="pointcut"  returning="returnVal" />

            <! -- Surround notification -->
            <aop:around method="around" pointcut-ref="pointcut"  />

            <! -- Throwing ="throwable" -- Throwing ="throwable" -- Throwing ="throwable"
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="throwable"/>

            <! Pointcut-ref: pointcut method to which the notification is applied -->
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>Copy the code

Declaration and definition in the code has been very clear, understand it, in the actual development, will be more inclined to use annotations to develop, after all, simpler and more concise.

Spring AOP simple application scenarios

The following Spring AOP application cases will reinforce this familiarity by simulating two common development scenarios. Note that the code for these scenarios may not be perfect for all situations, but they do apply to real software development. While the code in the case will not be presented as a full project demonstration, it is more likely to mimic AOP application code, so let’s get started. Performance monitoring is essential for a mature system, and the following code snippet gives us a snapshot of the elapsed time of the program:

// Calculate the elapsed time
long start = System.currentTimeMillis();
// Other code operations
long time = System.currentTimeMillis() - start;Copy the code

The following code will simulate the performance of monitoring API interface access and record the name of each interface including class name, elapsed time, etc. Simply define a monitoring information logging class:

** * Created by Wuzejian on 2017/2/20. ** Created by Wuzejian on 2017/2/20
public class MonitorTime {

    private String className;
    private String methodName;
    private Date logTime;
    private long comsumeTime;
    / /... Other attributes

    // omit set and get

 }Copy the code

Define a monitoring aspect class:

** * Created by Wuzejian on 2017/2/20. ** * Created by Wuzejian on 2017/2/20. ** * Created by Wuzejian on 2017/2/20
@Aspect
public class TimerAspect {
    /** * defines the pointcut function to filter all methods */ of classes whose names end in controller
    @Pointcut("execution(* com.zejian.spring.controller.*Controller.*(..) )")
    void timer() {
    }

    @Around("timer()")
    public Object logTimer(ProceedingJoinPoint thisJoinPoint) throws Throwable {

        MonitorTime monitorTime=new MonitorTime();
        // Get the target class name
        String clazzName = thisJoinPoint.getTarget().getClass().getName();
        // Get the target class method name
        String methodName = thisJoinPoint.getSignature().getName();

        monitorTime.setClassName(clazzName);// Record the class name
        monitorTime.setMethodName(methodName);// Record the corresponding method name
        monitorTime.setLogTime(new Date());// Record the time

        // Time and call the target function
        long start = System.currentTimeMillis();
        Object result = thisJoinPoint.proceed();
        long time = System.currentTimeMillis() - start;

        // Set the elapsed time
        monitorTime.setComsumeTime(time);
        // Upload information recorded by monitorTime to the monitoring system
        //MonitoruUtils.report(monitorTime)

        returnresult; }}Copy the code

Then declare the slice in the XML file:

<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"
       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/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <! --<context:component-scan base-package=""-->
    <! Enable automatic proxy support for @AspectJ -->
    <aop:aspectj-autoproxy />

    <! -- Define target object -->
    <bean id="userController" class="com.zejian.spring.controller.UserController" />
    <! -- Define aspect class -->
    <bean name="timerAspect" class="com.zejian.spring.SpringAopAction.TimerAspect"/>
</beans>Copy the code

The time consumed by each interface is calculated each time the pointcut function defines the filtering method to be used as the performance indicator of the access interface. In addition to performance monitoring, there is probably even more important exception monitoring, and exception handling is inevitable in each module. To avoid writing try/catch scripts everywhere, it is a good idea to handle exceptions uniformly, and Spring AOP can obviously do the job. It is perfectly possible to use surround notification in the aspect class to handle the exception information uniformly and to encapsulate the exception information and report it to the backend logging system. The following code demonstrates this clever operation. Start by writing an exception wrapper class (simple simulation only) :

/** * Created by wuzejian on 2017/2/20. * Classes that encapsulate exception information */
public class ExceptionInfo {

    private String className;
    private String methodName;
    private Date logTime;// Record the time of the exception
    private String message;// Exception information
    / /... Other attributes
    // omit set get
    }Copy the code

The unified exception handling section class is as follows:

/** * Created by Wuzejian on 2017/2/20
@Aspect
public class ExceptionMonitor {

    /** * Define the exception monitoring class */
    @Pointcut("execution(com.zejian.spring *(..) )")
    void exceptionMethod() {
    }

    @Around("exceptionMethod()")
    public Object monitorMethods(ProceedingJoinPoint thisJoinPoint) {
        try {
            return thisJoinPoint.proceed();
        } catch (Throwable e) {
            ExceptionInfo info=new ExceptionInfo();
            // Exception class record
            info.setClassName(thisJoinPoint.getTarget().getClass().getName());
            info.setMethodName(thisJoinPoint.getSignature().getName());
            info.setLogTime(new Date());
            info.setMessage(e.toString());
            // Upload the log system
            //ExceptionReportUtils.report(info);
            return null; }}}Copy the code

As for the notification function body in ExceptionMonitor, here is only a simple demonstration of code implementation, which can be modified according to business requirements in actual development. The application of AOP is far more than these two kinds, such as caching, permission validation, content processing, transaction control and so on can be implemented using AOP, which provides special processing methods in Spring transaction control, limited to the space to talk about this first.

The implementation principles of Spring AOP are outlined

In the previous analysis, we talked about the implementation principle of Spring AOP is based on dynamic weaving dynamic proxy technology, and AspectJ is static weaving, and dynamic proxy technology is divided into Java JDK dynamic proxy and CGLIB dynamic proxy, the former is based on reflection technology implementation, the latter is based on inheritance mechanism implementation. The code implementation of these two technologies is examined with a simple example.

JDK dynamic proxy

For A simple example, declare A class A and implement the ExInterface interface, using JDK dynamic proxy technology to incorporate permission validation and logging before and after execute(). Note that this is just demo code and does not represent the actual application.

/ * * * Created by zejian on 2017/2/11. * Blog: http://blog.csdn.net/javazejian [the original address, please respect the original] * /
JDK dynamic proxy implementations must have a corresponding interface class
public interface ExInterface {
    void execute();
}

// Class A implements the ExInterface interface class
public class A implements ExInterface{
    public void execute(){
        System.out.println(Execute A's execute method...); }}// The implementation of the proxy class
public class JDKProxy implements InvocationHandler{

    /** * The target object to be proxied */
    private A target;

    public JDKProxy(A target){
        this.target=target;
    }

    /** * Create proxy class * @return* /
    public ExInterface createProxy() {return (ExInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /** * Invoking any method of the propped class (target object) triggers the invoke method * @paramProxy Indicates the proxy class * @paramMethod Method of the proxied class @paramArgs method argument * of the propped class @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Filtering does not require the business method
        if("execute".equals(method.getName())) {
            // Verify permissions before calling
            AuthCheck.authCheck();
            // Call the target object's method
            Object result = method.invoke(target, args);
            // Record log data
            Report.recordLog();
            return result;
        }eles if("delete".equals(method.getName())){
            / /...
        }
        // Execute the original method if no enhancement is required
        returnmethod.invoke(target,args); }}// Test validation
 public static void main(String args[]){
      A a=new A();
      // Create a JDK proxy
      JDKProxy jdkProxy=new JDKProxy(a);
      // Create a proxy object
      ExInterface proxy=jdkProxy.createProxy();
      // Execute the proxy object method
      proxy.execute();
  }Copy the code

Running results:

Execute method does not call any permission and log code, nor does it directly operate on A object. Instead, it just calls the method of proxy object, and the final result is expected. This is the dynamic proxy technology, is not familiar with Spring AOP? Actually the underlying dynamic proxy is through reflection technology to realize, as long as get A class A class files and the implementation of class A interface, naturally you can generate the same interface proxy class object and invokes A method, on the bottom reflection technology implementation, for the moment but much discussion, please note that implement the Java dynamic proxy is A prerequisite, This condition is that the target object must have an interface. For example, the interface of class A is ExInterface. Using the dynamic proxy technology of ExInterface interface, A proxy object of the same type as class A can be created.

 A a=new A();
 // Create a JDK proxy class
 JDKProxy jdkProxy=new JDKProxy(a);
 // Create a Proxy object. The Proxy object also implements ExInterface
 ExInterface proxy=jdkProxy.createProxy();
 // Execute the proxy object method
 proxy.execute();Copy the code

Proxy object creation is achieved through the Proxy class, provided by the Java JDK, using Proxy#newProxyInstance method to dynamically generate Proxy object (Proxy), the underlying implementation through reflection, this method takes three parameters

/ * * * @paramLoader A class loader that passes the target object (class A, the propped object) @paramInterfaces The implementation interface of the target object (A) * @paramThe h callback handles (as analyzed later) */
public static Object newProxyInstance(ClassLoader loader,Class<? >[] interfaces,InvocationHandler h)Copy the code

The code for creating proxy class proxy is as follows:

public ExInterface createProxy() {return (ExInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }Copy the code

The proxy class (JDKProxy in Demo) also needs to implement the InvocationHandler interface, also provided by the JDK. The invoke method that the proxy class must implement is overwritten. You can think of InvocationHandler as a Callback. After the Proxy method creates the Proxy object, When the execute method is called (the proxy object also implements ExInterface), the InvocationHandler#invoke method is called, so we can control method execution on the proxied object (the target object) within the invoke method, To dynamically add additional business before and after this method, the code in the Demo shows this nicely:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // Filtering does not require the business method
    if("execute".equals(method.getName())) {
        // Verify permissions before calling (dynamically add other business to be executed)
        AuthCheck.authCheck();

        // Call the target object's method (execute the proxied object's execute method)
        Object result = method.invoke(target, args);

        // Log data (dynamically add other services to be performed)
        Report.recordLog();

        return result;
    }eles if("delete".equals(method.getName())){
     / /...
     return method.invoke(target, args);
    }
    // Execute the original method if no enhancement is required
    return method.invoke(target,args);
}Copy the code

The invoke method takes three parameters:

  • Object Proxy: generated proxy Object
  • Method Method: The Method of the target object, called by reflection
  • Object[] args: parameter of the target Object method

This is Java JDK dynamic proxy code implementation process, summary, use JDK dynamic proxy, proxied class (target object, such as class A), must have implementation interface such as (ExInterface), Because the JDK provides A Proxy class that uses the target object’s ClassLoader and Interface, as well as its handle (Callback) to create A Proxy object with the same Interface as class A, this Proxy object will have all the methods in Interface ExInterface. At the same time, the proxy class must implement an InvocationHandler interface similar to a callback function and override the invoke method in this interface. The invoke method is invoked when each method of the proxy is called (such as proxy#execute() in the case). The Invoke method can dynamically add other peripheral business operations before and after the execution of A method on the target object (propped object such as A) without touching any code of the target object, thus fully decoupling the operation of the peripheral business from the target object (propped object such as A). Of course, the disadvantages were obvious: the need to have interfaces, which led to the CGLIB dynamic proxy

CGLIB dynamic proxy

The CGLIB dynamic proxy does not require the target object to have an interface class. In fact, the CGLIB dynamic proxy is implemented by inheritance, thus reducing the need for unnecessary interfaces. Github.com/cglib/cglib).

// Proxied class is the target object
public class A {
    public void execute(){
        System.out.println(Execute A's execute method...); }}/ / the proxy class
public class CGLibProxy implements MethodInterceptor {

    /** * Proxied target class */
    private A target;

    public CGLibProxy(A target) {
        super(a);this.target = target;
    }

    /** * Create proxy object * @return* /
    public A createProxy() {// Use CGLIB to generate proxy:
        // 1. Declare an enhanced class instance for the production proxy class
        Enhancer enhancer = new Enhancer();
        // 2. Set the bytecode of the propped class. CGLIB generates subclasses of the propped class based on the bytecode
        enhancer.setSuperclass(target.getClass());
        // Set the callback function, which is a method intercept
        enhancer.setCallback(this);
        // 4. Create proxy:
        return (A) enhancer.create();
    }

    /** * callback function * @paramProxy Proxy object * @paramMethod Delegate class method * @paramArgs method parameter * @paramMethodProxy Each propped method corresponds to a methodProxy object, and the * methodProxy.invokesuper method ends up calling the original method of the delegate class (target class) * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   // Filtering does not require the business method
      if("execute".equals(method.getName())) {
          // Verify permissions before calling (dynamically add other business to be executed)
          AuthCheck.authCheck();

          // Call the target object's method (execute the proxied object's execute method)
          Object result = methodProxy.invokeSuper(proxy, args);

          // Log data (dynamically add other services to be performed)
          Report.recordLog();

          return result;
      }else if("delete".equals(method.getName())){
          / /...
          return methodProxy.invokeSuper(proxy, args);
      }
      // Execute the original method if no enhancement is required
      returnmethodProxy.invokeSuper(proxy, args); }}Copy the code

The CGLibProxy class needs to implement a MethodInterceptor interface and rewrite the intercept method, which is similar to the JDK dynamic proxy InvocationHandler interface. Also understood as a callback function, the Intercept method is called every time a proxy object’s method is called, which allows dynamic enhancement of the method before and after execution at runtime. CGLib is A dynamic Proxy implemented by inheritance, so it needs to pass the Class of the target object (such as A). Create () creates A proxy object for the target object (such as A). The result is the same as the JDK dynamic proxy.

public A createProxy() {// 1. Declare an enhanced class instance for the production proxy class
    Enhancer enhancer = new Enhancer();
    // 2. Set the bytecode of the propped class. CGLIB generates subclasses of the propped class based on the bytecode
    enhancer.setSuperclass(target.getClass());
    // 3. Set the callback function, which is a method intercept
    enhancer.setCallback(this);
    // 4. Create proxy:
    return (A) enhancer.create();
  }Copy the code

That’s it for JDK proxy technology and CGLIB proxy technology. We should also understand that Spring AOP does use CGLIB or JDK proxies to dynamically generate proxy objects. The methods of AOP proxy classes enhance the target method by dynamically weaving enhancement processing into the target object’s pointcut. This is not a very in-depth analysis of these two technologies, preferring to show you the most simplified model code of the underlying implementation of Spring AOP. Spring AOP has implemented both technologies internally, and Spring AOP also adjusts the timing of use automatically. JDK dynamic proxy is automatically selected when an interface is available, and CGLIB is selected if not. Of course, the underlying implementation of Spring AOP is not so simple. To make proxy object generation easier, Spring AOP implements a factory class that focuses on proxy object generation, thus avoiding a lot of manual coding. This is also very human, but the core is dynamic proxy technology. In terms of performance, Spring AOP, while requiring no special compiler assistance, is no better than AspectJ’s static weaving. Finally, the principle model of Spring AOP simplification is given as follows, attached brief source code, 【GITHUB source code download 】

If you like my blog, after reading feel harvest is very big, might as well small sponsorship me, let me have the motivation to continue to write high-quality blog, thank you for your appreciation! Alipay, wechat