全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

java 中动态代理机制的实例讲解

java 中动态代理机制的实例讲解

在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:

InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

  • proxy:  指代我们所代理的那个真实对象
  • method:  指代的是我们所要调用真实对象的某个方法的Method对象
  • args:  指代的是调用真实对象某个方法时接受的参数

如果不是很明白,等下通过一个实例会对这几个参数进行更深的讲解。

接下来我们来看看Proxy这个类:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is
 also the superclass of all dynamic proxy classes created by those methods.

Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
 throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method
 invocations to the specified invocation handler.

这个方法的作用就是得到一个动态的代理对象,其接收三个参数,我们来看看这三个参数所代表的含义:

  • loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
  • interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
  • h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

好了,在介绍完这两个接口(类)以后,我们来通过一个实例来看看我们的动态代理模式是什么样的:

首先我们定义了一个Subject类型的接口,为其声明了两个方法:

public interface Subject
{
  public void rent();

  public void hello(String str);
}

接着,定义了一个类来实现这个接口,这个类就是我们的真实对象,RealSubject类:

public class RealSubject implements Subject
{
  @Override
  public void rent()
  {
    System.out.println("I want to rent my house");
  }

  @Override
  public void hello(String str)
  {
    System.out.println("hello: " + str);
  }
}

下一步,我们就要定义一个动态代理类了,前面说个,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外:

public class DynamicProxy implements InvocationHandler
{
  // 这个就是我们要代理的真实对象
  private Object subject;

  //  构造方法,给我们要代理的真实对象赋初值
  public DynamicProxy(Object subject)
  {
    this.subject = subject;
  }

  @Override
  public Object invoke(Object object, Method method, Object[] args)
      throws Throwable
  {
    //  在代理真实对象前我们可以添加一些自己的操作
    System.out.println("before rent house");

    System.out.println("Method:" + method);

    //  当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
    method.invoke(subject, args);

    //  在代理真实对象后我们也可以添加一些自己的操作
    System.out.println("after rent house");

    return null;
  }

}

最后,来看看我们的Client类:

/**
 * Java学习交流QQ群:589809992 我们一起学Java!
 */
public class Client
{
  public static void main(String[] args)
  {
    //  我们要代理的真实对象
    Subject realSubject = new RealSubject();

    //  我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
    InvocationHandler handler = new DynamicProxy(realSubject);

    /*
     * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
     * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
     * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
     * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
     */
    Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
        .getClass().getInterfaces(), handler);

    System.out.println(subject.getClass().getName());
    subject.rent();
    subject.hello("world");
  }
}

我们先来看看控制台的输出:

$Proxy0

before rent house
Method:public abstract void com.xiaoluo.dynamicproxy.Subject.rent()
I want to rent my house
after rent house

before rent house
Method:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
hello: world
after rent house

我们首先来看看 $Proxy0 这东西,我们看到,这个东西是由 System.out.println(subject.getClass().getName()); 这条语句打印出来的,那么为什么我们返回的这个代理对象的类名是这样的呢?

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
        .getClass().getInterfaces(), handler);

可能我以为返回的这个代理对象会是Subject类型的对象,或者是InvocationHandler的对象,结果却不是,首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了。

同时我们一定要记住,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号。

接着我们来看看这两句

subject.rent(); 
subject.hello(“world”);

这里是通过代理对象来调用实现的那种接口中的方法,这个时候程序就会跳转到由这个代理对象关联到的 handler 中的invoke方法去执行,而我们的这个 handler 对象又接受了一个 RealSubject类型的参数,表示我要代理的就是这个真实对象,所以此时就会调用 handler 中的invoke方法去执行:

/**
 * Java学习交流QQ群:589809992 我们一起学Java!
 */
public Object invoke(Object object, Method method, Object[] args)
      throws Throwable
  {
    //  在代理真实对象前我们可以添加一些自己的操作
    System.out.println("before rent house");

    System.out.println("Method:" + method);

    //  当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
    method.invoke(subject, args);

    //  在代理真实对象后我们也可以添加一些自己的操作
    System.out.println("after rent house");

    return null;
  }

