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

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();
    }
}

输出:
在这里插入图片描述
这个最简单不过了吧,但是我们现在有新需求了,我想在执行的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();
    }
}

结果:
在这里插入图片描述
貌似实现了我们要的东西。是的确实,而且我们用了一种代理的思想,对外服务的对象已经是代理对象了,代理对象对我们的真实对象的方法进行了扩展。但是问题又来了,如果我们有很多类,很多方法,每个方法都要扩展,那岂不是一个类要一个代理对象啦,有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();

    }
}

在这里插入图片描述
结果也是对的,当然只是很简单的例子,但是我发现不管我换什么类,调用前和调用后的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();
    }
}

结果:
在这里插入图片描述

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();
    }
}

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

在这里插入图片描述
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵,部分图片来自网络,侵删。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值