This article will move from Java’s proxy mechanism to Spring’s AOP.

1. Proxy mode

The agent mode is a very common design mode, the word agent is broken down to accept on behalf of, that is obviously to involve the request of the agent, the agent to provide the agent, and want to actually contact the client through the agent three roles. For an example of common life, each star have their own agent to driving in all kinds of things for yourself, this kind of scenario, the star itself is the principal, the agent is the agent, the stars put their performance, to attend the meeting schedule right entrusted to an agent, such as various businesses as customers want to please star to endorse, You have to do it through a broker. In this way, the stars themselves do not need to expose their identities, and the agent can also inform the merchants of the requirements of what they will eat and what they will do when they attend the event, saving the stars from having to worry about these trivial matters. On the other hand, being a broker can also provide services to multiple stars, so that businesses can contact only one broker, so that they can contact different stars and find a candidate suitable for their own company. The advantages of the proxy pattern are obvious from the above example:

Advantage 1: you can hide the implementation of the delegate class;

Advantage two: Decoupling the client from the delegate class, allowing you to do some extra processing without modifying the delegate code.

2. Bytecode and proxy mode

Java programmers should know that Java compiles.java source files into.class bytecode files using the Java compiler. These.class files are binary files that contain machine code that only the JVM virtual machine can recognize. The JVM virtual machine reads the bytecode files, takes out the binary data, and loads it into memory. The information in the. Class file is parsed to generate the corresponding class object, and then the class object creates a specific instance of the class to call the specific function.

Above illustrates the process of load Java bytecode, but a powerful Java is not only can be loaded at compile time to generate the bytecode, still can be in the runtime system, follow the Java build system organization. The class file format and structure, generate the corresponding binary data, and then converts the binary data is loaded into the corresponding class, This completes the ability to dynamically create a class in your code, as shown in the following diagram.

As an example of a dynamically generated class, Javassist is an open source library for analyzing, editing, and creating Java bytecodes. You can use Javasisst tools to dynamically create bytecodes and load classes at runtime, as follows:

/** * Created by zhoujunfu on 2018/9/6. */
public class JavassistDemo {
    
    public static void main(String[] args) {
        makeNewClass();
    }
    
