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
目录
相关文章
|
28天前
|
Java
JAVA 静态代理 & 动态代理
【11月更文挑战第14天】静态代理是一种简单的代理模式实现,其中代理类和被代理类的关系在编译时已确定。代理类实现与被代理类相同的接口,并持有被代理类的实例,通过调用其方法实现功能增强。优点包括代码结构清晰,易于理解和实现;缺点是对于多个被代理类,需为每个类编写相应的代理类,导致代码量大增,维护成本高。动态代理则在运行时动态生成代理类,更加灵活,减少了代码冗余,但可能引入性能损耗和兼容性问题。
|
2月前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
32 0
[Java]静态代理与动态代理(基于JDK1.8)
|
2月前
|
Java
Java访问外网图片地址时,如何添加代理?
【10月更文挑战第14天】Java访问外网图片地址时,如何添加代理?
45 2
|
2月前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
4月前
|
缓存 负载均衡 安全
|
5月前
|
Java Perl
Java进阶之正则表达式
【7月更文挑战第17天】正则表达式(RegEx)是一种模式匹配工具,用于在字符串中执行搜索、替换等操作。它由普通字符和特殊元字符组成,后者定义匹配规则。
37 4
|
5月前
|
数据采集 安全 Java
Java Selenium WebDriver:代理设置与图像捕获
Java Selenium WebDriver:代理设置与图像捕获
|
5月前
|
设计模式 Java
Java进阶之代理
Java进阶之代理
29 4
|
5月前
|
设计模式 Java
Java进阶之代理
Java进阶之代理
31 3
|
5月前
|
Java 编译器 API
Java进阶之标准注解
【7月更文挑战第15天】Java标准注解包括标记注解(如@Deprecated)、@Override(检查方法重写)、@SuppressWarnings(抑制警告)。多值注解如@RequestMapping在Spring中用于HTTP请求映射。元注解如@Retention控制注解保留策略,@Target指定应用位置。Java8引入类型注解(@FunctionalInterface、@SafeVarargs)和重复注解(@Repeatable)。自定义注解可通过反射读取,如示例中的MyMarkerAnnotation等。
28 2
下一篇
DataWorks