概述

在调用者和目标对象之间增加一个中介角色
调用者->中介商->目标对象

生活中介

租客->房屋中介->房东
求职者->招聘网站->公司
适龄男青年->媒婆->适龄女青年

为什么需要中间商转差价

1专业的人干专业的事情,被代理人只关注自己能力范围的事情
2 信息垄断隔绝,jar没有源码 需要对原来方法增强

代理三要素

  • 有共同的行为(方法) - 接口
  • 目标对象(被代理人) - 实现行为
  • 代理对象(代理人) - 实现行为 增强目标对象行为

设计原则

代理模式的两个设计原则:

  1. 代理类与委托类具有相似的行为(方法)
  2. 代理类增强委托类的行为,核心业务被代理人做,非核心业务公共业务代理人做

代理模式

静态代理

创建删除用户接口

  1. public interface UserServer {
  2. /**
  3. * 删除用户
  4. * @param userId
  5. */
  6. void deleteUser(Integer userId);
  7. }

创建目标对象

  1. public class UserServerImpl implements UserServer {
  2. @Override
  3. public void deleteUser(Integer userId) {
  4. System.out.println("删除用户"+userId);
  5. }
  6. }

创建代理对象

  1. public class UserServerProxy implements UserServer{
  2. private UserServer userServer;
  3. public UserServerProxy(UserServer userServer) {
  4. this.userServer = userServer;
  5. }
  6. @Override
  7. public void deleteUser(Integer userId) {
  8. System.out.println("开始事物");
  9. userServer.deleteUser(userId);
  10. System.out.println("提交事物");
  11. }
  12. }

测试验证

  1. public class UserApp {
  2. public static void main(String[] args) {
  3. // 目标对象
  4. UserServerImpl userTarget = new UserServerImpl();
  5. //代理对象,把目标对象传给代理对象,建立代理关系
  6. UserServerProxy proxy = new UserServerProxy(userTarget);
  7. //执行代理方法
  8. proxy.deleteUser(1);
  9. }
  10. }

动态代理

Proxy类

调用它的newInstance方法可以生成某个对象的代理对象,该方法需要三个参数:

  1. public static Object newProxyInstance(ClassLoader loader,
  2. Class<?>[] interfaces,
  3. InvocationHandler h) {
  4. Objects.requireNonNull(h);
  5. final Class<?> caller = System.getSecurityManager() == null
  6. ? null
  7. : Reflection.getCallerClass();
  8. /*
  9. * Look up or generate the designated proxy class and its constructor.
  10. */
  11. Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
  12. return newProxyInstance(caller, cons, h);
  13. }
  • ClassLoader loader:生成代理对象使用哪个类装载器【一般我们使用的是被代理类的装载器】
  • Class<?>[] interfaces:生成哪个对象的代理对象,通过接口指定【指定要被代理类的接口】
  • InvocationHandler h:生成的代理对象的方法里干什么事【实现handler接口,我们想怎么实现就怎么实现

InvocationHandler接口

  1. /**
  2. * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
  3. * method:我们所要调用某个对象真实的方法的Method对象
  4. * args:指代代理对象方法传递的参数
  5. */
  6. public Object invoke(Object proxy, Method method, Object[] args)
  7. throws Throwable;

事务代理类

  1. public class TransactionProxy {
  2. private Object target;
  3. public TransactionProxy(Object target) {
  4. this.target = target;
  5. }
  6. public Object getProxyInstance() {
  7. return Proxy.newProxyInstance(
  8. this.target.getClass().getClassLoader(),
  9. this.target.getClass().getInterfaces(),
  10. (Object object, Method method, Object[] args)->{
  11. System.out.println("开始事务");
  12. //执行目标对象方法
  13. Object returnValue = method.invoke(target, args);
  14. System.out.println("提交事务");
  15. return returnValue;
  16. }
  17. );
  18. }
  19. }

验证动态代理

  1. public class UserDynamicProxy {
  2. public static void main(String[] args) {
  3. UserServer target = new UserServerImpl();
  4. System.out.println(target.getClass());
  5. // 给目标对象,创建代理对象
  6. UserServer proxy = (UserServer) new TransactionProxy(target).getProxyInstance();
  7. // class $Proxy0 内存中动态生成的代理对象
  8. System.out.println(proxy.getClass());
  9. // 执行代理对象方法
  10. proxy.deleteUser(1);
  11. }
  12. }

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理.

Cglib

静态代理和动态代理模式都是要求目标对象是实现一个接口,但是目标对象并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。

Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.

  1. <!-- https://mvnrepository.com/artifact/cglib/cglib -->
  2. <dependency>
  3. <groupId>cglib</groupId>
  4. <artifactId>cglib</artifactId>
  5. <version>3.3.0</version>
  6. </dependency>

创建Cglib代理类

  1. public class CglibProxy implements MethodInterceptor {
  2. private Object target;
  3. public CglibProxy(Object target) {
  4. this.target = target;
  5. }
  6. public Object getProxyInstance() {
  7. //1.工具类
  8. Enhancer en = new Enhancer();
  9. //2.设置父类
  10. en.setSuperclass(target.getClass());
  11. //3.设置回调函数
  12. en.setCallback(this);
  13. //4.创建子类(代理对象)
  14. return en.create();
  15. }
  16. @Override
  17. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
  18. System.out.println("开始事务");
  19. Object returnValue = method.invoke(target, args);
  20. System.out.println("提交事务");
  21. return returnValue;
  22. }
  23. }

验证

  1. public class UserCglibProxy {
  2. public static void main(String[] args) {
  3. UserServer userServer = new UserServerImpl();
  4. CglibProxy cglibProxy = new CglibProxy(userServer);
  5. UserServer proxyInstance = (UserServer)cglibProxy.getProxyInstance();
  6. proxyInstance.deleteUser(2);
  7. }
  8. }