    public staticClass<? > makeNewClass() {try {
            / / get the ClassPool
            ClassPool pool = ClassPool.getDefault();
            // Create the Student class
            CtClass ctClass = pool.makeClass("com.fufu.aop.Student");
            // Create the Student member variable name
            CtField name = new CtField(pool.get("java.lang.String"), "name", ctClass);
            // Set name to private
            name.setModifiers(Modifier.PRIVATE);
            // Write name to class
            ctClass.addField(name, CtField.Initializer.constant("")); // Write to the class file
            // Add a set method named "setName"
            ctClass.addMethod(CtNewMethod.setter("setName", name));
            // Add a get method named getName
            ctClass.addMethod(CtNewMethod.getter("getName", name));
            // Add a constructor with no arguments
            CtConstructor cons = new CtConstructor(new CtClass[] {}, ctClass);
            cons.setBody("{name = \"Brant\"; }"); Public Sclass(){this.name = "brant"; }
            ctClass.addConstructor(cons);
            // Add a constructor with arguments
            cons = new CtConstructor(new CtClass[] {pool.get("java.lang.String")}, ctClass);
            cons.setBody("{$0.name = $1; }");  Public Sclass(String s){this.name = s; public Sclass(String s){this.name = s; }
            ctClass.addConstructor(cons);

            // reflection calls the newly created classClass<? > aClass = ctClass .toClass(); Object student = aClass.newInstance(); Method getter =null;
            getter = student.getClass().getMethod("getName");
            System.out.println(getter.invoke(student));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null; }}Copy the code

The two methods of loading bytecode statically and dynamically are introduced in order to introduce the following two methods of proxy. The proxy mechanism is divided into static proxy and dynamic proxy based on the different time of proxy class creation: static proxy: The proxy class is generated at compile time and exists before the program runs, so it is called a static proxy. In this case, the proxy class is usually defined in Java code. Dynamic proxy: The proxy classes are created at runtime, that is, in this case, the proxy classes are not defined in Java code, but are dynamically generated at runtime according to our “instructions” in Java code.

At present, static proxy mainly has AspectJ static proxy, JDK static proxy technology, and dynamic proxy has JDK dynamic proxy, Cglib dynamic proxy technology, and Spring Aop is the integration of JDK dynamic proxy and Cglib dynamic proxy two technologies, the following we combine examples step by step to introduce all the concepts.

3. Static proxy

3.1 AspectJ Static Proxy

For AspectJ, we’re going to take a quick look at it to set the stage for future understanding, but we just need to know the following definition:

AspectJ is a section-oriented framework for Java implementations that extends the Java language. AspectJ has a custom syntax, so it has a special compiler to generate Class files that comply with Java byte-encoding specifications.

Note the description of “specialized compiler” in the definition above. You can see that AspectJ is a typical static proxy technology, since the proxy classes are generated at compile time, and using AspectJ also requires specifying a specific compiler. Let’s use AspectJ to implement the star and broker model above.

First we introduce AspectJ dependencies in the Maven project:

<dependency> <groupId>org.aspectj</groupId> <artifactId> aspectJrt </artifactId> <version>1.8.9</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId> AspectJtools </artifactId> <version>1.8.9</version> </dependency>Copy the code

Then change the JavAC compiler to the ACJ compiler in IDEA to support AspectJ syntax:

Abstract the star’s performance into a ShowService interface, including singing and dancing functions

public interface ShowService {
    // Singing performances
    void sing(String songName);
    // Dance performances
    void dance(a);
}

Copy the code

Star class implements the ShowService interface:

package com.fufu.aop; /** * Created by zhoujunfu on 2018/9/6. ** * Created by zhoujunfu on 2018/9/6. */ public class Star implements ShowService{private String name; @Override public void sing(String songName) { System.out.println(this.name +" sing a song: " + songName);
    }

    @Override
    public void dance() {
        System.out.println(this.name + "dance");
    }

    public Star(String name) {
        this.name = name;
    }

    public Star() {
    }

    public static void main(String[] args) {
        Star star = new Star("Eminem");
        star.sing("Mockingbird"); }}Copy the code

Implement an AgentAspectJ with AspectJ syntax:

package com.fufu.aop; /** * Created by zhoujunfu on 2018/9/7. */ public Aspect AgentAspectJ {/** * define pointcut */ pointcut sleepPointCut():call(* Star.sing(..) ); /** * pointcut eatPointCut():call(* star.eat (..)) ); / * * before * * * defined front notice (parameters) : join function} {* function body * * / before () :sleepPointCut(){ getMoney(); } / rear definition notice * * * * after (parameters) : join function} {* function body * * / after () :sleepPointCut(){
        writeReceipt();
    }

    private void getMoney() {
        System.out.println("get money");
    }

    private void writeReceipt() {
        System.out.println("write receipt"); }}Copy the code

Create a Star and run the method:

public static void main(String[] args) {
        Star star = new Star("Eminem");
        star.sing("Mockingbird");
    }
Copy the code

Output:

get money
Eminem sing a song: Mockingbird
write receipt
Copy the code

You can see that the sing() method of Star outputs the pre-notification and post-notification that we defined in AgentAspectJ, so it is AspectJ that generates the enhanced Star class at compile time from the code defined in AgentAspectJ code, and when we actually call it, The function of the proxy class is implemented. We won’t go into the specifics of AspectJ syntax, except that the Pointcut is the entry point for defining proxies. Here we define two pointcuts, the Sing () and dance() methods of the Star class. Before () and after(), respectively, define additional operations that are specifically required before and after the pointcut.

To summarize, AspctJ implements compile-time enhancements to classes using a specific compiler and syntax, and implements static proxies.

3.2 JDK Static Proxy

In general, JDK static proxies are more of a design pattern. The proxy and delegate classes in JDK static proxies implement the same interface or derive from the same parent class. The basic class diagram for the proxy mode is shown below:

We then implement a JDK static proxy pattern by coding the above star and broker example.

The agent human also implements the ShowService interface, holding a star object to provide the real performance, and adding things the agent needs to handle before and after each performance, such as collecting money, invoicing, etc. :

package com.fufu.aop;

/** * Created by zhoujunfu on 8/9/6. * Broker */
public class Agent implements ShowService{

    private Star star;

    public Agent(Star star) {
        this.star = star;
    }

    private void getMoney(a) {
        System.out.println("get money");
    }

    private void writeReceipt(a) {
        System.out.println("write receipt");
    }
    @Override
    public void sing(String songName) {
        // Collect money before the song begins
        getMoney();
        // The star begins to sing
        star.sing(songName);
        // Invoice after singing
        writeReceipt();
    }

    @Override
    public void dance(a) {
        // Collect money before dancing begins
        getMoney();
        // The star starts to dance
        star.dance();
        // Invoice after dancewriteReceipt(); }}Copy the code

To hire a star through an agent:

 public static void main(String[] args) {
        Agent agent = new Agent(new Star("Eminem"));
        agent.sing("Mockingbird");
 }
Copy the code

Output:

get money
Eminem sing a song: Mockingbird
write receipt
Copy the code

The above is a typical static proxy example, very simple but also illustrative, let’s look at the advantages and disadvantages of static proxy:

Advantages: Business classes can focus on their own logic and can be reused, adding common logic processing through proxy classes.

Disadvantages: 1. An interface of a proxy object only serves one type of object. If you want to proxy many classes, you must proxy for each class.

2. If an interface adds a method, all proxy classes need to implement the method in addition to all implementation classes. Increases the complexity of code maintenance

In addition, if the proxy pattern is to be used as described above, the real role (delegate class) must already exist as an internal property of the proxy object. However, in practice, a real role must correspond to a proxy role. If a large number of roles are used, the class will expand rapidly. Also, how do you use a proxy if you don’t know the real role (the delegate class) beforehand? These issues can be addressed by Java’s dynamic proxy classes.

Dynamic proxy

The source code for the dynamic proxy class is generated dynamically by the JVM during program execution, based on mechanisms such as reflection, so there are no bytecode files for the proxy class. The relationship between the proxy class and the delegate class is determined at runtime.

4.1 Dynamic Proxy Roadmap

Want to understand the idea of dynamic proxy class implementation is what, we also need to start with the problem of the existence of static proxy, because after all, dynamic proxy is to solve the problem of the existence of static proxy, let’s look at the problem of static proxy:

  1. Class bloat: Every proxy class is a concrete class that needs to be written by a programmer, which is unrealistic.
  2. Method-level proxy: Both the proxy class and the implementation class implement the same interface, so each method of the proxy class needs to be proxy. If you have a few methods, I will have a few, so the coding is complicated and cannot be maintained.

Dynamic proxy how to solve:

  1. The first question is easy to answer, similar to the example of using Javasisst to dynamically create the bytecode of the proxy class in code and then retrieve the proxy class object.
  2. The second issue leads to the InvocationHandler. To construct a generic and simple proxy class, you can hand over all of the triggering real character actions to a triggering manager that manages the triggering uniformly. This manager is called the InvocationHandler. Sleep () corresponds to sleep(), run() corresponds to run(). In Java, Method is also an object, so, A dynamic proxy class can hand off all calls to itself as Method objects to the InvocationHandler, which calls different methods of the specific implementation class, depending on the Method. The InvocationHandler is responsible for adding the proxy logic and calling the methods of the concrete implementation class.

In other words, the dynamic proxy class and the implementation of the same interface, but the dynamic proxy class is based on the implementation of the interface generated dynamically, does not need to care about the user, in addition to the dynamic proxy class all method calls, unified to the InvocationHandler, does not need to deal with the implementation of each interface of each method.

In this pattern, it is important that the Proxy and RealSubject implement the same functionality. (The function I’m talking about here can be understood as a public method of a class.)

In object-oriented programming, if we want to agree that Proxy and RealSubject can achieve the same function, there are two ways:

A. An intuitive approach is to define a functional interface and let Proxy and RealSubject implement this interface. [B]. There is also a more subtle way, which is through inheritance. If a Proxy inherits from a RealSubject, it has the functionality of a RealSubject and can override methods in a RealSubject to implement polymorphism.

The mechanism for creating dynamic proxies provided in the JDK is designed with a in mind and cglib with B in mind.

4.1 JDK Dynamic Proxy (via interface)

Let’s first look at a specific example, or the above star and agent model as an example, so as to facilitate comparison and understanding:

Abstract the star’s performance into a ShowService interface, including singing and dancing functions:

package com.fufu.aop;

/** * Created by zhoujunfu on 2018/9/6. */
public interface ShowService {
    // Singing performances
    void sing(String songName);
    // Dance performances
    void dance(a);
}
Copy the code

Star class implements the ShowService interface:

package com.fufu.aop;

/** * Created by zhoujunfu on 2018/9/6. * star class */
public class Star implements ShowService{
    private String name;

    @Override
    public void sing(String songName) {
        System.out.println(this.name + " sing a song: " + songName);
    }

    @Override
    public void dance(a) {
        System.out.println(this.name + "dance");
    }

    public Star(String name) {
        this.name = name;
    }

    public Star(a) {}}Copy the code

Implement a request handler for a proxy class that handles calls to all methods of the concrete class:

package com.fufu.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/** * Created by zhoujunfu on 2018/9/7. */
public class InvocationHandlerImpl implements InvocationHandler {

    ShowService target;

    public InvocationHandlerImpl(ShowService target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // Collect money before the show begins
        getMoney();
        // The star begins to sing
        Object invoke = method.invoke(target, args);
        // Invoice after performance
        writeReceipt();

        return invoke;
    }

    private void getMoney(a) {
        System.out.println("get money");
    }

    private void writeReceipt(a) {
        System.out.println("write receipt"); }}Copy the code

Implementing a dynamic proxy using the JDK dynamic proxy mechanism

package com.fufu.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * Created by zhoujunfu on 2018/9/7. */ public class JDKProxyDemo { public static void main(String[] args) { // 1. Star Star = new Star("Eminem"); ClassLoader ClassLoader = star.getClass().getClassLoader(); Class[] interfaces = star.getClass().getinterfaces (); InvocationHandler InvocationHandler = new InvocationHandlerImpl(star); During this process, * A. DK dynamically creates bytecode * b in memory equivalent to the.class file based on the passed parameter information. And then convert to the corresponding class based on the corresponding bytecode, C. Then call newInstance() to create instance */ Object o = proxy.newproxyInstance (classLoader, interfaces, invocationHandler); ShowService showService = (ShowService)o; showService.sing("Mockingbird"); }}Copy the code

Let’s start with proxy creation and see what the JDK’s dynamic proxy does:

Object o = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
Copy the code
  1. Proxy.newproxyinstance () gets a list of all interfaces of the Star class (second argument: interfaces)
  2. Determine the class name of the proxy class to be generated. The default is com.sun.proxy.$ProxyXXXX
  3. According to the interface information to be implemented, the bytecode of the Proxy class is dynamically created in the code.
  4. Convert the corresponding bytecode to the corresponding class object;
  5. Create the InvocationHandler instance handler that handles all method calls to the Proxy
  6. The Proxy class object instantiates a Proxy object, taking the created handler object as argument (third argument: invocationHandler)

For InvocationHandler, we need to implement the following invoke methods:

public Object invoke(Object proxy, Method method, Object[] args) 
Copy the code

Within the code, each method in the proxy object is called directly to the Invoke method of InvocationHandler, which identifies the method based on the method argument passed to it by the proxy class.

As you can see, the proxy.newProxyInstance () method generates objects that implement the ShowService interface, so you can cast them to ShowService in code to achieve the same effect as static proxies. We can use the following code to save the bytecode of the generated proxy class to disk and decompile to see the structure of the dynamic proxy class generated by the JDK.

package com.fufu.aop;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;

/** * Created by zhoujunfu on 2018/9/7. */
public class ProxyUtils {

    public static void main(String[] args) {
        Star star = new Star("Eminem");
        generateClassFile(star.getClass(), "StarProxy");
    }

    public static void generateClassFile(Class clazz, String proxyName) {

        // Generate bytecode based on the class information and the provided proxy class name
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String paths = clazz.getResource(".").getPath();
        System.out.println(paths);
        FileOutputStream out = null;

        try {
            // Save to hard disk
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch(IOException e) { e.printStackTrace(); }}}}Copy the code

Decompiling the starpoxy.class file yields:

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

import com.fufu.aop.ShowService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

The dynamic proxy class StarPoxy implements the ShowService interface
public final class StarProxy extends Proxy implements ShowService {
    // Load all methods defined in the interface
    private static Method m1;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m0;

    // The constructor calls InvocationHandler, which holds the InvocationHandler object h
    public StarProxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw newUndeclaredThrowableException(var4); }}// An automatically generated sing() method that actually calls the invoke method of the InvocationHandler object H, passing in the M3 parameter object representing the Sing () method
    public final void sing(String var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw newUndeclaredThrowableException(var4); }}// Generate the dance() method in the same way
    public final void dance(a) throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}public final String toString(a) throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}public final int hashCode(a) throws  {
        try {
            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}// Load all methods defined in the interface
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals".new Class[]{Class.forName("java.lang.Object")});
            m3 = Class.forName("com.fufu.aop.ShowService").getMethod("sing".new Class[]{Class.forName("java.lang.String")});
            m4 = Class.forName("com.fufu.aop.ShowService").getMethod("dance".new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString".new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode".new Class[0]);
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw newNoClassDefFoundError(var3.getMessage()); }}}Copy the code

As you can see from the decomcompiled code above, the JDK generates a dynamic proxy class that implements the same interface as the concrete class and holds an InvocationHandler object (which in turn holds the concrete class) that calls the methods in the dynamic proxy class. The invoke() method passed to InvocationHandler is triggered, using the method argument to distinguish the specific method being called, as shown in the following figure:

4.2 CGLIB Dynamic Proxy (through Inheritance)

The mechanism provided in the JDK for generating dynamic proxy classes has a distinctive feature:

A class must have an interface to implement, and the generated proxy class can only delegate methods defined by a class interface. For example, if the above example Star implements the play() method in addition to the ShowService interface method, the generated dynamic proxy class will not have this method! More extreme: if a class does not implement an interface, then it cannot use the JDK to generate dynamic proxies!

Fortunately, we have Cglib, “Cglib (Code Generation Library) is a powerful, high performance, high quality Code Generation Library, which can extend Java classes and implement Java interfaces at runtime.”

Cglib creates A dynamic proxy class of class A using the following pattern:

1. Find all non-final public method definitions on A; 2. Convert the definitions of these methods into bytecode; 3. Convert the composed bytecode into the corresponding proxy class object; 4. Implement the MethodInterceptor interface, which handles requests for all methods on the proxy class (this interface has the same functionality and role as the JDK dynamic proxy InvocationHandler)

The ShowService interface and the Star class are both reusable. The ShowService interface and the Star class are both reusable.

Implementing the MethodInterceptor interface:

package com.fufu.aop;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/** * Created by zhoujunfu on 2018/9/7. */
public class MethodInterceptorImpl implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        // Collect money before the show begins
        getMoney();
        // The star begins to sing
        Object invoke = methodProxy.invokeSuper(o, objects);
        // Invoice after performance
        writeReceipt();

