代理模式 Java 实现

介绍

  • 什么是代理模式
  • 静态代理
  • JDK 自带的动态代理
  • CGLIB 动态代理

代理模式

意图:为其他对象提供一种代理,以控制对这个对象的访问。

例子:买火车票不一定要在火车站,去网上各个代理商那里也可以

代码思路:实体类 A 实现了接口 IA,而实体类 A 很复杂,那么使用实体类 B 去实现接口 IA,通过实体类 B 调用实体类 A 去满足功能。

注意事项:

1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

upload successful

静态代理

静态代理其实就是在程序运行之前,提前写好被代理方法的代理类,编译后运行。

下面代理模式实现需要写很多代码,不建议使用。

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
// 接口 A
public interface IServiceA {
void sayHello(String str);
}

// ServiceAImpl 实现接口 A
public class ServiceAImpl implements IServiceA {

@Override
public void sayHello(String str) {
System.out.println(str);
}
}

// 代理对象 ServiceProxyAImpl 也实现接口 A,并且构造函数必须传入接口 A 的实例
public class ServiceProxyAImpl implements IServiceA {
private IServiceA iServiceA;
public ServiceProxyAImpl(IServiceA iServiceA) {
this.iServiceA = iServiceA;
}
@Override
public void sayHello(String str) {
iServiceA.sayHello(str+ " is proxy ");
}
}

// 进行测试
public class Main {
public static void main(String[] args) {
IServiceA realA = new ServiceAImpl();
       // 传入真实对象
       IServiceA proxyA = new ServiceProxyAImpl(realA);
realA.sayHello("realA");
       // 代理对象的调用
       proxyA.sayHello("proxyA");
}
}

程序输出 :
ServiceAImpl sayrealA
ServiceAImpl sayproxyA is proxy

动态代理

通过反射机制,在运行时生成代理类

JDK 动态代理

被代理的类需要是接口实现,如果被代理的类没有实现接口,就不能使用 JDK 动态代理

  1. java.lang.reflect.Proxy:生成动态代理类和对象;
  2. java.lang.reflect.InvocationHandler:通过 invoke 方法实现对真实角色的代理访问。
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
// 接口 A
public interface IServiceA {
void sayHello(String str);
}

// ServiceAImpl 实现接口 A
public class ServiceAImpl implements IServiceA {
@Override
public void sayHello(String str) {
System.out.println(str);
}
}

public class ProxyHandler implements InvocationHandler {
private IServiceA serviceA;
public ProxyHandler(IServiceA serviceA) {
this.serviceA = serviceA;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(serviceA, args);
}
}

public class MainProxy {
public static void main(String[] args) {
  // 真实对象
       IServiceA serviceA = new ServiceAImpl();
       // 通过 Proxy 得到代理对象
       IServiceA proxyServiceA = (IServiceA) Proxy
.newProxyInstance(serviceA.getClass().getClassLoader(), serviceA.getClass().getInterfaces(),
new ProxyHandler(serviceA));
serviceA.sayHello("serviceA");
proxyServiceA.sayHello("proxy serviceA");
}
}

程序输出:
serviceA
proxy serviceA

CGLIB 动态代理

通过改变字节码,对需要被代理的类,生成他的子类,子类去覆盖被代理类的方法,其中 private、final 修饰的方法不会被重写。

  1. 首先实现 MethodInterceptor,方法调用会被转发到该类的 intercept() 方法。
  2. 通过 Enhancer 来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用 create() 方法得到代理对象
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
// 接口 A
public interface IServiceA {
void sayHello(String str);
}

// ServiceAImpl 实现接口 A
public class ServiceAImpl implements IServiceA {
@Override
public void sayHello(String str) {
System.out.println(str);
}
}

public class MyMethodInterceptor implements MethodInterceptor {

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o,objects);
}
}

public class CGLIBMain {

public static void main(String[] args) {
IServiceA serviceA = new ServiceAImpl();
serviceA.sayHello("serviceA");

       Enhancer enhancer = new Enhancer(); // 字节码增强
       enhancer.setSuperclass(ServiceAImpl.class); // 设置父类
       enhancer.setCallback(new MyMethodInterceptor()); // 设置回调方法
       IServiceA proxyA = (IServiceA) enhancer.create();
proxyA.sayHello("proxyA");
}
}

程序输出:
serviceA
proxyA