This article takes you through the use of Spring AOP

The main content

The proxy pattern

The proxy pattern is a common design pattern in Java development. The design goal is to insert additional functionality between the service class and the client class that is transparent to the caller and acts as a masquerade of control. Examples of renting: tenant, agent, landlord. Corresponding to the proxy mode: customer class, agent class, delegate class (proxy class).

Provide a proxy (proxy class) for an object (delegate class) that controls access to that object. Delegate classes and proxy classes have a common parent class or parent interface. The proxy class preprocesses, filters, and assigns requests to specific objects.

Common agent situations in life:

Rental agencies, wedding companies, etc

Two design principles for the proxy pattern:

1. Proxy classes and delegate classes have similar behavior (common)

2. Proxy classes enhance the behavior of the delegate class

Common proxy modes:

1. Static proxy

2. Dynamic proxy

Static agent

An object provides a proxy with a fixed role to control access to the object. Proxy classes and delegate classes have a common parent class or parent interface, so proxy objects can be used wherever delegate objects are used. The proxy class is responsible for pre-processing, filtering, dispatching requests to the delegate class for processing, and subsequent processing after the delegate class executes the request.

The three elements of agency

A, have a common behavior (marriage) – interface

B. Target Role (newcomer) – Realization behavior

C, the role of agent (wedding company) – to enhance the behavior of the target object

Characteristics of static proxies

1. Fixed target roles

2. Get the target role before the application executes

Proxy objects enhance the behavior of target objects

4. It is possible to have multiple agents causing “quasi-explosions” (disadvantages)

Static proxy implementation

Define the behavior (collectively) define the interface

/** * defines the behavior */
public interface Marry {
    public void toMarry(a);
}
Copy the code

Target object (Implementation behavior)

/** * static proxy -- > target object */
public class You implements  Marry {
    // Implement the behavior
    @Override
    public void toMarry(a) {
        System.out.println("I'm getting married..."); }}Copy the code

Proxy objects (implement behavior, enhance behavior of target objects)

/** * static proxy -- > proxy object */
public class MarryCompanyProxy implements Marry {

    // Target object
    private Marry marry;
    // Pass the target object through the constructor
    public MarryCompanyProxy(Marry marry) {
        this.marry = marry;
    }

    // Implement the behavior
    @Override
    public void toMarry(a) {
        // Enhance behavior
        before();
                
        // Execute the method in the target object
        marry.toMarry();
        
        // Enhance behavior
        after();
    }

    /** * enhance behavior */
    private void after(a) {
        System.out.println("Happy wedding, early birth of your son!");
    }

    /** * enhance behavior */
    private void before(a) {
        System.out.println("The site is being arranged..."); }}Copy the code

Implement the function of the target object through the proxy object

// Target object
You you = new You();
// Construct the proxy role and pass in the real role
MarryCompanyProxy marryCompanyProxy = new MarryCompanyProxy(you);
// Call a method in the target object through the proxy object
marryCompanyProxy.toMarry();
Copy the code

Static proxy has a fixed role for proxy. For example, there are 20 DAO classes in the DAO layer. If you want to proxy the access rights of methods, you need to create 20 static proxy roles, which causes class explosion and cannot meet the needs of production.

A dynamic proxy

Dynamic proxies are more flexible in creating proxy objects than static proxies. The bytecodes of dynamic proxy classes are generated dynamically by Java reflection while the program is running. It dynamically creates proxy objects for the target object at the runtime of the program through reflection mechanism as needed, without the programmer writing its source code manually. Dynamic proxies not only simplify programming but also improve the scalability of software systems because reflection can generate any type of dynamic proxy class. The behavior of the agent can delegate multiple methods to meet production needs and achieve code generality.

Dynamic proxy can be implemented in two ways:

1. JDK dynamic proxy

2. CGLIB dynamic proxy

Dynamic proxy characteristics

1. The target object is not fixed. 2. Proxy objects enhance the behavior of target objectsCopy the code

