java jdk动态代理原理,java中有哪些常用的动态代理技术

  java jdk动态代理原理,java中有哪些常用的动态代理技术

  如何解决写爬虫IP受阻的问题?立即使用。

  随着Java动态代理机制的出现,Java开发人员无需手动编写代理类,只需指定一组接口和委托类对象,就可以动态获取代理类。(推荐:java视频教程)

  代理负责将所有方法调用分派给委托对象以执行反射。在调度执行的过程中,开发人员还可以根据需要调整委托对象及其功能。这是一个非常灵活的代理框架。让我们开始学习动态代理。

  动态代理的简要说明

  在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler(接口),一个是proxy(类)。

  一、 InvocationHandler(interface)的描述:

  InvocationHandler是由代理实例的调用处理程序实现的接口。

  每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,方法调用被编码并被分派给其InvocationHandler的invoke方法。每个动态代理类都必须实现调用处理程序的接口。并且代理类的每个实例都与一个处理程序相关联。当我们通过代理对象调用一个方法时,这个方法的调用会被转发给InvocationHandler接口的invoke方法调用。让我们看一下invoke方法,InvocationHandler接口的唯一方法:

  Object Invoke (Object Proxy,Method Method,Object[]args)Throwable该方法接收三个参数并返回一个对象类型,分别代表以下含义:

  代理:指我们所代表的真实对象。

  方法:指我们要调用真实对象的方法的方法对象。

  Args:指调用真实对象的方法时接受的参数。

  返回的对象指的是实对象方法的返回类型,下面的例子会进一步理解。

  从代理实例上的方法调用返回的值。二。代理描述(类别):

  Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

  这个代理类的功能是动态创建一个代理对象。我们经常使用newProxyInstance方法:

  公共静态对象new proxy instance(Class loader loader,Class?[]接口,调用处理程序h)对Throws IllegalArgumentException参数的理解:

  //一个ClassLoader对象,它定义使用哪个ClassLoader对象来加载生成的代理对象。

  loader——定义代理类的类加载器

  //一个接口对象数组,指示我将向需要代理的对象提供什么接口。

  interfaces -代理类要实现的接口列表

  //一个InvokeHandler对象,指示当我的动态代理对象调用方法时,将关联哪个InvokeHandler对象。

  h-调用处理程序,调度方法调用以理解返回的结果:代理对象的一个例子

  具有代理类的指定调用处理程序的代理实例,该代理类由指定的类加载器定义并实现指定的接口

  简单的Java代理

  我们创建了一个Java项目来测试和理解动态代理。项目结构如下:

  一、 先定义一个接口Interface,添加两个方法。

  包com . huhx . proxy;

  公共接口界面{

  void get myname();

  String getNameById(字符串id);

  }二、 定义一个真实的实现上述接口的类,RealObject:

  包com . huhx . proxy;

  公共类RealObject实现接口{

  @覆盖

  public void getMyName() {

  System.out.println(我叫huhx );

  }

  @覆盖

  公共字符串getNameById(字符串id) {

  System.out.println(参数id: id );

  返回‘huhx’;

  }

  }三、 定义一个代理对象,也实现了上述的Interface接口:

  包com . huhx . proxy;

  公共类SimpleProxy实现接口{

  代理的专用接口;

  公共简单代理(代理的接口){

  this.proxied=代理

  }

  @覆盖

  public void getMyName() {

  系统。出去。println(“proxy get my name”);

  代理的。获取my name();

  }

  @覆盖

  公共字符串getNameById(字符串id) {

  系统。出去。println( proxy getname byid );

  返回代理的。getname byid(id);

  }

  }四、 SimpleMain在Main方法中,测试上述的结果:

  包com。huhx。代理人;

  公共类简单主体{

  私有静态空的使用者(接口接口){

  iface。获取my name();

  字符串名称=I面。getname byid( 1 );

  系统。出去。println( name: name );

  }

  公共静态void main(String[] args) {

  consume(新真实对象());

  系统。出去。println(====================================);

  consume(新简单代理(新真实对象()));

  }

  }五、 运行的结果如下:

  我的名字是huhx

  参数id: 1

  名称:huhx

  ========================================================

  代理获取我的名字

  我的名字是huhx

  代理getnamebyid

  参数id: 1

  名称:huhxJava的动态代理

  完成了上述简单的爪哇代理,现在我们开始学习爪哇的动态代理,它比代理的思想更向前一步,因为它可以动态地创建代理并动态的处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。下面我们通过案例来加深爪哇动态代理的理解:

  一、 创建一个继承了InvocationHandler的处理器:DynamicProxyHandler

  包com。huhx。动态代理;

  导入Java。郎。反思。调用处理程序;

  导入Java。郎。反思。方法;

  导入Java。util。数组;

  公共类DynamicProxyHandler实现InvocationHandler {

  代理的私有对象;

  公共DynamicProxyHandler(代理的对象){

  System.out.println(动态代理处理程序构造器:已代理。getclass());

  this.proxied=代理

  }

  @覆盖

  公共对象调用(对象代理、方法方法、对象[]参数)抛出可投掷的

  System.out.println(动态代理名:代理。getclass());

  系统。出去。println( method: method。getname());

  系统。出去。println( args:数组。tostring(args));

  对象调用对象=方法。invoke(proxied,args);

  if (invokeObject!=null) {

  系统。出去。println( invoke对象: invoke对象。getclass());

  }否则{

  System.out.println(调用对象为null’);

  }

  返回invoke对象

  }

  } 二、 我们写一个测试的Main方法,DynamicProxyMain:

  包com。huhx。动态代理;

  导入Java。郎。反思。调用处理程序;

  导入Java。郎。反思。代理人;

  导入com。huhx。代理。界面;

  导入com。huhx。代理。实物;

  公共类DynamicProxyMain {

  公共静态空的使用者(接口接口){

  iface。获取my name();

  字符串名称=I面。getname byid( 1 );

  系统。出去。println( name: name );

  }

  公共静态void main(String[] args)引发异常,SecurityException,Throwable {

  真实对象真实对象=新真实对象();

  消费者(实物);

  系统。出去。println(======================);

  //动态代理

  类加载器类加载器=接口。班级。获取类加载器();

  班级?[]接口=新类[]{接口。class };

  invocation handler=new DynamicProxyHandler(真实对象);

  接口代理=(接口)代理。newproxyinstance(类加载器、接口、处理程序);

  系统。出去。println( in dynamicproxyMain proxy: proxy。getclass());

  消费者(代理);

  }

  }三、 运行结果如下:

  我的名字是huhx

  参数id: 1

  名称:huhx

  ==============================

  动态代理处理程序构造器:com.huhx.proxy.RealObject类

  在动态代理主代理中:class com.sun.proxy.$Proxy0

  动态代理名称:class com.sun.proxy.$Proxy0

  方法:getMyName

  参数:空

  我的名字是huhx

  调用对象为空

  动态代理名称:class com.sun.proxy.$Proxy0

  方法:getNameById

  参数:[1]

  参数id: 1

  调用对象:java.lang.String类

  名称:huhx从以上输出结果,我们可以得出以下结论:

  与代理对象相关联的InvocationHandler,只有在代理对象调用方法时,才会执行它的引起方法

  引起的三个参数的理解:对象代理是代理的对象,方法方法是真实对象中调用方法的方法类,Object[] args是真实对象中调用方法的参数

  Java动态代理的原理

  一、 动态代理的关键代码就是Proxy.newProxyInstance(classLoader, interfaces, handler),我们跟进源代码看看:

  公共静态对象新代理实例(类加载器加载器,类?[]接口InvocationHandler h)抛出IllegalArgumentException {

  //处理程序不能为空

  if (h==null) {

  抛出新的NullPointerException();

  }

  期末班?[]intfs=接口。clone();

  最终安全管理器sm=系统。getsecuritymanager();

  如果(sm!=null) {

  checkProxyAccess(反射。getcallerclass()、loader、intfs);

  }

  /*

  *查找或生成指定的代理类。

  */

  //通过装货设备和接口,得到代理的班级对象

  班级?cl=getProxyClass0(loader,intfs);

  /*

  *用指定的调用处理程序调用其构造函数。

  */

  尝试{

  最终构造者?cons=cl。获取构造函数(构造函数参数);

  最终调用处理程序ih=h;

  如果(sm!=null proxyaccesshelper。needsnewinstancecheck(cl)){

  //使用特权创建代理实例,因为代理类可以

  //实现需要特殊权限的非公共接口

  返回门禁控制器。doprivileged(new PrivilegedActionObject(){

  公共对象运行(){

  返回newInstance(cons,ih);

  }

  });

  }否则{

  //创建代理对象的实例

  返回newInstance(cons,ih);

  }

  } catch(NoSuchMethodException e){

  抛出新的内部错误(例如tostring());

  }

  }二、 我们看一下newInstance方法的源代码:

  私有静态对象新实例(构造函数?cons,InvocationHandler h) {

  尝试{

  返回cons.newInstance(新对象[]{ h });

  } catch(IllegalAccessException 实例化异常e){

  抛出新的内部错误(例如tostring());

  } catch(InvocationTargetException e){

  throwable t=e . get cause();

  if(运行时异常的测试实例){

  throw(运行时异常)t;

  }否则{

  抛出新的内部错误(t . tostring());

  }

  }

  }三、 当我们通过代理对象调用 一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。

  体现这句话的代码,我在源码中没有找到,于是我在测试类的主要的方法中加入以下代码:

  如果(代理的代理实例){

  调用处理器调用处理器=代理。getinvocationhandler(代理);

  invocationHandler.invoke(proxy,realObject.getClass().getMethod(getMyName ),null);

  系统。出去。println(-);

  }这段代码的输出结果如下,与上述中调用代理对象中的获取我的名字方法输出是一样的,不知道虚拟机(Java虚拟机的缩写)底层是否是这样判断的:

  动态代理处理程序构造器:com.huhx.proxy.RealObject类

  动态代理名称:class com.sun.proxy.$Proxy0

  方法:getMyName

  参数:空

  我的名字是huhx

  调用对象为空

  -更多爪哇岛知识请关注爪哇岛基础教程栏目。以上就是爪哇动态代理的原理的详细内容,更多请关注我们其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • ubuntu18.04安装jdk8,ubuntu中安装jdk
  • ubuntu18.04安装jdk8,ubuntu中安装jdk,Ubuntu 安装 JDK8 的两种方法(总结)
  • JDK1.8安装教程,安装配置jdk1.8
  • JDK1.8安装教程,安装配置jdk1.8,2020JDK1.8安装教程详解(一次就可安装成功)
  • ,,jdk8使用stream实现两个list集合合并成一个(对象属性的合并)
  • ,,IntelliJ IDEA之配置JDK的4种方式(小结)
  • java代理模式详解,java代理模式的典型例子,java代理模式(jdk proxy)
  • java中spi有什么作用,jdk的spi机制
  • java中spi有什么作用,jdk的spi机制,一文搞懂Java的SPI机制(推荐)
  • ,,详解JDK自带javap命令反编译class文件和Jad反编译class文件(推荐使用jad)
  • ,,JAVA帮助文档全系列 JDK1.5 JDK1.6 JDK1.7 官方中英完整版整理
  • ,,JAVA JDK8 List分组的实现和用法
  • idea配置tomcat和jdk,idea配置本地gradle
  • 简单叙述一下jdk环境变量的配置,jdk环境变量配置是干什么的
  • 建立Java开发环境,安装JDK,一般需要设置环境变量,在安装完JDK后,需要在环境变量中配置
  • 留言与评论(共有 条评论)
       
    验证码: