Spring Aop underlying responsibility chain idea implementation

Hands-on AOP responsibility chain implementation

A brief introduction to AOP

One of Spring's two important features, AOP, is aspect-oriented programming.

image-20230204155405588

Its function is simply that decoupling can be achieved through proxy classes to achieve functional enhancement without changing the code of the class itself. Understanding what it can do we can think about how to implement it. Here Involves the chain of responsibility model (more on that later).

To implement simple aop we must at least do:

  • has target class
  • Dynamic proxy target class
  • Custom notification method

Before implementing aop, we need to briefly review some prerequisite knowledge and confirm the dependencies and versions used before reviewing to avoid unexpected bugs in the demo.

Java version: 1.8

Maven version: 3.6.x

rely

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.6.RELEASE</version>
    </dependency>

Dynamic proxy (proxy target class)

To understand agents, we need to review the knowledge about agents.

At present, there are two types of agents. Static agents and dynamic agents can be easily described in words.

  • Static proxies can implement proxies but are limited to abstract classes and cannot proxy objects other than abstract classes.
  • Dynamic proxy relies on the reflection mechanism to implement proxy for any class

Create target class

We will use Userservice as our proxy target class

public class UserService {
    
    
    
    public Object insert  ()
    {
    
    
        System.out.println("==插入用户成功==");
        return "user insert ok";
    }
    
}

Create a proxy factory

Here we use cglib as a dynamic proxy. In fact, by implementing the support class of dynamic proxy, we can achieve simple aop enhancement.

Code examples

public class ProxyFactory implements MethodInterceptor {
    
    
    private Object target;

    public UserService getProxy(Object target){
    
    
        //被代理对象
        this.target = target;
        //cglib 生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(target.getClass().getClassLoader());
        //生成代理对象
        return (UserService)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        //执行目标方法
        Object result = null;

        try {
    
    
            //前置通知
            System.out.println("前置通知");
             result = method.invoke(target, objects);

            //    返回通知
            System.out.println("返回通知");
        } catch (Throwable e) {
    
    
            //异常通知
            System.out.println("异常通知");
            throw new RuntimeException(e);
        } finally {
    
    
        //    后置通知
            System.out.println("后置通知");
        }

        return result;
    }
}

test
public class Run {
    
    
    public static void main(String[] args) {
    
    
        UserService userService = new UserService();
        userService.insert();
        UserService userService1 = new ProxyFactory().getProxy(userService);
        userService1.insert();

    }
}

image-20230204163324899

As long as we add code in the place marked with comments, is it a simple aspect enhancement? At this time, there will be a question that needs to be thought about. Think about the AOP we use in Spring, in the case of labeling aspects and enhancing annotations. , Spring helps us achieve aspect enhancement.

So this is just the beginning. What is the purpose of decoupling when we use AOP? If we want to write the above case like this, wouldn't it be deceiving others? This class decouples the agent factory and the coupling is high, which does not achieve the effect at all. So next we are going to solve this problem

  • Provide flexibility
  • decoupling
  • Can we use design patterns to solve problems?

chain of responsibility model

We hope to use design patterns to increase the flexibility of our own demoAOP. Here is a brief introduction to the chain of responsibility model.

In order to avoid the request sender being coupled with multiple request handlers, all request handlers are connected in a chain by remembering the reference of the next object through the previous object; when a request occurs, the request can be linked along the This chain is passed until an object handles it.

PS: Recursion

image-20230204164417938

So what is the structure of our implementation of the chain of responsibility model?

image-20230204164549365

Here we implement pre-enhancement to demonstrate the idea of ​​getting started with the chain of responsibility model.

chain of responsibility

We use recursion to make continuous calls to notifications

public class Chian {
    
    

    //记录index下标
    private int index=  -1;
    private List<BaseAdvice> adviceList;

    public Chian(List<BaseAdvice> adviceList) {
    
    
        this.adviceList = adviceList;
    }

    public Object proeccd() throws Throwable{
    
    
        if(index == adviceList.size()-1){
    
    
            System.out.println("==执行目标方法==");
            return null;
        }
        return  adviceList.get(++index).execute(this);
    }
}

Enhanced notification base class

public abstract class BaseAdvice {
    
    

    public abstract Object execute(Chian chian) throws Throwable;

}

Pre-enhancement class

public class BeforeAdvice extends BaseAdvice{
    
    
    @Override
    public Object execute(Chian chian) throws Throwable {
    
    
        /*
        * 只做逻辑增强
        * 如果还有继续调用链的下一个通知
        * */
        System.out.println("前置通知");
        //调用链通知
        return   chian.proeccd();
    }
}

test

public static void main(String[] args) throws Throwable {
    
    
     List<BaseAdvice> adviceList = new ArrayList<>();
    adviceList.add(new BeforeAdvice());
    Chian chian = new Chian(adviceList);
    chian.proeccd();
}