JDK dynamic proxy

Note: The target object of the JDK dynamic proxy must have an interface implementation

newProxyInstance

The Proxy class:

The Proxy class is an action class that implements the Proxy. It can be used to dynamically generate implementation classes for one or more interfaces. This class provides the following actions:

/* Returns an instance method call of a proxy class with the specified interface dispatched to the specified call handler. Loader: A ClassLoader object that defines which ClassLoader objects load interfaces on the generated proxy objects: An array of Interface objects that represents the set of interfaces I am going to provide to the object I want to proide. If I provide an array of interfaces to the object I want to proide, then the proxy object claims to implement the Interface (polymorphic), so I can call the methods in the set of interfaces: An InvocationHandler interface that represents the interface implemented by the InvocationHandler of the proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method call is encoded and assigned to its invoke handler method (a subclass passed in to the InvocationHandler interface) */
public static Object newProxyInstance(ClassLoader loader, Class
       [] interfaces, InvocationHandler h)
Copy the code

Getting a proxy object

public class JdkHandler implements InvocationHandler {

    // Target object
    private Object target; // The type of the target object is not fixed and is generated dynamically when it is created
    // Assign the target object through the constructor
    public JdkHandler(Object target) {
        this.target = target;
    }

    /** * 1, call the target Object's method (return Object) * 2, enhance the target Object's behavior *@paramProxy The proxy instance that invokes the method *@paramMethod Method of the target object *@paramArgs Method parameter * of the target object@return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // Enhance behavior
        System.out.println("============== method before execution");

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

        // Enhance behavior
        System.out.println("Method executed after ==============");

        return result;
    }


    Public static Object newProxyInstance(ClassLoader, * Class<? >[] interfaces, * InvocationHandler h) * loader: interfaces: The InvocationHandler interface (the implementation class passed in to the InvocationHandler interface) * * *@return* /
    public Object getProxy(a) {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); }}Copy the code

Implement the function of the target object through the proxy object

// Target object
You you = new You();
// Get the proxy object
JdkHandler jdkHandler = new JdkHandler(you);
Marry marry = (Marry) jdkHandler.getProxy();
// Call a method in the target object through the proxy object
marry.toMarry();	
Copy the code
Q: How is invoke invoked in a Java dynamic proxy class? $Proxy0. Class (); $Proxy0. Class (); $Proxy0. Class (); The invoke() method of InvocationHandler, a member variable in the parent class, is invoked in the method body when the corresponding method is called.Copy the code

Note: JDK dynamic proxies rely on interface implementation. If some classes do not have an interface implementation, JDK proxies cannot be used.

CGLIB dynamic proxy

The dynamic proxy mechanism of the JDK can only be used to delegate classes that implement the interface, and classes that do not implement the interface cannot use the JDK dynamic proxy mechanism. The principle of cglib is to generate a subclass of the specified target class, and override the method implementation enhancement. Therefore, final modified classes cannot be propped up.

Add the dependent

Introduce cglib dependencies in the POM.xml file

<! -- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
Copy the code

Define the class

Implements the MethodInterceptor interface

public class CglibInterceptor implements MethodInterceptor {

    // Target object
    private Object target;
    // Pass the target object through the constructor
    public CglibInterceptor(Object target) {
        this.target = target;
    }

    /** * get the proxy object *@return* /
    public Object getProxy(a) {
        // The create() method of the Enhancer object generates a class for generating proxy objects
        Enhancer enhancer = new Enhancer();
        // Set the parent class (target class as its parent)
        enhancer.setSuperclass(target.getClass());
        // Sets the interceptor callback object to its own object
        enhancer.setCallback(this);
        // Generate a proxy class object and return
        return enhancer.create();
    }

    /** * interceptors * 1, method calls to target objects * 2, enhanced behavior *@paramObject Dynamically generated proxy instance * by CGLib@paramMethod The method invoked by the entity class that is referenced by the proxied method@paramObjects Parameter value list *@paramThe proxy class generated by methodProxy has proxy references to methods *@return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        // Enhance behavior
        System.out.println("============== method before execution");

        // Call the target Object's method (return Object)
        Object result = methodProxy.invoke(target,objects);

        // Enhance behavior
        System.out.println("Method executed after ==============");

        returnresult; }}Copy the code

A method is called

// Target object
You you = new You();
CglibInterceptor cglibInterceptor = new CglibInterceptor(you);
Marry marry = (Marry) cglibInterceptor.getProxy();
marry.toMarry();

User user = new User();
CglibInterceptor cglibInterceptor = new CglibInterceptor(user);
User u = (User) cglibInterceptor.getProxy();
u.test();
Copy the code

Differences between JDK agents and CGLIB agents

  • JDK dynamic proxy implementation interface, Cglib dynamic proxy inheritance idea
  • JDK dynamic proxies (when the target object has interfaces) perform more efficiently than Ciglib
  • Select the JDK proxy if the target object has an interface implementation, or the Cglib proxy if no interface implementation exists

Spring AOP

Problems caused by log processing

We have a Pay(interface) and then two implementation classes DollarPay and RmbPay need to rewrite the Pay() method. In this case, we need to monitor the performance of the Pay method, add logs and so on. How do we do that?

The easiest way to think about it

Write logging code for each character method, as follows

Disadvantages: too much code duplication, too much coupling added to the logging code (if you need to change the logging code functional requirements, all the methods in the class need to change, a lot of work)

Improve the solution with the decorator pattern/proxy pattern

Decorator pattern: Dynamically add some additional responsibilities to an object.

Proxy mode: Just mentioned. Hence the following structure:

Found after the careful consideration even though no changes to the original internal code, do log processing for each class, and reference to the target class, but if the number of business class to add a lot of, the manual for each business class implements a decorator or create corresponding proxy class, at the same time, the coupling of the code, once the demand change, You can imagine the amount of work.

Is there a better solution to write the code once, reuse the code where you want to add logging, achieve loose coupling, and still function perfectly?

The answer is yes, such a technology exists, and AOP already provides a perfect implementation for it!

What is AOP?

Aspect Oriented Programing, compared with OOP object-oriented programming, Aop is no longer concerned about a class in the program code, some methods, and Aop consideration is more of a face to face cut, that is, between layers of a cut, so it is called the cut. Think of hamburgers (with meat in the middle). So how does AOP intercept the entire aspect? Consider the servlet filter /* configuration you learned earlier, which is actually an AOP implementation.

What can AOP do?

AOP is mainly used in logging, performance statistics, security control, transaction processing and other aspects to achieve the reuse of common functions.

The characteristics of AOP

1. Reduce the degree of coupling between modules and improve the degree of aggregation of business codes. (High cohesion and low coupling)

2. Improved code reuse.

3. Improve system scalability. (The higher version is compatible with the lower version)

4. You can add new functions without affecting the original functions

The underlying implementation of AOP

Dynamic Proxy (JDK + CGLIB)

Basic concepts of AOP

Joinpoint

For every point intercepted, spring refers to every method intercepted, a Spring AOP join point represents the execution of a method.

Pointcut

Spring has a special expression language definition for intercepting join points (matching rule definitions specify which methods to intercept and which methods to process).

Advice (Advice)

Intercept what to do after each join point (each method)

1. Pre-notification (pre-enhancement) - Before () notification before execution method 2. Return notification (Return enhancement) - afterReturn notification after the return method ends normally 3. Exception throw notification (exception throw enhancement) -- afetrThrow() 4. Final notification - after this notification is executed regardless of whether the method has an exception. 5. Surround advice - Around advice that surrounds a join point, such as a method call. This is the most powerful type of notification. Wraparound notification enables custom behavior before and after a method call. It also chooses whether to continue with the join points or simply return their own return values or throw an exception to end execution.Copy the code

Aspect (Aspect)

A pointcut, in combination with advice, determines the definition of a section. Pointcuts define which methods of which classes to intercept, and advice defines what to do once a method has been intercepted. A section is an abstraction of a crosscutting concern, similar to a class, which is an abstraction of an object’s characteristics.

Target = Target object

The target object to be proxied

Weave (Weave)

The process of applying a facet to a target object and generating a proxy object is called weaving

Introduction

The process of dynamically adding methods or fields to a class at runtime without modifying the original application code is called import

Implementation of Spring AOP

Spring AOP environment setup

Coordinate dependency introduction

<! --Spring AOP-->
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.9</version>
</dependency>
Copy the code

Add the configuration of spring.xml

Adding a namespace

xmlns:aop="http://www.springframework.org/schema/aop"
Copy the code
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop.xsd
Copy the code

Annotations to realize

Define the plane

/** * Aspects * Abstraction of pointcuts and advice (similar to classes in object-oriented) * definition of pointcuts and advice (pointcuts define which methods of which classes to intercept, and advice defines what to do once a method has been intercepted) */
@Component // Pass the object to the IOC container for instantiation
@Aspect // Declare that the current class is an aspect
public class LogCut {

