The article has been hosted on GitHub, you can go to GitHub to view and read, welcome bosses to Star! Search wechat public number [code out Offer] to receive a variety of learning materials!


What is AOP

Aspect Oriented Programming (AOP), or section-oriented Programming, uses a technique called “crosscutting” to cut open the interior of wrapped objects and encapsulate the common behavior that affects multiple classes into a reusable module named “Aspect”, or Aspect. The so-called “facets”, simply speaking, are those unrelated to the business, but are encapsulated by the logic or responsibility of business modules, which is convenient to reduce the repetitive code of the system, reduce the degree of coupling between modules, and is conducive to the future operability and maintainability.

Application scenarios: Such as logging, auditing, declarative transactions, security, and caching.

Ii. Scenario analysis

To better understand AOP, infiltrate the idea of section-oriented programming. Let me give you an example that is very common in development. Print log

First, we need to understand what logging is.

Logging: Logging is a way to keep track of what is happening while some software is running, and software developers can call logging related methods into their code to indicate that something is happening. An event can be described by a message that contains optional variable data. In addition, an event also has the concept of importance, which can also be called a severity level. Developers can analyze the desired information by differentiating severity levels.

Knowing what a log is, you need to know how and where to print a log. To print logs, import dependencies and use log tools to print log severity levels and log information. Where to print the log is, of course, a key place in our project code.

Here is an example of A code before and after the use of three methods, A, B, C, but before calling each method, require A line of log “A method was called!” After each method is called, it is also required to print the log “a method has been called!” .

Ordinary people can be in the beginning and the end of each method is printed, add a log to do so much more if the method, will have a lot of repetitive code, appear very trouble, someone will think of, why don’t you encapsulate print log this feature, and then make it can in the specified place (such as the execution method before, or after the execution method) automatically to call? If you can, the business function code is not mixed with this other code, so AOP does just that.

Its working principle is JDK dynamic proxy and CGLIB dynamic proxy, here will not expand the knowledge of dynamic proxy! Or see AOP first!

AOP terminology

What AOP does: Spring’s AOP programming is all about adding helper functionality to the methods of the original class through dynamic proxy classes.

AOP terminology describe
The join (Joinpoint) Join points are methods that exist objectively in a program class and can be intercepted by Spring to cut into content
Point (Pointcut) Cut into the join point by Spring
Advice Additional capabilities can be added to pointcuts: pre-notification, post-notification, exception notification, surround notification, and so on.
Target Object The target object of the proxy
Introduction (the Introduction) A special enhancement that dynamically adds Field and Method to a class at run time
Weave (has) The process of creating a new proxy class by applying advice to a concrete class
The agent (Proxy) The resulting class that is woven into the advice by AOP
Section (Aspect) Consists of pointcuts and notifications that weave crosscutting logic into the join points specified by the section

Four, AOP terminology analysis

3.1 points

Simply put, a place that allows you to use notifications, enhancements. Just like printing logs before and after methods, we can do things before and after a piece of code, we can do things after a piece of code, we can do things after a piece of code throws exceptions. So, lines of code (methods, etc.) that can be manipulated here are join points.

3.2 point

Looking at code such as method by method as join points, where do we print logs (enhancement operations), and where do we pick out where we need to print logs (around join points), known as pointcuts.

3.3 Enhancement and notification

In terms of enhancements, AS I mentioned above, actions done through pointcuts are called enhancements, such as when we print logs, and logging is an enhancement operation.

3.4 Target Objects

The target object is simply the object to be enhanced.

3.5 introduction

Allows us to add new method attributes to existing classes. This does not apply the aspect (that is, the new method property defined by the enhancement) to the target object

3.6 woven into

The process of creating a new proxy class by applying enhancements to specific target objects

3.7 the agent

A proxy is just like the mediation we used to buy a house, that is, a proxy object (mediation object) that is woven into AOP to enhance our target object

Section 3.8

A section is a combination of advice (enhancement) and pointcuts. Advice says what to do and when, and pointcuts say where to do, which is a complete aspect definition.

Five, SpringAOP development steps

5.1 The POM.xml file introduces dependencies

Introducing Spring core dependencies (Spring-Context) and SpringAOP dependencies (Spring-Aspects)

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> < version > 5.1.6. RELEASE < / version > < / dependency > < the dependency > < groupId > org. Springframework < / groupId > < artifactId > spring - aspects < / artifactId > < version > 5.1.6. RELEASE < / version > < / dependency >Copy the code

5.2 Create the spring-context. XML file and add a schema

We need to add the AOP and context’s Schema to the header of the core configuration file

<? The XML version = "1.0" encoding = "utf-8"? > <beans xmlns="" xmlns:context="" xmlns:aop="" xmlns:xsi="" xsi:schemaLocation=" "> </beans>Copy the code

5.3 Defining primitive classes

The simulation creates a primitive class

