Java is object-oriented design language, object-oriented inheritance features are vertical extension, and AOP (Object Oriented Programming, object-oriented Programming) can be considered as horizontal extension, Spring’s AOP capabilities also align well with the OCP principles of the “SOLID” principles (open for extension, closed for modification).

Project creation and basic dependencies refer to the IOC container use, refer to: Spring use tutorial (a) : IOC container use

Pom depends on

Using Spring’s AOP, you need to add the following dependencies to the IOC container’s dependencies:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring_version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>${spring_version}</version>
</dependency>
Copy the code

applicationContext.xml

Applicationcontext.xml needs to be configured as follows:


      
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
	   default-autowire="byName">

<! -- proxy-target-class Defaults to false, indicating that the weaving mode is dynamic proxy based on interface. True indicates that the weaving mode is based on CGLib-->
<! Of course, if the enhanced class does not implement the interface, Spring will automatically use the CGLib dynamic proxy.
	<aop:aspectj-autoproxy proxy-target-class="true"/>
	<context:component-scan base-package="org.example"/>
</beans>

Copy the code

CGLib is a dynamic proxy technology based on bytecode enhancement technology

The basic concept

There are two important concepts in AOP: aspects and pointcuts.

A facet, or system concern, is a function that spans multiple core logic

In layman’s terms, an aspect is a class that defines enhancements and uses pointcuts to declare the objects those enhancements apply to.

Pointcuts, which define where to insert the execution of the aspect in the application process

A pointcut can be defined as an “execution expression” or “annotation.” Execution is the use of a regular expression to define the scope of an enhanced method in an aspect, such as execution(* org.example.*DAO. The org.example expression defines that all methods of all XxxDAO classes will be enhanced under the org.example package.

It may seem like a one-size-fits-all solution, but because of that, it can be very damaging. For example, when the maintainer of a project changes, the later student may not know about such configuration, or he may not want his newly added DAO to be proxy, which may bring some unexpected effects.

Therefore, I will only show you how to use AOP in conjunction with annotations, which is a highly aware approach (like Spring’s explicit use of Transactionnal annotations for methods that require transactions, rather than adding transactions to all methods by default) that does not cause the above problems.

Annotation AOP practice

Suppose you now need to add a new aspect that counts the execution time of a method.

Annotations Metric

To do this, we define a monitoring Metric as follows:

package org.example.aop.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Metric {
    String methodName(a);
}
Copy the code

The Target annotation states that the Metric annotation is valid for the method, and the Retention annotation states that the Metric annotation is valid at runtime.

Where the methodName attribute requires that the annotation be used, you need to tell it the methodName.

Cut class MetricAspect

Define the section class MetricAspect as follows:

package org.example.aop.aspects;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.example.aop.annotations.Metric;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MetricAspect {

    The value attribute in the Before annotation represents the pointcut */
    @Before(value = "@annotation(metric)")
    public void metricBefore(Metric metric) {
        System.out.printf("method:[%s] begin metric ! %n", metric.methodName());
    }

    /** * The value attribute in the Around annotation represents the pointcut */
    @Around(value = "@annotation(metric)")
    public Object metricAround(ProceedingJoinPoint joinPoint, Metric metric) throws Throwable {
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed();
        } finally {
            long spend = System.currentTimeMillis() - start;
            String msg = String.format("method:[%s], spendTime:[%s]ms", metric.methodName(), spend);
            System.out.println(msg);
            // Can be output to the monitoring log}}}Copy the code

Note that the Aspect class also needs to be injected into the IOC container, so MetricAspect has the Component annotation declaration, in addition to using the Aspect annotation declaration that this is a Aspect class.

The Before annotation states that the pointcut for the method enhancement is Before the method is executed, and its value indicates that the pointcut for the enhancement is the method with the Metric annotation declaration.

The Around annotation states that the method’s enhanced access timing includes before and after, and that the enhanced method’s execution time is controlled by joinPoint.proceed(). So the metricAround method logic is to record the system time before the method is executed, and count the method execution time after the method is executed and print it out.

Target object Calculator

Define a class Calculator as follows:

package org.example.pojo;

import org.example.aop.annotations.Metric;
import org.springframework.stereotype.Component;

import java.util.Random;

@Component("calculator")
public class Calculator {
    @Metric(methodName = "Calculator.add")
    public int add(int a, int b) throws InterruptedException {
        // The simulation method takes time
        Thread.sleep(new Random().nextInt(3000));
        returna + b; }}Copy the code

Calculator provides an Add method that provides the ability to calculate the sum of two numbers. The Add method has a Metric annotation declaration indicating that it needs to monitor the calculation time.

The main method tests AOP

Create Application class as follows:

package org.example.start;

import org.example.pojo.Calculator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {
    
    public static void main(String[] args) throws InterruptedException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        Calculator calculator = (Calculator) applicationContext.getBean("calculator");
        calculator.add(5.5); }}Copy the code

The ApplicationContext is used to start the IOC container load context, as described earlier in the use of the IOC container.

Execute main as follows:

method:[Calculator.add] begin metric !
method:[Calculator.add], spendTime:[451]ms
Copy the code

The first line is cut class MetricAspect. MetricBefore method, the effect of the second line is MetricAspect metricAround method the effect.

Junit testing and jar testing are similar to the IOC container usage section, which is not covered here.

conclusion

  • The use of AOP in Spring requires the addition of POM dependencies and the turning on of AOP in the XML configuration file.
  • Annotation AOP is recommended as an explicit and secure form of use.