Java 代理模式

代理模式为某一个对象(委托类)提供一个代理(代理类),用来控制这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤、将请求的分配给指定对象。

代理模式的两个设计原则

  1. 代理类于委托类具有相似的行为
  2. 代理类增强委托类的行为

代理的三要素

  1. 有共同的行为 — 接口
  2. 目标角色 — 委托类,实现接口
  3. 代理角色 — 代理类,增加委托类的行为

静态代理

静态代理的特点

  • 目标角色固定
  • 在应用程序执行之前就得到了目标角色
  • 代理对象会增强目标对象的行为
  • 有可能存在多个代理,引起 “类爆炸”(缺点)

代码实现

共同的父接口
1
2
3
4
5
6
package org.example.house;

// 共同的接口
public interface IRentHouse {
void toRentHouse();
}
委托类
1
2
3
4
5
6
7
8
package org.example.house;

public class RentHouseImpl implements IRentHouse{
@Override
public void toRentHouse() {
System.out.println("租房...");
}
}
代理类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package org.example.house;

public class RentProxy implements IRentHouse{
private IRentHouse rentHouse;

// 构造函数传入委托对象
public RentProxy(IRentHouse rentHouse) {
this.rentHouse = rentHouse;
}

@Override
public void toRentHouse() {
// 扩展的行为
System.out.println("看房子...");
System.out.println("签署合同...");

// 调用委托对象方法
this.rentHouse.toRentHouse();

// 扩展的行为
System.out.println("售后服务...");
}
}
测试,执行代理方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package org.example;

import org.example.house.IRentHouse;
import org.example.house.RentHouseImpl;
import org.example.house.RentProxy;

public class App
{
public static void main( String[] args )
{
// 目标对象,委托对象
IRentHouse rentHouse = new RentHouseImpl();

// 代理对象
RentProxy rentProxy = new RentProxy(rentHouse);

rentProxy.toRentHouse();
}
}

动态代理

相比于静态代理,动态代理在创建代理对象上更加灵活,动态代理类的字节码在程序运行时,由Java反射机制动态生成。

动态代理的特点

  • 目标对象(实现类)不固定
  • 在应用程序执行时动态创建目标对象
  • 代理对象会增强目标对象的行为

JDK 动态代理

JDK 动态代理的目标对象必须有接口实现,没有接口实现的类不能使用JDK动态代理。

JDK动态代理核心是使用 Proxy 代理类的 newProxyInstance 方法生成代理。

1
public static Object newProxyInstance(ClassLoader loader, Class<T>[] interfaces, InvocationHandler h)
  • 返回值:代理对象。
  • loader:类加载器,定义了由哪些ClassLoader对象来对生成的代理对象进行加载
  • interfaces: 一组目标对象和代理对象需要实现的接口
  • h:回调接口,代理执行后调用的回调接口,构造器需要传递一个目标对象(委托对象),Invoke方法实现代理方法。

Jdk动态代理的实现过程

目标接口

  1. 创建目标类(委托类)的接口
租房接口
1
2
3
4
5
6
package org.example.house;

// 共同的接口
public interface IRentHouse {
void toRentHouse();
}

目标类(委托类)

  1. 创建目标类(委托类),实现接口 IRentHouse
1
2
3
4
5
6
7
8
package org.example.house;

public class RentHouseImpl implements IRentHouse{
@Override
public void toRentHouse() {
System.out.println("租房...");
}
}

代理工厂

  1. 创建代理工厂,用来创建代理对象,相比静态代理,这里不再需要创建指定目标类(委托类)的代理类了。

方法一 创建 InvocationHandler 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package org.example.dynamic;

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

/**
* 代理工厂
*/
public class JdkProxyFactory{
// 目标对象
private Object target;

// 构造器传递目标对象
public JdkProxyFactory(Object target) {
this.target = target;
}

// 获取目标对象的代理对象
public Object getProxy(){

// 通过调用 Proxy代理类中的静态方法 newProxyInstance 得到代理类

// 获取类加载器
ClassLoader classLoader = this.getClass().getClassLoader();

// 获取代理对象的接口
Class[] interfaces = target.getClass().getInterfaces();

// InvocationHandler 接口
// 也可以通过代理工厂实现 InvocationHandler 接口的方式,那么 newProxyInstance 的三个参数就是 this
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* 当代理对象方法时,invoke方法就会执行,可以在 invoke方法中实现代理方法(目标对象的行为增强)
* @param proxy 代理对象
* @param method 目标方法
* @param args 目标方法所需要的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("看房子...");
System.out.println("签署合同...");

// 调用目标对象的方法,通过反射中提供的 invoke 调用目标对象的方法
Object result = method.invoke(target, args);

System.out.println("售后服务...");

return result;
}
};

// 调用方法,得到代理对象
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}

方法二 代理工厂实现 InvocationHandler 接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package org.example.dynamic;

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

