代理模式

代理模式,使用代理对象来代替对真实对象(real object)的访问,
这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

代理模式的主要作用是扩展目标对象的功能。

代理模式主要分为2种:

  1. 静态代理
  2. 动态代理
  3. JDK 动态代理
  4. CGLIB 动态代理
1
2
# 以下编码运行环境:
JDK17

静态代理

静态代理,是对目标对象的每个方法都手动编码加上增强功能的一种方式。

🌰 举例子,实现步骤:

  1. 定义Animal接口,一个实现该接口的Cat类。
  2. 创建一个同样实现该接口的代理类,这里用了匿名内部类, 重写所有抽象方法
    以及增强的功能,规定传参类型,封装成工具类(ProxyUtil)。
  3. 调用代理工具类,传入目标对象参数(new Cat())。Done!

Animal 接口

1
2
3
4
5
6
// 动物
public interface Animal {
default void eat() {
System.out.println("Animal eat");
}
}

Cat 目标类

1
2
3
4
5
6
7
8
9
10
11
// 猫
public class Cat implements Animal {

public Cat() {
}

@Override
public void eat() {
System.out.println("猫吃鱼");
}
}

ProxyUtil 代理工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 代理工具类
class ProxyUtil {
public static Animal staticProxy(Animal obj) {
return new Animal() {
@Override
public void eat() {
System.out.println("proxy eat start");
obj.eat();
System.out.println("proxy eat end");
}
};
}
}

测试:

1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Animal animal = ProxyUtil.staticProxy(new Cat());
animal.eat();
System.out.println("----------------");
}
}

说明

静态代理,实现简单,但是需要手动给每一个目标类和每一个方法加上增强功能部分,
实在麻烦!😓

动态代理

动态代理,相比静态代理则更加灵活,不需要一个个手动添加增强功能。

JVM 角度, 动态代理是运行时动态生成字节码并加载到JVM中。

JDK 动态代理

主要依赖JDKjava.lang.reflect.Proxy类,Proxy.newProxyInstance()方法

newProxyInstance方法有3个参数:

  1. ClassLoader loader, 目标对象的类加载器
  2. Class<?>[] interfaces, 目标对象实现的接口数组
  3. InvocationHandler h, 需要自定义实现,重写该接口中的invoke方法(增强功能部分)

🌰举例子,实现步骤

  1. 定义Animal接口,一个实现该接口的Cat类。同上Animal 接口
  2. 使用Proxy.newProxyInstance()方法创建代理对象,InvocationHandler 参数
    使用匿名内部类, 重写invoke方法添加增强功能,规定传参类型,
    封装成工具类(ProxyUtil)。
  3. 调用代理工具类,传入目标对象参数(Cat.class)。Done!

ProxyUtil 代理工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 代理工具类
class ProxyUtil {
public static <T> T jdk(Class<T> clz) {
Object object = Proxy.newProxyInstance(
clz.getClassLoader(),
clz.getInterfaces(),
(proxy, method, args) -> {
System.out.println("jdk proxy start");
// 使用newInstance方法
Object res = method.invoke(clz.getDeclaredConstructor().newInstance(), args);
System.out.println("jdk proxy end");
return res;
});

return (T) object;
}
}

测试:

1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Animal o2 = ProxyUtil.jdk(Cat.class);
o2.eat();
System.out.println("----------------");
}
}

说明

JDK动态代理,查看源码得知,其实是生成一个继承Proxy类实现传入目标对象接口的代理子类,通过自定义InvocationHandler
拓展接口方法功能的方式。

JDK动态代理,只能代理实现了接口的类。

CGLIB 动态代理

主要依赖CGLIB库中,Enhancer.create()方法。

create方法有2个参数:

  1. Class type, 目标对象Class类型
  2. Callback callback, 需要自定义实现,实现intercept方法(增强功能部分)

🌰举例子,实现步骤

  1. 定义Animal接口,一个实现该接口的Cat类。同上Animal 接口
  2. 使用Enhancer.create()方法创建代理对象,Callback 参数使用匿名内部类,
    重写intercept方法添加增强功能,规定传参类型, 封装成工具类(ProxyUtil)。
  3. 调用代理工具类,传入目标对象参数(Cat.class)。Done!

ProxyUtil 代理工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 代理工具类
class ProxyUtil {
public static <T> T cglib(Class<T> clz) {
Object object = Enhancer.create(clz,
(MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("cglib proxy start " + method.getName());
// 使用invokeSuper方法
Object res = proxy.invokeSuper(obj, args);
System.out.println("cglib proxy end " + method.getName());
return res;
});

return (T) object;
}
}

测试:

1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Animal o5 = ProxyUtil.cglib(Cat.class);
o5.eat();
System.out.println("----------------");
}
}

说明

CGLIB动态代理,是通过生成一个目标对象的子类,对方法调用进行拦截。

CGLIB动态代理,可以代理类(甚至抽象类),不管该类是否实现接口。