Spring AOP实现原理

YangeIT大约 8 分钟SpringAOP设计模式AOP代理模式

Spring AOP实现原理

1. 代理模式

程序为什么要代理?

  • 说法1:原始对象如果觉得本类上的工作太多,可以通过代理来转移部分职责。
  • 说法2:如果不改原始类的代码的情况下,可以使用代理对原始对象的功能进行增强
  • 特点:原始对象的什么方法想被增强(被代理),代理类一定要有对应的方法。

代理模式UML 类图如下

image-20191011005747639
image-20191011005747639

类图中虚线箭头表示接口实现

菱形和箭头表示组合(组合:部分和整体的关系,并且生命周期是相同的。例如:人与手)

具体参考uml类图open in new window

代理类实现了被代理类的接口,同时与被代理类是组合关系。下面看一下代理模式的实现

2. 静态代理

例子

租客-中介-房主

代理这个词是来源于Java设计模式中的代理模式,代理模式最简单的理解就是通过第三方来代理我们的工作

比如中介,房东需要将自己的房子租出去,而租客需要租房子,三者关系如此

租客租房子一般都找不到房东,房东也不会轻易将自己暴露给广大租客,因此就需要中介来充当这个中间关系

因此租客就只能通过中介来进行租房子这个工作,不需要通过房东,这就叫做代理—-就是中介代理房东来处理租房子这件事情

open in new window

观众-中介-明显

比如大明星想唱歌,唱歌这个动作不光要明星参与,还要准备场地和音响,售票等动作,观众不会直接找明星唱歌,而是找中介公司组织的演唱会,三者关系如此

观众听歌一般都找不到明星,明星也不会轻易将自己暴露给广大观众面前,因此就需要中介来充当这个中间关系

因此观众就只能通过中介来进行听明星唱歌了,这就叫做代理—-就是中介代理明星来处理唱歌这件事情

代码实现:👇 👇

1️⃣ 接口类:

public interface Star {
    void sing();
}

3.动态代理

动态代理

动态代理 就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。 在生成代理对象的过程中,目标对象不变,代理对象中的方法是目标对象方法的增强方法。

可以理解为运行期间,对象中方法的动态拦截,在拦截方法的前后执行功能操作。 👈 🍐

  1. 代理类在程序运行期间创建的代理对象称之为动态代理对象。
  2. 这种情况下,创建的代理对象,并不是事先在Java代码中定义好的。而是在运行期间,根据我们在动态代理对象中的指示动态生成 实时生成,没有.class文件。 🍐

也就是说,你想获取哪个对象的代理,动态代理就会为你动态的生成这个对象的代理对象

有了动态代理的技术,那么就可以在不修改方法源码的情况下,增强被代理对象的方法的功能,在方法执行前后做任何你想做的事情。 🍐 ❤️

实现动态代理有2种方式:

  1. JDK自带方法
  2. CGLIB 库的方法

JDK和Cglib的区别:

CglibJDK
是否提供子类代理
是否提供接口代理是(可强制)
区别必须依赖于CGLib的类库,但是它需要类来实现任何接口代理的是指定的类生成一个子类,覆盖其中的方法实现InvocationHandler 使用Proxy.newProxyInstance产生代理对象 被代理的对象必须要实现接口

3.1 JDK自带方法

JDK自带代理

1️⃣ Proxy类的newProxyInstance方法

创建代理对象

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException

其中的参数含义如下:

  • loader: 被代理的类的类加载器
  • interfaces: 被代理类的接口数组
  • invocationHandler: 就是刚刚介绍的调用处理器类的对象实例

2️⃣ InvocationHandler接口是最核心的接口

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

我们对于被代理的类的操作都会由该接口中的invoke方法实现,其中的参数的含义分别是:

  • proxy :被代理的类的实例
  • method :调用被代理的类的方法
  • args :该方法需要的参数

使用方法 👇 👇

使用方法首先是需要实现该接口,并且我们可以在invoke方法中调用被代理类的方法并获得返回值,自然也可以在调用该方法的前后去做一些额外的事情,从而实现动态代理

下面是一个实际例子。

3.1.3 JDK自动代理实际例子

Star接口:

public interface Star {
    void dance();
}

3.2 CGLIB 库的方法

CGLIB代理

Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展

Cglib子类代理及详细解析open in new window

CGlibopen in new window是一个字节码增强库,为AOP等提供了底层支持。

CGLIB 是针对实现代理,主要是对指定的类生成一个子类,并覆盖其中方法实现增强,但是因为采用的是继承,所以该类或方法最好不要声明成 final,对于 final 类或方法,是无法继承的

案例:👇 👇

1️⃣ 新建一个maven项目,并引入cglib依赖:

导入依赖

 <dependency>
	   <groupId>cglib</groupId>
	   <artifactId>cglib</artifactId>
	   <version>3.1</version>
 </dependency>

4.参考文章

Spring AOP实现原理open in new window

趣析Java中的静态代理,JDK动态代理和cglib动态代理open in new window

CGLIB问题分析open in new window