    /** * pointcut: * Match rules. Specify which methods are intercepted, which methods need to be handled * Define pointcuts *@Pointcut(" Matching rules ") * * Introduction to Aop pointcut expressions * 1. Execution of any public method: * execution(public *(..)) Execution of any set method * execution(* set*(..)) (* com.xxxx.service.*.*(..)); (* com.xxxx.service. * com.xxxx.service (* com.xxxx.service (* com.xxxx.service)); *. * (..) Note: The first * in the expression represents the scope of the method. Optional values: private, protected, public (* for all scopes) */
    @Pointcut("execution (* com.xxxx.service.. *. * (..) )"
    public void cut(a){}

    /** * Declares the pre-notification and applies it to the defined pointcut * the notification is executed before the target class method is executed ** /
   @Before(value = "cut()")
    public void before(a) {
        System.out.println("Pre-notification.....");
    }

    /** * Declares the return notification and applies the notification to the defined pointcut * the notification is executed after the target class method (no exceptions) executes
   @AfterReturning(value = "cut()")
    public void afterReturn(a) {
        System.out.println("Return notification.....");
    }

    /** * Declares the final notification and applies the notification to the defined pointcut * after the target class method (with or without exceptions) executes the notification ** /
    @After(value = "cut()")
    public void after(a) {
        System.out.println("Final notice.....");
    }

    /** * Declare an exception notification and apply the notification to the defined pointcut * execute the notification when the target class method is abnormal */
    @AfterThrowing(value="cut()",throwing = "e")
    public void afterThrow(Exception e) {
        System.out.println("Exception notification....." + "Abnormal cause:" + e.getCause());
    }

    /** * declare surround advice and apply the advice to the pointcut * define the corresponding processing by surround advice before and after method execution * the corresponding method needs to be explicitly called otherwise the specified method cannot be accessed (pjp.proceed();) *@param pjp
     * @return* /
    @Around(value = "cut()")
    public Object around(ProceedingJoinPoint pjp) {
        System.out.println("Pre-notification...");

        Object object = null;
        try {
            object = pjp.proceed();
            System.out.println(pjp.getTarget() + "= = = = = =" + pjp.getSignature());
            // system.out. println(" return notification...") );
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("Exception notification...");
        }
        System.out.println("Final notice...");

        returnobject; }}Copy the code

Configuration file (spring.xml)

 <! AOP proxy configuration -->
 <aop:aspectj-autoproxy/>
Copy the code

XML realize

Define the plane

** * Aspects * Abstraction of pointcuts and advice (similar to classes in object-oriented) * definition of pointcuts and advice (pointcuts define which methods of which classes to intercept, and advice defines what to do once a method has been intercepted) */@Component // Pass the object to the IOC container for instantiation
public class LogCut02 {


    public void cut(a){}


    /** * Declares the pre-notification and applies it to the defined pointcut * the notification is executed before the target class method is executed ** /

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

    /** * Declares the return notification and applies the notification to the defined pointcut * the notification is executed after the target class method (no exceptions) executes

    public void afterReturn(a) {
        System.out.println("Return notification.....");
    }

    /** * Declares the final notification and applies the notification to the defined pointcut * after the target class method (with or without exceptions) executes the notification ** /

    public void after(a) {
        System.out.println("Final notice.....");
    }

    /** * Declare an exception notification and apply the notification to the defined pointcut * execute the notification when the target class method is abnormal */

    public void afterThrow(Exception e) {
        System.out.println("Exception notification....." + "Abnormal cause:" + e.getCause());
    }


    /** * declare surround advice and apply the advice to the pointcut * define the corresponding processing by surround advice before and after method execution * the corresponding method needs to be explicitly called otherwise the specified method cannot be accessed (pjp.proceed();) *@param pjp
     * @return* /

    public Object around(ProceedingJoinPoint pjp) {
        System.out.println("Pre-notification...");

        Object object = null;
        try {
            object = pjp.proceed();
            System.out.println(pjp.getTarget() + "= = = = = =" + pjp.getSignature());
            // system.out. println(" return notification...") );
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("Exception notification...");
        }
        System.out.println("Final notice...");

        returnobject; }}Copy the code

Configuration file (spring.xml)

 <! -- AOP related configuration -->
<aop:config>
    <! - aop aspects -- -- >
    <aop:aspect ref="logCut02">
        <! Define aop pointcuts -->
        <aop:pointcut id="cut" expression="execution(* com.xxxx.service.. *. * (..) )"/>
        <! Specify the pre-notification method name and reference the pointcut definition -->
        <aop:before method="before" pointcut-ref="cut"/>
        <! Specify return notification method name and reference pointcut definition -->
        <aop:after-returning method="afterReturn" pointcut-ref="cut"/>
        <! Specify the exception notification method name and reference the pointcut definition -->
        <aop:after-throwing method="afterThrow" throwing="e" pointcut-ref="cut"/>
        <! Specify the final notification method name and reference the pointcut definition.
        <aop:after method="after" pointcut-ref="cut"/>
        <! Specify the surround notification method name and reference the pointcut definition -->
        <aop:around method="around" pointcut-ref="cut"/>
    </aop:aspect>
</aop:config>
Copy the code

Spring AOP summary

The proxy pattern implements three elements

  1. The interface definition
  2. The target object and the proxy object must implement a unified interface
  3. Proxy objects hold references to target objects to enhance target object behavior

The proxy pattern implements classification and corresponding distinction

  1. Static proxy: Manually create proxy objects for the target object, that is, create proxy objects during program compilation

  2. Dynamic proxy: Dynamically creates the proxy object corresponding to the target object during the program running time.

  3. JDK dynamic proxy: The propped target object must implement some interface or set of implementations to create a proxy object through callbacks.

  4. Cglib dynamic proxy: The proxied target object can be implemented by inheritance without implementing an interface.

    Dynamic agent compared with static agent, improve the development efficiency, can create mass agents, improve code reuse rate.

Aop understand

  1. Aspect oriented, instead of OOP, focuses on layers or planes in code
  2. Decouple and improve system scalability
  3. Improved code reuse

Aop keywords

  1. Join points: Each method

  2. Pointcut: A collection of matched methods

  3. Aspect: The set of join points and pointcuts determines the aspect, the abstraction of crosscutting concerns

  4. Notifications: Several types of notifications

  5. Target object: the proxied object

  6. Weaving: The process of applying facets to target objects and generating proxy objects at run time

  7. Import: The process of dynamically introducing methods or fields into a program at runtime without modifying the original code