public interface UserService {
    public void save(a);

public class UserServiceImpl implements UserService {
    public void save(a) {
        System.out.println("save method executed..."); }}Copy the code

5.4 Define the pass class

Define notification classes (add additional enhancements)

public class MyAdvice implements MethodBeforeAdvice { // Implement the pre-notification interface
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before advice executed..."); }}Copy the code

5.5 define the bean

Configuring bean objects

<! -- Primitive object --> <bean id="us" class="com.mylifes1110.service.impl.UserServiceImpl"/ > <! -- Auxiliary (enhanced) object --> <bean id="myAdvice" class="com.mylifes1110.advice.MyAdvice" />
Copy the code

5.6 Defining pointcuts to form facets

Define pointcuts and form aspects

<aop:config> <! Aop :pointcut id="myPointCut" expression="execution(* save())" /> <! <aop:advisor advice-ref="myAdvice" pointcut-ref="myPointCut" /> </aop:config>Copy the code

5.7 Enhancement Results

Use pre-notification to result in enhanced print statements before Advice executed… Save method executed… is printed before the save() method. .

Six, notifications,

Define notification classes for notification (enhancement) effect. Implement different interfaces and override methods to achieve different notification effects

Notice the name interface describe
Pre notice MethodBeforeAdvice interface Enhance in front of the target object
The rear notice AfterAdvice interface Note: the method in this interface is empty, and the third method is used by default
The rear notice AfterReturningAdvice interface Make enhancements after the target object
Abnormal notice ThrowsAdvice Enhance the target object after an exception occurs
Surrounding the notification MethodInterceptor Enhance before and after the target object

Seven, wildmatch entry point

Wildcard pointcuts based on expressions

Wildcard expression order: Return value type full class name. Method name (parameter)

Note: You can use.. To implement the wildcard parameter list, use * to wildcard the method name or return value type

<! --public int com.mylifes1110.service.UserServiceImpl.queryUser(int,String,com.entity.User) --> <! < AOP :pointcut id="myPointCut" expression="execution(* *(com.mylifes1110.bean.User))"/ > <! --> < AOP :pointcut id="myPointCut" expression="execution(* save())"/ > <! --> < AOP :pointcut id="myPointCut" expression="execution(* save(..) )"/ > <! Aop :pointcut id="myPointCut" expression="execution(com.mylifes1110.bean.User *(..) )"/ > <! < AOP :pointcut id="myPointCut" expression="execution(* com.mylifes1110.bean.UserServiceImpl.*(..) )"/ > <! < AOP :pointcut id="myPointCut" expression="execution(* com.mylifes1110.bean.*.*(..) )"/ > <! < AOP :pointcut id="myPointCut" expression="execution(* com.mylifes1110.. *. * (..) )" />
Copy the code

8. Agent mode

8.1 Agent Mode

Separating core functions from auxiliary functions (transaction, log, performance monitoring code) makes core business functions purer and auxiliary business functions reusable.

Functional separation

8.2 Application Scenario Simulation of proxy Mode

Through the object of the proxy class, adding auxiliary functions for the object of the original class (object of the target class), it is easier to change the proxy implementation class and facilitate maintenance.

Scenario simulation: We need to go through the following process in renting a house:

  1. Release rental information
  2. Show tenants houses
  3. Sign the contract
  4. Collect the rent

But what if you’re a landlord and have other chores in your life? Then can you give the unimportant and not the core link to the intermediary (agent) to do? For example: release rental information and show tenants. It is ok to leave these two things to the intermediary. We can deal with our own affairs by ourselves, and we can go through important procedures, such as signing contracts and collecting rent, by contacting tenants well.

8.3 Creating a Service Interface and Implementation Class

Create Service interfaces and implementation classes to simulate the application scenario of dynamic proxies

package com.mylifes1110.service;

public interface LandlordService {
    void rent(a);

package com.mylifes1110.service.impl;

import com.mylifes1110.service.LandlordService;

public class LandlordServiceImpl implements LandlordService {
    public void rent(a) {
        System.out.println("Sign a contract");
        System.out.println("Payment"); }}Copy the code

8.4 Static Proxy

The following is the static proxy design pattern to solve the proxy problem

  • Static proxy process, create a proxy class and implement the same interface, create the implementation class object, add auxiliary functions in the proxy class and call the core method of the implementation class object, make the auxiliary functions and core method trigger together, complete the proxy
  • Static proxy problems
    • As the number of helper functions increases, so does the number of proxy classes, resulting in an excessive number of proxy classes, which is not conducive to project management.
    • The auxiliary function code of multiple proxy classes is redundant, and when modified, the maintainability is poor.
Static agent

Create a static proxy class

package com.mylifes1110.advice1;

import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;

/ * * *@ClassName Proxy
 * @DescriptionStatic proxy class *@Author Ziph
 * @Date 2020/7/19
 * @Since 1.8
 * @Version1.0 * /

public class Proxy implements LandlordService {
    private LandlordService landlordService = new LandlordServiceImpl();