        return invoke;
    }

    private void getMoney(a) {
        System.out.println("get money");
    }

    private void writeReceipt(a) {
        System.out.println("write receipt"); }}Copy the code

Create dynamic proxy:

package com.fufu.aop;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

/** * Created by zhoujunfu on 2018/9/7. */
public class CglibProxyDemo {

    public static void main(String[] args) {
        Star star = new Star("Eminem");

        MethodInterceptor methodInterceptor = new MethodInterceptorImpl();

        //cglib reinforcer, used to create dynamic proxy
        Enhancer enhancer = new Enhancer();
        // Set the class to create the dynamic proxy
        enhancer.setSuperclass(star.getClass());
        // Set the CallBack to be called for all methods on the proxy class, which is intercepted by the Intercept () method
        enhancer.setCallback(methodInterceptor);

        ShowService showService = (ShowService) enhancer.create();
        showService.sing("Mockingbird"); }}Copy the code

As can be seen from the above examples, Cglib implements dynamic proxy through inheritance. The concrete class does not need to implement a specific interface, and the proxy class can call the non-interface methods of the concrete class, which is more flexible.

5.Spring AOP

5.1 concept

The specific concept of AOP is no longer said, a large number of web search, this article mainly introduces the use of Spring AOP low-level proxy technology, because usually in the use of Spring AOP, many people are copy configuration, the above introduction of these technical concepts are not clear.

