Java进阶之代理

简介: 【7月更文挑战第16天】Java动态代理通过`java.lang.reflect.Proxy`和`InvocationHandler`实现,无需编译期定义代理类。与静态代理相比,它更灵活,代码更简洁,适用于方法数量变化或未知接口代理。

Java进阶之代理
Java中内置了java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来支持动态代理。
看之前我们先明白代理是什么?
代理就是被代理方授权给第三方来做被代理方的事情,这里的第三代理方就是被代理方的代理,哈哈哈。
代理方可以控制被代理方的访问,比如打官司,你要有事情,找我的代理律师,不要直接找我,但是代理律师和你谈的还是我的事情。
代理是一种设计模式,它为其他对象提供一种代理,以控制对这个对象的访问。
代码示例一下:
首先定义一个接口,接口可以为它的子类定义一种规范。
public interface IService {
void doSomething(int num);
}
然后实现类,这个类就是具体的业务操作,也就是我的事情
public class RealService implements IService {
public void doSomething(int num) {
System.out.println("解决我piao的事情,喜提【"+num+"】年缝纫机");
}
}
不用代理的情况下,我们就是直接被处理:
RealService me = new RealService();
me.doSomething(6);
这样的话,直接就上山干6年,么办法。
你肯定不想吧,你找个代理律师,这个piao的事情不直接找我RealService,我一句话不说,有事找我法务。
/**

   * 建一个法务,代理律师,我可继承了IService,我也可以doSomething(num)
   */
  public class ProxyService implements IService {
      private IService realService;
      public ProxyService(IService realService) {
          this.realService = realService;
      }
      public void doSomething(int num) {
        System.out.println("我是被代理方的代理律师,现在开始解决当事人piao问题");
          System.out.println("哎,我的当事人是不满十八周岁,且初次违法,恳请法律减轻处罚! 减1年:"+num--);
          System.out.println("哎,我的当事人对于自己的违法行为表现出深刻的悔过态度,‌承诺不再犯类似错误,恳请法律减轻处罚! 减1年:"+num--);
          realService.doSomething(num);
          System.out.println("事情解决,收取被代理方当事人报酬22万");
      }
  }
  我们看通过上述代理类来解决这个事情:
  // 新建业务类对象
  IService realService = new RealService();
  // 新建代理类对象,将业务类对象交给代理类代理
  IService proxyService = new ProxyService(realService);
  // 通过代理类去调用业务类的方法
  proxyService.doSomething();
  最后,本来要是直接面向业务类本身去doSomething(6)的话,体验卡有6年,但是使用代理后,减掉了2年。当然事后代理类还收取了报酬。
  可以看到调用方法的前后都可以加一些业务类本身没有的骚操作,以达到业务类本身所不具有的功能。
  以上是一个静态代理,静态代理在编译时就已经确定代理类和原始类的关系。通常,代理类和原始类实现相同的接口。代理类持有原始类的实例,并在其方法中调用原始类的方法,这样可以在调用前后添加额外的逻辑。
  静态代理是有缺点的:
  代码冗余:每个代理类都需要手动编写,如果接口方法很多,代理类会变得非常庞大。
  灵活性差:一旦接口增加方法,所有代理类都需要修改,比如上面如果不只是piao了,还是强制piao,那就需要增加更多的骚操作方法来处理。
  那么有没有一种更好的解决方案呢?
  有,那就是动态代理!
  动态代理中的代理类并不要求在编译期就确定,而且此时可能也不知道要代理哪些,可以在运行期动态生成,从而实现对目标对象的代理功能。
  听起来好熟悉,是不是反射的时候就是这么说的: 编译期不确定,在运行期动态去操作类的实例,没错,Java动态代理底层也是用的反射机制。
  使用Java动态代理:
  要用java.lang.reflect.InvocationHandler接口来代替代理类继承的接口,这个接口只有一个invoke方法来支持传入要代理的method方法,并且使用反射去调用它。
  要使用java.lang.reflect.Proxy类的newProxyInstance方法来创建代理类,三个参数分别是被代理业务类加载器、被代理业务类接口列表、代理类本身。
  这样Java底层机制就会通过反射来完成代理。
  class ProxyDong implements InvocationHandler {
      private Object realService;
      public Object proxy(Object obj) {
          this.realService = obj;
          return Proxy.newProxyInstance(
              obj.getClass().getClassLoader(), // 被代理业务类加载器
              obj.getClass().getInterfaces(), // 被代理业务类接口列表
              this // 代理类本身
            );
      }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      int num = (int) args[0];
      System.out.println("我是被代理方的代理律师,现在开始解决当事人piao问题,当前体验卡年数:"+num);
      num--;
          System.out.println("哎,我的当事人是不满十八周岁,且初次违法,恳请法律减轻处罚! 减1年后年数:"+num);
          num--;
          System.out.println("哎,我的当事人对于自己的违法行为表现出深刻的悔过态度,‌承诺不再犯类似错误,恳请法律减轻处罚! 减1年后年数:"+num);
          method.invoke(this.realService, num);
          System.out.println("事情解决,收取被代理方当事人报酬22万");
      return null;
    }
  }
  观察发现不管是动态代理还是静态代理,肯定是要让代理去持有被代理的业务类。
  使用动态代理解决:
  RealService me = new RealService();
  IService proxyService = (IService) new ProxyDong().proxy(me);
  proxyService.doSomething(6);

  这就是Java的动态代理,动态代理的优势:
  无需手动编写代理类:动态代理自动生成代理类,减少了代码量。
  高度灵活:代理类可以在运行时动态创建,不受接口方法数量限制。
  也就是说,真实的被代理的业务类发生改变了,比如我们业务类中新加一个qiang()方法,动态代理类也不用修改,直接使用的时候继续调用就可以执行那一套减年套路:
  proxyService.qinag(10);
  这就是动态代理的强大之处,它能够自动适应接口的变化,无需手动更新代理类。

  这里的减年骚操作只是其中的一种,我们还有很多的应用场景:
  访问控制:如安全代理确保只有特定用户可以访问敏感操作。
  日志记录:记录方法调用的时间和参数,便于监控和调试。
  事务管理:在方法调用前后开启和提交事务。
  性能优化:如缓存代理缓存结果,减少数据库访问次数。
  等等...web开发中的spring框架中的拦截器(Interceptors)、面向切面编程(AOP)等等都是代理模式。

  END
