Spring 5.x 源码解析之一文搞懂AOP基本原理

Spring 5.x 源码解析之一文搞懂AOP基本原理

  • AOP是什么
  • 简单的例子
    • 自定义代理
    • JDK动态代理
    • JDK动态代理增加拦截器
    • CGLib代理

AOP是什么

我不想讲很规范的定义,因为那只会增加我们对AOP学习的压力,一开始就来一堆名字定义,我是不是要去记这些概念才能理解AOP呢,其实不是,我想这些概念只不过是原理之后的规范而已,大家得统一一个规范,不然你说你的APO,我说我的AOP,不好理解,但是原理是通的,所以我会先用简单的问题一步步展现原理,没有什么名次概念,只有简单的,接口,方法,最多就是个动态代理。我们暂且把AOP就当做给我的方法增加点什么操作吧。

简单的例子

简单的例子,我们定义了一个接口,有一个实现类,一个测试类:

public interface MyServiceInterface {
     
    void doService();
}

public class MyServiceimp implements MyServiceInterface {
     
    public void doService() {
     
        System.out.println("========doService========");
    }
}

public class Test {
     
    public static void main(String[] args) {
     
        MyServiceInterface myService=new MyServiceimp();
        myService.doService();
    }
}

输出:
Spring 5.x 源码解析之一文搞懂AOP基本原理_第1张图片
这个最简单不过了吧,但是我们现在有新需求了,我想在执行的doService方法前后增加log日志显示,但是不能修改我的源码。本来想直接改源码不就得了,但是现在没办法,源码不让动,所以这个时候就会想那我重新弄个类,然后把他放进来,在他前后增加方法不就可以了,于是有了第二版的。

自定义代理

为了简单起见,我创建了一个新的类:

package proxy;

import aop.MyServiceInterface;

public class AopProxy1 implements MyServiceInterface {
     

    MyServiceInterface myServiceInterface;

    public void setMyServiceInterface(MyServiceInterface myServiceInterface) {
     
        this.myServiceInterface = myServiceInterface;
    }

    public void doService() {
     
        System.out.println("======doService之前=======");
        myServiceInterface.doService();
        System.out.println("======doService之后=======");
    }
}

然后测试:

package proxy;

import aop.MyServiceInterface;
import aop.MyServiceimp;

public class Test {
     
    public static void main(String[] args) {
     
        MyServiceInterface myServiceimp=new MyServiceimp();
        AopProxy1 aopProxy1=new AopProxy1();
        aopProxy1.setMyServiceInterface(myServiceimp);
        aopProxy1.doService();
    }
}

结果:
Spring 5.x 源码解析之一文搞懂AOP基本原理_第2张图片
貌似实现了我们要的东西。是的确实,而且我们用了一种代理的思想,对外服务的对象已经是代理对象了,代理对象对我们的真实对象的方法进行了扩展。但是问题又来了,如果我们有很多类,很多方法,每个方法都要扩展,那岂不是一个类要一个代理对象啦,有100个类,我还要重新写100个,而且基本都是重复性的劳动,有没有更好的实现方法呢?当然有,叫做动态代理,其实动态代理一般有两种,一种是JDK的,一种叫CGLIB,具体的区别可以百度下,简单说系就是JDK的是需要接口,用的是反射,而CGLIB可以是普通类,对字节码操作。

JDK动态代理

其实就是对我上面的这种做法做了增强,不需要每次都创建一个代理类,只需要创建通用动态代理类,把想代理的对象传进去,实现了InvocationHandler接口,原理是利用反射调用方法,具体可以看内部的源码,我这里只是做简单的使用:

package Proxy2;

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

public class JDKDynamicProxy implements InvocationHandler {
     

    Object target;

    public Object getProxy(Object target) {
     
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
        System.out.println("======JDKDynamicProxy 调用之前=======");
        method.invoke(this.target, args);
        System.out.println("======JDKDynamicProxy 调用之后=======");
        return null;
    }


}


package Proxy2;

import aop.MyServiceInterface;
import aop.MyServiceimp;

public class Test {
     
