介绍

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

代理模式

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

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

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

注意事项:

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

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

代理模式 Java 实现 - 图1

静态代理

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

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

  1. // 接口 A
  2. public interface IServiceA {
  3. void sayHello(String str);
  4. }
  5. // ServiceAImpl 实现接口 A
  6. public class ServiceAImpl implements IServiceA {
  7. @Override
  8. public void sayHello(String str) {
  9. System.out.println(str);
  10. }
  11. }
  12. // 代理对象 ServiceProxyAImpl 也实现接口 A,并且构造函数必须传入接口 A 的实例
  13. public class ServiceProxyAImpl implements IServiceA {
  14. private IServiceA iServiceA;
  15. public ServiceProxyAImpl(IServiceA iServiceA) {
  16. this.iServiceA = iServiceA;
  17. }
  18. @Override
  19. public void sayHello(String str) {
  20. iServiceA.sayHello(str+ " is proxy ");
  21. }
  22. }
  23. // 进行测试
  24. public class Main {
  25. public static void main(String[] args) {
  26. IServiceA realA = new ServiceAImpl();
  27. // 传入真实对象
  28. IServiceA proxyA = new ServiceProxyAImpl(realA);
  29. realA.sayHello("realA");
  30. // 代理对象的调用
  31. proxyA.sayHello("proxyA");
  32. }
  33. }
  34. 程序输出 :
  35. ServiceAImpl sayrealA
  36. ServiceAImpl sayproxyA is proxy

动态代理

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

JDK 动态代理

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

  1. java.lang.reflect.Proxy:生成动态代理类和对象;
  2. java.lang.reflect.InvocationHandler:通过 invoke 方法实现对真实角色的代理访问。
  1. // 接口 A
  2. public interface IServiceA {
  3. void sayHello(String str);
  4. }
  5. // ServiceAImpl 实现接口 A
  6. public class ServiceAImpl implements IServiceA {
  7. @Override
  8. public void sayHello(String str) {
  9. System.out.println(str);
  10. }
  11. }
  12. public class ProxyHandler implements InvocationHandler {
  13. private IServiceA serviceA;
  14. public ProxyHandler(IServiceA serviceA) {
  15. this.serviceA = serviceA;
  16. }
  17. @Override
  18. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  19. return method.invoke(serviceA, args);
  20. }
  21. }
  22. public class MainProxy {
  23. public static void main(String[] args) {
  24. // 真实对象
  25. IServiceA serviceA = new ServiceAImpl();
  26. // 通过 Proxy 得到代理对象
  27. IServiceA proxyServiceA = (IServiceA) Proxy
  28. .newProxyInstance(serviceA.getClass().getClassLoader(), serviceA.getClass().getInterfaces(),
  29. new ProxyHandler(serviceA));
  30. serviceA.sayHello("serviceA");
  31. proxyServiceA.sayHello("proxy serviceA");
  32. }
  33. }
  34. 程序输出:
  35. serviceA
  36. proxy serviceA

CGLIB 动态代理

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

  1. 首先实现 MethodInterceptor,方法调用会被转发到该类的 intercept() 方法。
  2. 通过 Enhancer 来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用 create() 方法得到代理对象
  1. // 接口 A
  2. public interface IServiceA {
  3. void sayHello(String str);
  4. }
  5. // ServiceAImpl 实现接口 A
  6. public class ServiceAImpl implements IServiceA {
  7. @Override
  8. public void sayHello(String str) {
  9. System.out.println(str);
  10. }
  11. }
  12. public class MyMethodInterceptor implements MethodInterceptor {
  13. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
  14. return methodProxy.invokeSuper(o,objects);
  15. }
  16. }
  17. public class CGLIBMain {
  18. public static void main(String[] args) {
  19. IServiceA serviceA = new ServiceAImpl();
  20. serviceA.sayHello("serviceA");
  21. Enhancer enhancer = new Enhancer(); // 字节码增强
  22. enhancer.setSuperclass(ServiceAImpl.class); // 设置父类
  23. enhancer.setCallback(new MyMethodInterceptor()); // 设置回调方法
  24. IServiceA proxyA = (IServiceA) enhancer.create();
  25. proxyA.sayHello("proxyA");
  26. }
  27. }
  28. 程序输出:
  29. serviceA
  30. proxyA