    public void rent(a) {
        // Proxy events
        System.out.println("Release the news.");
        System.out.println("Look at the house");
        // Core; }}Copy the code

Static proxy implementation

package com.mylifes1110.advice1;

import org.junit.Test;

public class ProxyTest {
    / * * *@MethodName proxyTest
     * @Param []
     * @DescriptionStatic proxy implementation *@Author Ziph
     * @Date2020/7/10 * /
    public void proxyTest(a) {
        new Proxy().rent();
    /** * Results: ** Release information * see the house * sign the contract * receive payment */
Copy the code

8.5 JDK and CGLIB selection

Spring base includes JDK proxy and Cglib proxy.

The basic rule is: the target business class uses a JDK proxy if it has an interface, and a CGLib proxy if it does not. If true: <aop:config proxy-target-class=”true”>, use the CGLIB proxy

class DefaultAopProxyFactory{
    // The JDK proxy and CGLib proxy selection rules are clearly defined in this method
    // The basic rule is: the target business class uses JDK proxies if it has interfaces, and CGLib proxies if it does not
    public AopProxy createAopProxy(a){...}
Copy the code

8.6 JDK Dynamic Proxy

JDK dynamic proxies are implemented at the bottom of the JDK based on interfaces, which means we must implement JDK dynamic proxies interfaces and override methods to do this

package com.mylifes1110.advice2;

import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
import org.junit.Test;

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

public class ProxyTest {
    / * * *@MethodName proxyTest
     * @Param []
     * @DescriptionJDK dynamic proxy implementation *@Author Ziph
     * @Date2020/7/10 * /
    public void proxyTest(a) {
        // The target that needs to use the proxy
        LandlordService landlordService = new LandlordServiceImpl();
        // Anonymous inner class
        InvocationHandler handler = new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // Proxy events
                System.out.println("Release the news.");
                System.out.println("Look at the house");
                returnmethod.invoke(landlordService, args); }};// Dynamically build the proxy class
        LandlordService proxy = (LandlordService) Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),

        /** * Results: ** Release information * see the house * sign the contract * receive payment */}}Copy the code

8.7 CGLIB Dynamic Proxy

CGLIB dynamic proxies are implemented under Spring based on inherited superclasses, which means we must do this by inheriting the specified superclass and overriding its methods

package com.mylifes1110.advice3;

import com.mylifes1110.service.LandlordService;
import com.mylifes1110.service.impl.LandlordServiceImpl;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler;

import java.lang.reflect.Method;

/ * * *@ClassName ProxyTest
 * @DescriptionCGLIB dynamic proxy implementation *@Author Ziph
 * @Date 2020/7/19
 * @Since 1.8
 * @Version1.0 * /

public class ProxyTest {
    public static void main(String[] args) {
        final LandlordService landlordService = new LandlordServiceImpl();
        // Create a bytecode enhancement object
        Enhancer enhancer = new Enhancer();
        // Set the parent class (equivalent to implementing the primitive class interface)
        // Set the callback function (extra function code)
        enhancer.setCallback(new InvocationHandler() {
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                // Proxy events
                System.out.println("Release the news.");
                System.out.println("Look at the house");
                Object ret = method.invoke(landlordService, args);
                returnret; }});// Create a dynamic proxy class
        LandlordService proxy = (LandlordService) enhancer.create();;
        /** * Results: ** Release information * see the house * sign the contract * receive payment */}}Copy the code

9. Rear processor

9.1 Post-processor understanding

  • Many post-processors are defined in Spring;
  • Before each bean is created, there will bea post-processing process, namely reprocessing, to make relevant changes and adjustments to the bean;
  • In Spring-AOP, there is a specialized post-processor that is responsible for reprocessing a proxy component from the original business component (Service).
Common post processor

9.2 Defining a post-processor

/** * After the bean is created, it reprocesses the bean */
public class MyBeanPostProcessor implements BeanPostProcessor{

    /** * is executed before the bean's init method@paramBean The original bean object *@param beanName
     * @return
     * @throws BeansException
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Post-processor executes before init" + bean.getClass());
        return bean;
	/** * executes after the bean's init method@paramThe bean bean postProcessBeforeInitialization back *@param beanName
     * @return
     * @throws BeansException
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Post-processor executes after init ~~~" + bean.getClass());
        return bean;// The return here is the final return value of getBean()}}Copy the code

9.3 Configuring cpus

<! - processor after configuration, will all the bean declaration in the cycle to the factory to intervene - > < bean class = "com. Mylifes1110. Beanpostprocessor. MyBeanPostProcessor" > < / bean >Copy the code

9.4 Bean life cycle

Create Bean object -> Constructor -> Setter method to inject properties, satisfy dependencies -> post-processor pre-procedure -> Init initialization -> post-processor post-procedure -> Build complete -> Destroy

9.5 Dynamic Proxy source Code (Understanding)

/ / AbstractAutoProxyCreator AspectJAwareAdvisorAutoProxyCreator parent / / the handler class after wrapIfNecessary method in the dynamic proxy generation process AbstractAutoProxyCreator#postProcessAfterInitialization(Object bean, String beanName){ if (! This. EarlyProxyReferences. The contains (cacheKey)) {/ / dynamic custom agent return wrapIfNecessary (bean, beanName cacheKey); }}Copy the code