Java-JDK动态代理

简介: Java-JDK动态代理

概述


Java1.3以后,JAVA提供了动态代理技术,允许开发者在运行期创建接口的代理实例。

JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler.


InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。

而Proxy利用InvocationHandler动态的创建一个符合某一接口的实例,生成目标类的代理对象。


改造

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwODEzMTIxODMzNDkx.png

首先我们移除性能监视的横切代码,如下

package com.xgj.aop.base.jdkproxy;
/**
 * 
 * 
 * @ClassName: ForumServiceImpl
 * 
 * @Description: ForumService实现类
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月12日 下午4:14:30
 */
public class ForumServiceImpl implements ForumService {
  @Override
  public void removeTopic(int topicId) {
    // 模拟业务逻辑
    System.out.println("模拟删除Topic,topicId=" + topicId);
    try {
      Thread.currentThread().sleep((long) (Math.random() * 1000 * 10));
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
  @Override
  public void removeForum(int forumId) {
    // 模拟业务逻辑
    System.out.println("模拟删除forum,forumId=" + forumId);
    try {
      Thread.currentThread().sleep((long) (Math.random() * 1000 * 10));
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}


如上只编写了业务代码,移除的性能监视横切代码,放哪里呢?

InvocationHandler就是横切代码的家,编写实现类实现InvocationHandler 接口,重写invoke方法

比如:

package com.xgj.aop.base.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PerformanceHandler implements InvocationHandler {
  private Object target;
  /**
   * 
   * 
   * @Title:PerformanceHandler
   * 
   * @Description:构造函数, 入参target为业务目标类
   * 
   * @param target
   */
  public PerformanceHandler(Object target) {
    this.target = target;
  }
  // 性能监视的横切代码 + 业务代码
  @Override
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    // 开始监控 入参 方法的全限定名称
    PerformanceMonitor.begin(target.getClass().getName() + "."
        + method.getName());
    // 通过反射调用业务类的目标方法
    Object object = method.invoke(target, args);
    // 结束监控
    PerformanceMonitor.end();
    return object;
  }
}


分析:


invoke方法中PerformanceMonitor相关的为性能监视的横切代码,我们发现,横切代码只出现一次,而不是像原来那样每个类中都有。


method.invoke()通过Java反射机制间接调用目标对象的方法,这样 InvocationHandler的invoke方法就将横切逻辑代码和业务类方法的业务逻辑代码编织到一起,所以可以将InvocationHandler看成一个编织器。


具体分析这段代码:


首先实现了InvocationHandler接口,重写invoke方法

public Object invoke(Object proxy, Method method, Object[] args)


其中


proxy是最终生成的代理实例,一般不会用到


method是被代理目标实例的某个具体方法,通过它可以发起目标实例方法的反射调用


args是被代理实例某个方法的入参,在方法反射调用时使用。


其次,在构造函数里通过target传入希望被代理的目标对象。 在invoke方法中,将目标对象传递给method.invoke()方法,并调用目标实例的方法。


测试类,利用Proxy创建ForumService接口的代理实例:


package com.xgj.aop.base.jdkproxy;
import java.lang.reflect.Proxy;
public class ForumServiceTest {
  public static void main(String[] args) {
    // 希望被代理的目标业务类
    ForumService target = new ForumServiceImpl();
    // 将目标类业务和横切代码编织到一起
    PerformanceHandler handler = new PerformanceHandler(target);
    // 根据编织了目标业务类逻辑和性能监控横切逻辑的InvocationHandler实例创建代理实例
    ForumService proxy = (ForumService) Proxy.newProxyInstance(target
        .getClass().getClassLoader(),
        target.getClass().getInterfaces(), handler);
    // 调用代理实例
    proxy.removeTopic(3);
    proxy.removeForum(1);
  }
}


上述代码完成了业务类代码和横切面代码的编织工作并生成了代理实例。


PerformanceHandler handler = new PerformanceHandler(target); —>将性能监视横切逻辑编织到ForumService实例中。


然后通过Proxy的 newProxyInstance()讲台方法为编织了业务逻辑和心梗监视横切逻辑的handler创建了一个符合ForumService接口的代理实例。


第一个入参为类加载器


第二个入参为创建代理实例所需要实现的一组接口


第三个参数是整了业务逻辑和横切逻辑的编织器对象。


按照上述设置,这个代理实例就实现了目标业务类的所有接口,即ForumServiceImpl的ForumService接口。


这样就可以按照调用ForumService接口实例相同的方式调用代理实例了。


代理实例方法调用的时序图:


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwODEzMTMxNjI0ODYx.png

运行结果:


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwODEzMTI0ODQyOTcz.png


其他相关接口/类

ForumService.java

package com.xgj.aop.base.jdkproxy;
/**
 * 
 * 
 * @ClassName: ForumService
 * 
 * @Description: ForumService接口
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月12日 下午4:13:31
 */
public interface ForumService {
  /**
   * 
   * 
   * @Title: removeTopic
   * 
   * @Description: 根据topicId删除Topic
   * 
   * @param topicId
   * 
   * @return: void
   */
  void removeTopic(int topicId);
  /**
   * 
   * 
   * @Title: removeForum
   * 
   * @Description: 根据forumId删除Forum
   * 
   * @param forumId
   * 
   * @return: void
   */
  void removeForum(int forumId);
}


PerformanceMonitor.java

package com.xgj.aop.base.jdkproxy;
public class PerformanceMonitor {
  // 通过一个ThreadLocal保存与调用线程相关的性能监视信息
  private static ThreadLocal<MethoPerformance> performanceLocal = new ThreadLocal<MethoPerformance>();
  /**
   * 
   * 
   * @Title: begin
   * 
   * @Description: 启动对某一目标方法的性能监视
   * 
   * @param method
   * 
   * @return: void
   */
  public static void begin(String method) {
    System.out.println("begin to monitor:" + method);
    MethoPerformance methoPerformance = new MethoPerformance(method);
    performanceLocal.set(methoPerformance);
  }
  /**
   * 
   * 
   * @Title: end
   * 
   * @Description: 输出性能监视结果
   * 
   * @param method
   * 
   * @return: void
   */
  public static void end() {
    MethoPerformance methoPerformance = performanceLocal.get();
    // 打印出方法性能监视的结果信息
    methoPerformance.printPerformance();
  }
}


MethoPerformance.java

package com.xgj.aop.base.jdkproxy;
public class MethoPerformance {
  private long beginTime;
  private long endTime;
  private String methodName;
  /**
   * 
   * 
   * @Title:MethoPerformance
   * 
   * @Description:构造函数
   * 
   * @param methodName
   */
  public MethoPerformance(String methodName) {
    super();
    this.methodName = methodName;
    this.beginTime = System.currentTimeMillis();
  }
  /**
   * 
   * 
   * @Title: printPerformance
   * 
   * @Description: 计算耗时
   * 
   * 
   * @return: void
   */
  public void printPerformance() {
    endTime = System.currentTimeMillis();
    long cost = endTime - beginTime;
    System.out.println(methodName + " costs " + cost / 1000 + "秒\n");
  }
}


相关文章
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
25天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
23 0
[Java]静态代理与动态代理(基于JDK1.8)
|
1月前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
21 1
|
1月前
|
Java
深入理解Java动态代理
深入理解Java动态代理
19 1
|
29天前
|
Java
Java代码解释静态代理和动态代理的区别
### 静态代理与动态代理简介 **静态代理**:代理类在编译时已确定,目标对象和代理对象都实现同一接口。代理类包含对目标对象的引用,并在调用方法时添加额外操作。 **动态代理**:利用Java反射机制在运行时生成代理类,更加灵活。通过`Proxy`类和`InvocationHandler`接口实现,无需提前知道接口的具体实现细节。 示例代码展示了两种代理方式的实现,静态代理需要手动创建代理对象,而动态代理通过反射机制自动创建。
|
1月前
|
设计模式 缓存 Java
从源码学习Java动态代理|8月更文挑战
从源码学习Java动态代理|8月更文挑战
|
3月前
|
Java API 开发者
Jdk动态代理为啥不能代理Class?
该文章主要介绍了JDK动态代理的原理以及为何JDK动态代理不能代理Class。
Jdk动态代理为啥不能代理Class?
|
4月前
|
缓存 Java 测试技术
day27:Java零基础 - 动态代理
【7月更文挑战第27天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
43 2
day27:Java零基础 - 动态代理
|
3月前
|
开发者 C# 容器
【独家揭秘】当WPF邂逅DirectX:看这两个技术如何联手打造令人惊艳的高性能图形渲染体验,从环境搭建到代码实践,一步步教你成为图形编程高手
【8月更文挑战第31天】本文通过代码示例详细介绍了如何在WPF应用中集成DirectX以实现高性能图形渲染。首先创建WPF项目并使用SharpDX作为桥梁,然后在XAML中定义承载DirectX内容的容器。接着,通过C#代码初始化DirectX环境,设置渲染逻辑,并在WPF窗口中绘制图形。此方法适用于从简单2D到复杂3D场景的各种图形处理需求,为WPF开发者提供了高性能图形渲染的技术支持和实践指导。
226 0
|
3月前
|
设计模式 Java C++
揭秘!JDK动态代理VS CGLIB:一场关于Java代理界的‘宫心计’,你站哪队?
【8月更文挑战第24天】Java 动态代理是一种设计模式,允许在不改动原类的基础上通过代理类扩展功能。主要实现方式包括 JDK 动态代理和 CGLIB。前者基于接口,利用反射机制在运行时创建代理类;后者采用继承方式并通过字节码技术生成子类实现类的代理。两者在实现机制、性能及适用场景上有明显差异。JDK 动态代理适用于有接口的场景,而 CGLIB 更适合代理未实现接口的类,尽管性能更优但存在一些限制。开发者可根据需求选择合适的代理方式。
184 0