The two main features of Spring are IOC and AOP. IOC is responsible for dynamically injecting objects into the container in a way that it can be injected as and when it is needed. It is also important to understand Spring’s IOC. But today I’m going to focus on AOP. AOP is widely used to deal with system-level services that have crosscutting properties. AOP is a good complement to OOP to deal with cross-cutting concerns that are distributed across modules in a system, such as transaction management, logging, caching, and so on.

The key to an AOP implementation is the AOP proxy that the AOP framework automatically creates.

AOP proxies are mainly divided into static proxies and dynamic proxies.

  • Static proxies are represented by AspectJ;
  • Dynamic proxies are represented by Spring AOP

1, AspectJ

AspectJ is a static proxy enhancement with compile-time generation of AOP proxy classes, which is also called compile-time enhancement for better performance. Disadvantages: Requires a specific compiler for processing

2, Spring AOP

Spring AOP uses dynamic proxies that generate AOP proxy classes at runtime. Dynamic proxies mean that the AOP framework does not modify the bytecode, but instead temporarily generates an AOP object for a method in memory that contains all of the target object’s methods, enhanced at specific pointcuts. And calls back the methods of the original object. Disadvantages: Because Spring AOP needs to generate an AOP proxy at every run time, performance is slightly worse.

Since the use of AspectJ also needs to be handled using a specific compiler, it can be a bit of a hassle. Today I’m going to focus on Spring AOP

Spring AOP dynamic proxy has two main ways, JDK dynamic proxy and CGLIB dynamic proxy.

  • JDK dynamic proxies receive proxied classes through reflection and require that the proxied classes implement an interface. At the heart of JDK dynamic proxies are the InvocationHandler interface and Proxy class.
  • If the target class does not implement the interface, Spring AOP chooses to use CGLIB to dynamically proxy the target class. CGLIB (Code Generation Library) is a Code Generation Library that dynamically generates subclasses of a class at runtime (by modifying the bytecode to implement the proxy). Note that CGLIB is dynamically proxied by inheritance, so if a class is marked final, it cannot be dynamically proxied using CGLIB. JDK and cglib dynamic proxies to jointly implement our AOP aspect oriented functionality.

The following is a simple code to demonstrate the implementation principle of JDK and Cglib dynamic proxy.

First, THE JDK dynamic proxy implements AOP interception

  • 1. Define an interface, JdkInterface, for the target target class, which is the premise of the JDK dynamic proxy implementation
/** * Created by QCL on 2018/11/29 ** * Created by QCL on 2018/11/29 ** * Created by QCL on 2018/11/29 */ }Copy the code
  • 2. Implement the interface defined above with the target class JdkClass we want to proxy. Our experimental goal is to intercept before and after the add method of the target class without changing the target class JdkClass, and add custom section logic. That’s the beauty of AOP: there’s no coupling between code.
/** * Created by qcl on 2018/11/29 * desc: Target */ public class implements JdkInterface {@override public voidadd() {
        System.out.println("Add method for target class"); }}Copy the code

-3, the key step is to use our MyInvocationHandler to implement the InvocationHandler interface and invoke method in the interface. If you look closely at the Invoke method, it is there that aspect logic is added. The target class method is executed by the mehod. Invoke (Target,args) statement.

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * implements InvocationHandler {/** * implements InvocationHandler {/** * implements InvocationHandler; private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before ------- section adds logic"); Object invoke = method.invoke(target, args); // Execute by reflection, the target class's method system.out.println ("After ------- section adds logic");
        returninvoke; }}Copy the code
  • 4. Test results
/** * Created by QCL on 2018/11/29 * desc: test */ public class JdkTest {public static void main(String[] args) {JdkClass  jdkClass = new JdkClass(); MyInvocationHandler handler = new MyInvocationHandler(jdkClass); // Proxy dynamically creates a Proxy instance that matches an interface for the InvocationHandler implementation class // in this case proxyInstance is the enhanced Proxy class of our target class JdkInterface proxyInstance = (JdkInterface) Proxy.newProxyInstance(jdkClass.getClass().getClassLoader(), jdkClass.getClass() .getInterfaces(), handler); proxyInstance.add(); // Print the enhanced class type system.out.println ("= = = = = = = = = = = = ="+ proxyInstance.getClass()); }}Copy the code

Executing the above test class yields the following results

Second, CGLIb dynamic proxy implements AOP interception

  • 1, define a Base target class to be proxied (cglib does not need to define an interface)
/** * Created by QCL on 2018/11/29 * desc: class to be proxied */ public class Base {public voidadd(){
        System.out.println("Add method for target class"); }}Copy the code
  • 2. Define CglibProxy class to implement MethodInterceptor interface and Intercept method. The purpose of this proxy is to add custom section logic before and after the add method. The target class add method executes the statement proxy.invokesuper (Object, args).
import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; */ public class CglibProxy implements MethodInterceptor {@override */ CglibProxy implements MethodInterceptor public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("Before ------- section adds logic");
        methodProxy.invokeSuper(object, args);
        System.out.println("After ------- section adds logic");
        returnnull; }}Copy the code
  • 3. Test classes
/** * Created by QCL on 2018/11/29 * desc: class CglibTest {public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Base.class); // The intercept method hancer.setCallback(proxy) is used in CglibProxy. // Base = (base) enhancer. Create (); base = (base) enhancer. base.add(); Class<? extends Base> baseClass = base.getClass(); // Check whether the parent of the enhanced class is the unenhanced Base class system.out.println ("Enhanced class parent:"+baseClass.getSuperclass().getName());
        System.out.println("============ Print all methods of the enhanced class =============="); FanSheUtils.printMethods(baseClass); Base base2 = new Base(); System.out.println("Parent of unenhanced class:"+base2.getClass().getSuperclass().getName());
        System.out.println("============= Print methods for unenhanced target classes ==============="); FanSheUtils.printMethods(base2.getClass()); // Print all methods of the unenhanced class}}Copy the code

Here is the print

  • Cglib’s dynamic intercept cut was successful
  • The cglib dynamic proxy approach is to dynamically generate a subclass of the target class (Base) at runtime, and add a number of cglib-specific methods to the existing methods of the target class. The utility class that prints all the methods of the class with reflection is posted below
Public class FanSheUtils {// Prints all methods of this class public static voidprintMethods(Class cl) { System.out.println(); [] methods = cl.getDeclaredMethods(); // go through the number groupfor (Method method : methods) {
            System.out.print(""); // Get the Modifier for this method and print String modifiers = modifiers. ToString (method.getModifiers());if (modifiers.length() > 0) {
                System.out.print(modifiers + ""); } // Print the method name system.out.print (method.getName() +"("); Class[] paramTypes = method.getParameterTypes(); // Get an array of Class objects containing all parameter types for this method. // go through the number groupfor (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {
                    System.out.print(",");
                }
                System.out.print(paramTypes[i].getName());
            }
            System.out.println(");"); }}}Copy the code

Note: cglib.jar and ASm. jar are used above. Just import the following libraries in maven’s POM.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
Copy the code