AOP in the Spring Core Series (part 2)

In this article, WE will share with you how Spring can implement AOP based on XML. In this article, we will share with you how Spring can implement AOP based on XML. Article structure:

  1. Spring AOP-XML configuration
  2. Aspect priority
  3. Spring AOP application scenarios
  4. Spring AOP’s underlying implementation choice

1. Spring AOP-XML configuration

Here’s a quick look at XML development in the form of a case, defining a facet class MyAspectXML:

public class MyAspectXML {
    
    public void before(a){
        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(a){
        System.out.println("MyAspectXML===== final notification.. To the"); }}Copy the code

Note that this class is not annotated. Then take a look at our XML file:

<! Add the section to the Spring container
    <bean name="myAspectXML" class="com.zdy.MyAspectXML" />
    <! Configure the AOP aspect -->
    <aop:config>
        <! Define the pointcut -->
        <aop:pointcut id="pointcut" expression="execution(...) " />

        <! Define other pointcut functions -->
        <aop:pointcut id="otherPointcut" expression="execution(...) " />

        <! 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="otherPointcut"/>
        </aop:aspect>
    </aop:config>
Copy the code

As you can see, the < AOP: Aspect > tag actually corresponds to the MyAspectXML class, which is then assembled with various enhancements (suggestions). In fact, if you were familiar with the form of annotations in the previous article, you could see that XML annotations are nothing more than putting various elements together in XML. The effect is the same. XML configurations are rarely used at work and are generally annotations. So you read to understand the next OK. It’s also relatively simple. Then give the XMl configuration of the portal, take a look at:

  • Spring AOP Xml configuration

2. Aspect priority

First, the design-to-priority issue assumes that the enhanced Pointcuts intersect. There are two types of Aspect priorities. One is when multiple enhancements are defined in an Aspect. The other is multiple enhancements in different aspects. I’ll start with the conclusion, and then I’ll give you two examples for different situations.

  • The @Before enhancement in front of the target method is executed first with a higher priority. Enhancements @after, @afterRETURNING that follow the target method will be implemented later if they are higher in priority.
  • Multiple enhancements are defined in an Aspect. It depends on the order in which the definition is defined.
  • Multiple enhancements in different aspects. According to the Aspect implementation Ordered interface, the method getOrder returns a value that is relevant; the lower the return value, the higher the priority.

2.1 Define multiple enhancements in an Aspect

@Aspect
public class AspectOne {

    /** * Pointcut defines the Pointcut function */
    @Pointcut("execution(...) ")
    private void myPointcut(a){}

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

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

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

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

Print result:

Pre-notification.... 1. Notify.... After execution sequence 2,.... is notified Perform the following operations in sequence 4:.... Execution Sequence 3Copy the code

2.2 Multiple enhancements in different aspects

@Aspect
public class AspectOne implements Ordered {

    /** * Pointcut defines the Pointcut function */
    @Pointcut("execution(...) ")
    private void myPointcut(a){}

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

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

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

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningFour(a){
        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(a) {
        return 0; }}// The aspect class aspectTwo-java
@Aspect
public class AspectTwo implements Ordered {

    /** * Pointcut defines the Pointcut function */
    @Pointcut("execution(...) ")
    private void myPointcut(a){}

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

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

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

    @AfterReturning(value = "myPointcut()")
    public void AfterReturningFour(a){
        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(a) {
        return 1; }}Copy the code

Output result:

Pre-notification.. AspectOne.. Execution Sequence 1 Pre-notification.. AspectOne.. Perform operations in sequence 2. Notify.... Execute order 1--AspectTwo pre-notification.... Execute order 2--AspectTwo postnotification.... Execute order 4--AspectTwo postnotification.... Execution order 3--AspectTwo post-notification.. AspectOne.. Execution sequence 4 Post notification.. AspectOne.. Execution Sequence 3Copy the code

Now that we’ve shared AspectJ priorities, let’s look at two more examples that should make sense. But to be honest, I used it less. (^_^)

3. Practical application scenarios of Spring AOP

In fact, there are many practical application scenarios of Spring AOP. Among other things, Spring’s own transaction management actually uses AOP. Here I will come to a relatively close case for developers, performance monitoring. In terms of performance monitoring, it’s not that fancy. It’s just counting the time of a Web interface call. Then play log or write to other monitoring platform (Granafa, etc.).

Define an entity class to store some monitoring information:

public class MonitorData {
    / / the name of the class
    private String className;
    / / the method name
    private String methodName;
    // Consume time
    private String consumeTime;
    // Record the time
    private Date logTime;
    
    //gettter setter toString what to omit. }Copy the code
@Aspect
@Component
public class MonitorAspectJ {

    /** * defines the pointcut function to filter all methods */ of classes whose names end in controller
    @Pointcut("execution(* com.. *Controller.*(..) )")
    void timer(a) {}@Around("timer()")
    public Object logTimer(ProceedingJoinPoint thisJoinPoint) throws Throwable {

        MonitorData monitorData=new MonitorData();
        // Get the target class name
        String clazzName = thisJoinPoint.getTarget().getClass().getName();
        // Get the target class method name
        String methodName = thisJoinPoint.getSignature().getName();
        
        
        // Record the class name
        monitorData.setClassName(clazzName);
        // Record the corresponding method name
        monitorData.setMethodName(methodName);
        // Record the time
        monitorData.setLogTime(new Date());

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

        // Set the elapsed time
        monitorData.setConsumeTime(time.toString());
        // Upload information recorded by monitorTime to the monitoring system
        //MonitoruUtils.report(monitorTime)
        System.out.println(monitorData.toString());
        returnresult; }}Copy the code

In fact, it’s a little easier to understand, but it’s just a matter of enclosing all the methods of all the classes that end in Controller to keep track of the time. And then save it (I printed it out here).

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.

4. Choice of Spring AOP low-level implementation

The underlying implementation of Spring AOP has two options: JDK dynamic proxy and CGLib dynamic proxy. To conclude, JDK dynamic proxies are used by default if the target to be proxy has an interface. If not, the CGLib dynamic proxy is used. You can also specify the use of CGLib dynamic proxies. Methods:

  • < AOP: config proxy-target-class=”true”>
  • < AOP: aspectj-autoproxy proxy-target-class=”true”/>

If the object you want to proide does not implement any interface, you must use the CGLIb proxy. If so, you can use JDK proxy and CGLIb proxy. Later there is an opportunity to write a special dynamic proxy to expand to say. For the singleton classes we commonly use in Web projects, try to implement Spring AOP using CGLib dynamic proxies.

CGlib has the following characteristics: bytecode technology, slow startup, index each method, high efficiency. JDK dynamic proxies are quick to start, each method is called by reflection, inefficient, and methods have no indexes.

conclusion

Well, Spring AOP has been shared with you. Unfortunately, the underlying JDK dynamic proxy and CGLib dynamic proxy are not covered. But it doesn’t matter, later have time must be dedicated to a dynamic proxy article, through the two articles of Spring AOP, I hope we can at least grasp the idea of AOP in the use level, and can apply to work. Spring, as well as Spring Boot, actually uses Spring AOP in many places, which will be pointed out in future articles if it is covered. Over ,Have a good day .