我们看到,在真正通过代理对象来调用真实对象的方法的时候,我们可以在该方法前后添加自己的一些操作,同时我们看到我们的这个 method 对象是这样的:

public abstract void com.xiaoluo.dynamicproxy.Subject.rent()

public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)

正好就是我们的Subject接口中的两个方法,这也就证明了当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。

这就是我们的java动态代理机制。

本篇随笔详细的讲解了java中的动态代理机制,这个知识点非常非常的重要,包括我们Spring的AOP其就是通过动态代理的机制实现的,所以我们必须要好好的理解动态代理的机制。

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


# java  # 动态代理  # 动态代理机制的详解  # 动态代理的分析  # 详解Java的Proxy动态代理机制  # 详解Java Proxy动态代理机制  # 浅谈Java 代理机制  # Java动态代理机制的实例详解  # 带你深入了解java-代理机制  # 的是  # 自己的  # 来看看  # 就会  # 方法来  # 我们可以  # 这组  # 转化为  # 我要  # 是在  # 跳转到  # 就能  # 是这样  # 当我  # 将其  # 这两个  # 第二个  # 这个时候  # 我们一起  # 这三个 


相关文章: 如何在Windows 2008云服务器安全搭建网站?  C++中引用和指针有什么区别?(代码说明)  专业网站建设制作报价,网页设计制作要考什么证?  如何用景安虚拟主机手机版绑定域名建站?  建站之星与建站宝盒如何选择最佳方案?  建站之星后台搭建步骤解析:模板选择与产品管理实操指南  如何用IIS7快速搭建并优化网站站点?  定制建站方案优化指南:企业官网开发与建站费用解析  建站之星如何实现五合一智能建站与营销推广?  如何在新浪SAE免费搭建个人博客?  如何快速生成可下载的建站源码工具?  贸易公司网站制作流程,出口贸易网站设计怎么做?  建站主机与服务器功能差异如何区分?  建站之星客服服务时间及联系方式如何?  如何选择最佳自助建站系统?快速指南解析优劣  小型网站制作HTML,*游戏网站怎么搭建?  广州顶尖建站服务:企业官网建设与SEO优化一体化方案  建站主机解析:虚拟主机配置与服务器选择指南  招商网站制作流程,网站招商广告语?  南京做网站制作公司,南京哈发网络有限公司,公司怎么样,做网页美工DIV+CSS待遇怎么样?  定制建站流程解析:需求评估与SEO优化功能开发指南  网站建设制作需要多少钱费用,自己做一个网站要多少钱,模板一般多少钱?  网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?  建站之星2.7模板快速切换与批量管理功能操作指南  网站app免费制作软件,能免费看各大网站视频的手机app?  昆明高端网站制作公司,昆明公租房申请网上登录入口?  如何用美橙互联一键搭建多站合一网站?  如何通过西部建站助手安装IIS服务器?  如何在IIS服务器上快速部署高效网站?  如何选择高效便捷的WAP商城建站系统?  建站之星伪静态规则如何正确配置?  C++如何将C风格字符串(char*)转换为std::string?(代码示例)  长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?  香港服务器网站卡顿?如何解决网络延迟与负载问题?  香港服务器网站生成指南:免费资源整合与高速稳定配置方案  表情包在线制作网站免费,表情包怎么弄?  建站之星后台管理:高效配置与模板优化提升用户体验  视频网站制作教程,怎么样制作优酷网的小视频?  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  建站之星如何快速更换网站模板?  如何选择PHP开源工具快速搭建网站?  如何快速生成凡客建站的专业级图册?  广平建站公司哪家专业可靠?如何选择?  建站之星免费版是否永久可用?  高防服务器租用如何选择配置与防御等级?  如何通过NAT技术实现内网高效建站?  建站之星CMS建站配置指南:模板选择与SEO优化技巧  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  手机怎么制作网站教程步骤,手机怎么做自己的网页链接? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。