代理模式在整个设计模式中属于结构类模式,除了代理模式以外还包括我们了解过的适配器模式,装饰模式,组合模式等。他们都是通过组合类或者对象来进一步产生更复杂的结构和逻辑。在java中我们经常使用spring框架进行开发,spring中的AOP的核心就是代理。 代理模式 - 图1
代理模式中涉及几个角色:

  • 抽象主题角色:定义了被代理角色和代理角色的共同接口或者抽象类。
  • 被代理角色:实现或者继承抽象主题角色,定义实现具体业务逻辑的实现。
  • 代理角色:实现或者继承抽象主题角色,持有被代理角色的引用,控制和限制被代理角色的实现,并且拥有自己的处理方法(预处理和善后)

JDK代理

在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持。 我们举个例子,需求是需要在操作数据库的新增数据方法前和后打印输出日志。

  1. public class UserManagerImpl implements UserManager {
  2. @Override
  3. public void addUser(String userId, String userName) {
  4. System.out.println("UserManagerImpl.addUser");
  5. }
  6. }

如上代码我们需要在addUser这个方法执行前和后输出打印日志。 2. 动态代理类

  1. import java.lang.reflect.InvocationHandler;
  2. import java.lang.reflect.Method;
  3. import java.lang.reflect.Proxy;
  4. public class LogProxy implements InvocationHandler {
  5. // 目标对象
  6. private Object targetObject;
  7. //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
  8. public Object newProxyInstance(Object targetObject){
  9. this.targetObject=targetObject;
  10. //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
  11. //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
  12. //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
  13. //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
  14. //根据传入的目标返回一个代理对象
  15. return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
  16. targetObject.getClass().getInterfaces(),this);
  17. }
  18. @Override
  19. //关联的这个实现类的方法被调用时将被执行
  20. /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
  21. public Object invoke(Object proxy, Method method, Object[] args)
  22. throws Throwable {
  23. Object ret=null;
  24. try{
  25. /*原对象方法调用前处理日志信息*/
  26. System.out.println("开始调用");
  27. //调用目标方法
  28. ret=method.invoke(targetObject, args);
  29. /*原对象方法调用后处理日志信息*/
  30. System.out.println("调用结束");
  31. }catch(Exception e){
  32. e.printStackTrace();
  33. throw e;
  34. }
  35. return ret;
  36. }
  37. }

调用

  1. LogProxy logProxy=new LogProxy();
  2. UserManager userManager=(UserManager)logProxy.newProxyInstance(new UserManagerImpl());
  3. userManager.addUser("1", "三");

cglib代理

如果使用cglib代理,那么需要先引用cglib的依赖。

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

那么创建一回调拦截器,实现 MethodInterceptor接口,用于处理子类代理调用方法时回调的逻辑,也即真正代理的逻辑。

  1. public class ToolProxyCallback implements MethodInterceptor {
  2. // 目标对象
  3. private Object target;
  4. public ToolProxyCallback(Object target) {
  5. this.target = target;
  6. }
  7. @Override
  8. public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  9. // 入参日志打印
  10. System.out.println("准备执行目标方法;参数信息为="+args);
  11. // 权限拦截
  12. if(args.length <= 2) { // 假设这里的权限是参数不能小于2个
  13. return null;
  14. }
  15. // 通过反射执行目标方法
  16. Object resultObj = method.invoke(target,args);
  17. // 处理接口打印
  18. System.out.println("目标方法请求结果为;"+resultObj);
  19. return resultObj;
  20. }
  21. }

还需要一个工厂来创建子类代理的实例。

  1. public class ToolProxyFactory {
  2. /**
  3. * 获取子类代理实例
  4. * @param target 目标对象
  5. * @param callback 回调接口
  6. * @return
  7. */
  8. public static Object getProxyInstance(Object target, Callback callback) {
  9. // 工具类
  10. Enhancer enhancer = new Enhancer();
  11. // 设置父类
  12. enhancer.setSuperclass(target.getClass());
  13. // 设置回调函数。
  14. enhancer.setCallback(callback);
  15. return enhancer.create(); // 创建子类代理对象
  16. }
  17. }

那么调用目标方法就变为这样。

  1. public void testProjectProxy() {
  2. ToolService service = new ToolService();
  3. Callback toolProxyCallback = new ToolProxyCallback(service);
  4. ToolService serviceProxy = (ToolService)ToolProxyFactory.getProxyInstance(service,toolProxyCallback);
  5. /**
  6. * 使用 ToolProxyFactory 构建出 ToolCglibService的代理子类,通过代理子类去调用接口方法
  7. */
  8. String[] args = new String[]{"-s","test","-n","zhangsan"};
  9. serviceProxy.run(args);
  10. }