目录
相关文章
|
1月前
|
缓存 负载均衡 安全
|
2月前
|
Java Perl
Java进阶之正则表达式
【7月更文挑战第17天】正则表达式(RegEx)是一种模式匹配工具,用于在字符串中执行搜索、替换等操作。它由普通字符和特殊元字符组成,后者定义匹配规则。
21 4
|
2月前
|
数据采集 安全 Java
Java Selenium WebDriver:代理设置与图像捕获
Java Selenium WebDriver:代理设置与图像捕获
|
2月前
|
设计模式 Java
Java进阶之代理
Java进阶之代理
21 4
|
2月前
|
设计模式 Java
Java进阶之代理
Java进阶之代理
21 3
|
2月前
|
Java 编译器 API
Java进阶之标准注解
【7月更文挑战第15天】Java标准注解包括标记注解(如@Deprecated)、@Override(检查方法重写)、@SuppressWarnings(抑制警告)。多值注解如@RequestMapping在Spring中用于HTTP请求映射。元注解如@Retention控制注解保留策略,@Target指定应用位置。Java8引入类型注解(@FunctionalInterface、@SafeVarargs)和重复注解(@Repeatable)。自定义注解可通过反射读取,如示例中的MyMarkerAnnotation等。
19 2
|
2月前
|
Java 编译器 API
Java进阶之标准注解
Java进阶之标准注解
24 1
|
2月前
|
Java 数据库 Spring
Java编程问题之在测试中使用CGLIB创建代理类如何解决
Java编程问题之在测试中使用CGLIB创建代理类如何解决
|
2月前
|
缓存 Java 应用服务中间件
Java编程问题之重试机制问题之在CGLIB中设置目标对象类并创建代理类如何解决
Java编程问题之重试机制问题之在CGLIB中设置目标对象类并创建代理类如何解决
|
2月前
|
Java 编译器 API
Java进阶之标准注解
Java进阶之标准注解
24 0