    public static void main(String[] args) {
     
        MyServiceInterface serviceInterface=new MyServiceimp();
        JDKDynamicProxy jdkDynamicProxy=new JDKDynamicProxy();
        MyServiceInterface proxy = (MyServiceInterface)jdkDynamicProxy.getProxy(serviceInterface);
        proxy.doService();

    }
}

Spring 5.x 源码解析之一文搞懂AOP基本原理_第3张图片
结果也是对的,当然只是很简单的例子,但是我发现不管我换什么类,调用前和调用后的log信息是一样的System.out.println("======JDKDynamicProxy 调用之前=======");这句话被写死在了里面,如果我想要不同的类做不同的事,那要怎么办呢,我当然希望这块可以提取出来,放在另一个接口里,只要在接口里定义两个方法,然后让实现类去实现,最后把实现类传到动态代理类里,好,那我们试试。

JDK动态代理增加拦截器

我们定义一个接口,叫做拦截器,简单就是说在我的方法前后拦截,就可以做扩展啦:

package Proxy3;

public interface Interceptor {
     
    void before();
    void after();

}

一个log的实现类

package Proxy3;

public class LogInterceptor implements Interceptor {
     
    public void before() {
     
        System.out.println("我只是在方法前打log");
    }

    public void after() {
     
        System.out.println("我只是在方法后打log");
    }
}

一个是时间的实现类:

package Proxy3;

public class TimeInterceptor implements Interceptor {
     
    public void before() {
     
        System.out.println("我是在方法前记录时间:");
    }

    public void after() {
     
        System.out.println("我是在方法后记录时间");
    }
}


动态代理增强类:

package Proxy3;

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

public class JDKDynamicProxyAdvanced implements InvocationHandler {
     

    Object target;

    Interceptor interceptor;

    public void setInterceptor(Interceptor interceptor) {
     
        this.interceptor = interceptor;
    }

    public Object getProxy(Object target, Interceptor interceptor) {
     
        this.interceptor=interceptor;
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     
        interceptor.before();
        method.invoke(this.target, args);
        interceptor.after();
        return null;
    }


}

测试类:

package Proxy3;

import aop.MyServiceInterface;
import aop.MyServiceimp;

public class Test {
     
    public static void main(String[] args) {
     
        MyServiceInterface serviceInterface = new MyServiceimp();
        JDKDynamicProxyAdvanced jDKDynamicProxyAdvanced = new JDKDynamicProxyAdvanced();
        MyServiceInterface proxy = (MyServiceInterface) jDKDynamicProxyAdvanced.getProxy(serviceInterface, new TimeInterceptor());
        proxy.doService();

        jDKDynamicProxyAdvanced.setInterceptor(new LogInterceptor());
        proxy.doService();
    }
}

结果:
Spring 5.x 源码解析之一文搞懂AOP基本原理_第4张图片

CGLib代理

package cglib;

import aop.MyServiceimp;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLibProxyAdvanced {
     
    public static void main(String[] args) {
     
        Enhancer enhancer = new Enhancer();

        enhancer.setSuperclass(MyServiceimp.class);

        enhancer.setCallback(new MethodInterceptor() {
     
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
     
                System.out.println("cglib 代理");
                methodProxy.invokeSuper(o,objects);
                return o;
            }
        });
        MyServiceimp service = (MyServiceimp) enhancer.create();
        service.doService();
    }
}

结果:
Spring 5.x 源码解析之一文搞懂AOP基本原理_第5张图片
貌似好像GCLib写起来简单点,也没有对扩展类有接口要求,不过这只是最简单的应用,具体其他的高级功能还要自己去研究GCLib啦。其实基本上AOP的简单原理就这些了,当然spring的AOP没那么简单啦,具体我后面会分析源码,本篇只是想介绍最基本的AOP,在不修修改源代码,没有侵入性的情况下对原方法进行扩展和增强。

Spring 5.x 源码解析之一文搞懂AOP基本原理_第6张图片
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵,部分图片来自网络,侵删。

你可能感兴趣的:(Spring,5.x,源码之旅,Spring,5.x,Spring,5.x,源码解析,一文搞懂AOP基本原理,AOP,Spring,5.x,源码解析AOP)