Spring AOP uses dynamic proxies, enhancing business methods at run time so that no new classes are generated. For dynamic proxies, Spring AOP provides JDK dynamic proxy support as well as CGLib support. However, when to use which proxy?

The JDK’s dynamic proxy implementation of AOP is used by default if the target object implements an interface

You can force CGLIB to implement AOP if the target object implements an interface

3. If the target object does not implement an interface, the CGLIB library must be used, and Spring will automatically convert between JDK dynamic proxies and CGLIB

At the moment, Spring seems to have nothing to do with AspectJ, so why do @AspectJ annotations appear in so many projects that use Spring AOP? Spring is a dynamic proxy for applications, so why should it be related to AspectJ? The reason is that Spring AOP’s annotation-based configuration relies on the standard annotations of the AspectJ package, but does not require additional compilation and AspectJ weepers, whereas XML-based configuration does not. So Spring AOP just re-uses AspectJ’s annotations and has no other dependencies on AspectJ.

When Spring needs to use @AspectJ annotation support, the following configuration is required in the Spring configuration file:

<aop:aspectj-autoproxy/>
Copy the code

To enforce CGLIB, you can configure the following in the Spring configuration file:

<aop:aspectj-autoproxy proxy-target-class="true"/>
Copy the code

The proxy-target-class attribute value determines whether an interface-based or class-based proxy is created. If the proxy-target-class attribute value is set to true, the class-based proxy takes effect (the Cglib library is required). If the proxy-target-class genus value is set to false or this property is omitted, the standard JDK interface-based proxy.