// 实现InvocationHandler接口的代理工厂
public class JdkProxyFactoryHandler implements InvocationHandler {
// 目标对象
private Object target;

// 构造器传递目标对象
public JdkProxyFactoryHandler(Object target) {
this.target = target;
}

// 获取目标对象的代理对象
public Object getProxy(){

// 通过调用 Proxy代理类中的静态方法 newProxyInstance 得到代理类

// 获取类加载器
ClassLoader classLoader = this.getClass().getClassLoader();

// 获取代理对象的接口
Class[] interfaces = target.getClass().getInterfaces();

// InvocationHandler 接口
// 也可以通过代理工厂实现 InvocationHandler 接口的方式,那么 newProxyInstance 的三个参数就是 this
InvocationHandler invocationHandler = this;

// 调用方法,得到代理对象
Object proxy = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("看房子...");
System.out.println("签署合同...");

// 调用目标对象的方法,通过反射中提供的 invoke 调用目标对象的方法
Object result = method.invoke(target, args);

System.out.println("售后服务...");

return result;
}
}

创建代理

  1. 使用代理工厂创建代理,执行代理任务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.example;

import org.example.dynamic.JdkProxyFactory;
import org.example.house.IRentHouse;
import org.example.house.RentHouseImpl;

public class Starter {

public static void main(String[] args) {
// 创建目标对象
IRentHouse rentHouse = new RentHouseImpl();

// 创建代理工厂
JdkProxyFactory jdkProxyFactory = new JdkProxyFactory(rentHouse);

// 获取代理对象
IRentHouse proxy = (IRentHouse) jdkProxyFactory.getProxy();

// 通过代理对象调用方法
proxy.toRentHouse();
}
}

执行结果如图

CGLIB 动态代理

cblib是针对类来实现代理的,可以在没有目标接口的情况下动态生成代理。它的原理是对指定的目标类生成一个子类,并覆盖其中的方法来实现行为增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理。

引入依赖包 cglib

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

代理工厂

方法一 创建 MethodInterceptor 实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package org.example.dynamic;

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

import java.lang.reflect.Method;

/**
* Cglib动态代理工厂
*/
public class CglibProxyFactory {
// 目标对象
private Object target;

// 通过构造函数传入目标对象
public CglibProxyFactory(Object target) {
this.target = target;
}

// 获取代理对象
public Object getProxy(){
// 创建 Enhancer 对象,可以通过它的 create 方法创建一个代理对象
Enhancer enhancer = new Enhancer();

// 设置父类,将目标类作为代理类的父类
enhancer.setSuperclass(target.getClass());

// 定义方法拦截器
MethodInterceptor methodInterceptor = new MethodInterceptor() {
/**
* 当调用代理对象方法时, intercept 方法就会被执行
* @param o 由Cglib动态生成的代理类实例
* @param method 目标方法,(代理调用的目标方法)
* @param objects 目标方法的参数值列表
* @param methodProxy 代理对象对目标方法的引用
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("看房子...");
System.out.println("签署合同...");

// 调用目标方法
Object result = method.invoke(target, objects);
// 也可以使用 methodProxy 掉用目标方法
// Object result = methodProxy.invoke(target, objects);

System.out.println("售后服务...");

return result;
}
};
// 设置代理过程 (调用目标对象的方法,增强目标对象的方法)
enhancer.setCallback(methodInterceptor);

// 创建代理对象并返回
return enhancer.create();
}
}

方法二 实现 MethodInterceptor 接口的Cglib代理工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package org.example.dynamic;

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

import java.lang.reflect.Method;

// 实现 MethodInterceptor 接口的Cglib代理工厂
public class CglibProxyFactoryHandler implements MethodInterceptor {
// 目标对象
private Object target;

// 通过构造函数传入目标对象
public CglibProxyFactoryHandler(Object target) {
this.target = target;
}

// 获取代理对象
public Object getProxy(){
// 创建 Enhancer 对象,可以通过它的 create 方法创建一个代理对象
Enhancer enhancer = new Enhancer();

// 设置父类,将目标类作为代理类的父类
enhancer.setSuperclass(target.getClass());

// 定义方法拦截器
MethodInterceptor methodInterceptor = this;

// 设置代理过程 (调用目标对象的方法,增强目标对象的方法)
enhancer.setCallback(methodInterceptor);

// 创建代理对象并返回
return enhancer.create();
}

@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("看房子...");
System.out.println("签署合同...");

// 调用目标方法
Object result = method.invoke(target, objects);
// 也可以使用 methodProxy 掉用目标方法
// Object result = methodProxy.invoke(target, objects);

System.out.println("售后服务...");

return result;
}
}

创建代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package org.example;

import org.example.dynamic.CglibProxyFactory;
import org.example.dynamic.JdkProxyFactory;
import org.example.house.IRentHouse;
import org.example.house.RentHouseImpl;

public class CglibStarter {
public static void main(String[] args) {
// 创建目标对象
RentHouseImpl rentHouse = new RentHouseImpl();

// 创建代理工厂
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(rentHouse);

// 获取代理对象
RentHouseImpl proxy = (RentHouseImpl) cglibProxyFactory.getProxy();

// 通过代理对象调用方法
proxy.toRentHouse();
}
}