image-20230204170548913

It can be seen that the results are consistent with the results of the previous proxy method. Target decoupling is completed through chain calls + recursion and flexibility is increased.

Implement AOP

Enhanced implementation

The four enhancements do not implement surround enhancement here, because surround is equivalent to a combination of other enhancements.

base class

public abstract class BaseAdvice {
    
    

    public abstract Object execute(Chian chian) throws Throwable;

}

Four types of enhancements

Pre-enhancement

public class BeforeAdvice extends BaseAdvice{
    
    
    @Override
    public Object execute(Chian chian) throws Throwable {
    
    
        /*
        * 只做逻辑增强
        * 如果还有继续调用链的下一个通知
        * */
        System.out.println("前置通知(责任链)");
        //调用链通知
        return   chian.proeccd();
    }
}

post enhancement

public class AfterAdvice extends BaseAdvice{
    
    
    @Override
    public Object execute(Chian chian) throws Throwable {
    
    

        try {
    
    
            return chian.proeccd();
        } finally {
    
    
            System.out.println("后置增强");
        }
    }
}

Exception handling enhancement

public  class ThrowAdvice extends  BaseAdvice{
    
    
    @Override
    public Object execute(Chian chian) throws Throwable {
    
    
        try {
    
    
            return chian.proeccd();
        } catch (Throwable e) {
    
    
            System.out.println("异常通知");
            throw new RuntimeException(e);
        }

    }
}

Return to processing enhanced notifications

public class ReturnAdvice extends BaseAdvice{
    
    
    @Override
    public Object execute(Chian chian) throws Throwable {
    
    
        //如果没有异常就走返回通知
        Object value = chian.proeccd();
        System.out.println("返回通知");
            return value;
    }
}

Responsibility chain implementation

Use linked list + recursion to implement the chain of responsibility, and use the characteristics of the linked list data structure to enhance node adjustment point execution.

public class Chian {
    
    

    //记录index下标
    private int index=  -1;
    private List<BaseAdvice> adviceList;

    //目标方法
    private Method method;

    //方法参数
    private  Object[] args;
    //目标对象
    private  Object target;

    public Chian(List<BaseAdvice> adviceList) {
    
    
        this.adviceList = adviceList;
    }

    public Chian(List<BaseAdvice> adviceList, Method method, Object[] args, Object target) {
    
    
        this.adviceList = adviceList;
        this.method = method;
        this.args = args;
        this.target = target;
    }

    public Object proeccd() throws Throwable{
    
    
        if(index == adviceList.size()-1){
    
    
            return method.invoke(args,target);
        }
        return  adviceList.get(++index).execute(this);
    }
}

Agent class implementation

public class ProxyFactoryAddChian implements MethodInterceptor {
    
    
    private Object target;
    private List<BaseAdvice> adviceList;

    public ProxyFactoryAddChian() {
    
    
        adviceList = new ArrayList<>();
        adviceList.add(new BeforeAdvice());
        adviceList.add(new ReturnAdvice());
        adviceList.add(new AfterAdvice());
        adviceList.add(new ThrowAdvice());
    }

    public UserService getProxy(Object target){
    
    
        //被代理对象
        this.target = target;
        //cglib 生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调
        enhancer.setCallback(this);
        //设置类加载器
        enhancer.setClassLoader(target.getClass().getClassLoader());
        //生成代理对象
        return (UserService)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    
    
        //在生产代理的时候就把链设置好
        Chian chian = new Chian(adviceList,method,objects,target);
        return chian.proeccd();
    }
}

test

public class Run {
    
    
    public static void main(String[] args) throws Throwable {
    
    
        UserService userService = new UserService();
        //userService.insert();
        UserService userService1 = new ProxyFactoryAddChian().getProxy(userService);
        userService1.insert("编程导航小冷Demo");
    }
}

image-20230204195338199

Summarize

To achieve enhanced functions, we just need to replace the positions of the output statements with the code we want to implement. It may seem a bit doubtful. This is not exactly like spring's AOP. That is because part of AOP involves IOC. But it’s a coincidence that we have implemented ioc before

If this series is updated well, you can try to make a small Spring later. Read the spring source code with Xiao Leng and think about how to implement it with your own ideas.

So what did we learn from this hands-on chain of responsibility practice?

  • Application of chain of responsibility model
  • Use of recursion
  • Learn the ideas of excellent framework source code
  • Get a half-finished aopdemo

I hope everyone can continue to read Xiao Leng’s technical articles and make progress together. Your viewing can give Xiao Leng great encouragement.

Thank you for watching, please look forward to the next article

Guess you like

Origin blog.csdn.net/doomwatcher/article/details/128885072