So, while the Annotation of an Aspect is used, there is no compiler or weaver that uses it. It is implemented using JDK dynamic proxy or Cglib, which generates proxy classes at run time.

Having written so much, let’s post two more Spring AOP demo code, one based on XML and one based on annotations:

5.2 based on XML

Cut class:

package com.fufu.spring.aop;

import org.springframework.stereotype.Component;

/** * Created by Zhoujunfu on 2018/9/7. * XmL-based Spring AOP */
@Component
public class AgentAdvisorXML {

    public void getMoney(a) {
        System.out.println("get money");
    }

    public void writeReceipt(a) {
        System.out.println("write receipt"); }}Copy the code

Configuration file:

<?xml version="1.0" encoding="UTF-8"? >
<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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="star" class="com.fufu.proxy.Star">
        <property name="name" value="Eminem"/>
    </bean>

    <bean id="agentAdvisorXML" class="com.fufu.spring.aop.AgentAdvisorXML"/>
    
     <! -- XmL-based facets of Spring
     <aop:config>
         <! Define pointcut function -->
         <aop:pointcut id="singPointCut" expression="execution(* com.fufu.proxy.Star.sing(..) )"/>
         <! Order specifies the priority. The lower the priority is, the higher the priority is.
         <aop:aspect ref="agentAdvisorXML" order="0">
             <! -- Pre-notification -->
             <aop:before method="getMoney" pointcut-ref="singPointCut"/>
             <! -- Post-notification -->
             <aop:after method="writeReceipt" pointcut-ref="singPointCut"/>
         </aop:aspect>
     </aop:config>

</beans>
Copy the code

The test class:

package com.fufu.spring.aop;

import com.fufu.proxy.ShowService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * Created by zhoujunfu on 2018/9/7. */
public class Main {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");

        Object star = applicationContext.getBean("star");

        ShowService showService = (ShowService)star;
        showService.sing("Mockingbird"); }}Copy the code

5.3 Annotation-based

Cut class:

package com.fufu.spring.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

/** * Created by Zhoujunfu on 2018/9/7. * Annotated Spring AOP */
@Aspect
@Component
public class AgentAdvisor {

    @Before(value = "execution(* com.fufu.proxy.ShowService.sing(..) )")
    public void getMoney(a) {
        System.out.println("get money");
    }

    @After(value = "execution(* com.fufu.proxy.ShowService.sing(..) )")
    public void writeReceipt(a) {
        System.out.println("write receipt"); }}Copy the code

Configuration file:

<? xml version="1.0" encoding="UTF-8"? > <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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">


    <context:component-scan base-package="com.fufu.proxy, com.fufu.spring.aop"/>

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

</beans>
Copy the code

The test class:

package com.fufu.spring.aop;

import com.fufu.proxy.ShowService;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Created by zhoujunfu on 2018/9/7.
 */
public class Main {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop-annotation.xml");

        Object star = applicationContext.getBean("star");

        ShowService showService = (ShowService)star;
        showService.sing("Mockingbird"); }}Copy the code

6. Summary

The above content, while relatively straightforward, provides a comprehensive understanding of the Java proxy mechanism and Spring AOP.