Java动态代理(设计模式)代码详解

基础:需要具备面向对象设计思想,多态的思想,反射的思想;

Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类。代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程中,开发人员还可以按需调整委托类对象及其功能,这是一套非常灵活有弹性的代理框架。通过阅读本文,读者将会对Java动态代理机制有更加深入的理解。本文首先从Java动态代理的运行机制和特点出发,对其代码进行了分析,推演了动态生成类的内部实现。

代理模式的基本概念和分类

代理模式:为其他对象提供一个代理,来控制对这个对象的访问。代理对象起到中介作用,可以去掉服务或者增加额外的服务,或者引用别人的话:“代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。”

代理模式在开发中的应用场景

远程代理:为不同地理的对象提供局域网代表对象。

虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。比如网页中的先显示文字再显示图片。

保护代理:控制不同用户的访问权限。比如:只有当客户注册成功之后,才可以进行增删改查等操作。

智能引用代理:提供对目标代理额外的服务。

代理模式的实现方式

使用继承和聚合实现动态代理,哪种更好呢!

public interface Moveable {
	public void move();
}
public class Car implements Moveable{
	@Override
	  public void move() {
		try {
			Thread.sleep(new Random().nextint(1000));
			System.out.println("……行驶中……");
		}
		catch(InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
public class Car2 extends Car{
	@Override
	  public void move()
	  {
		//分离代码,增加业务逻辑
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始行驶……");
		super.move();
		long endTime=System.currentTimeMillis();
		System.out.println("汽车结束行驶……时间:"+(endTime-startTime)+"ms");
	}
}

继承方式实现代理

Moveablecar2=newCar2();
car2.move();

聚合方式实现代理

Carcar=newCar();
Moveablem=newCar3(car);
m.move();

总结

使用继承方式不够灵活,当功能叠加的时候,只能臃肿的扩展代理类;
使用聚合的方式,代理之间可以相互传递,灵活的组合代理;

public class CarLogProxy extends Car{
	@Override
	  public void move()
	  {
		//分离代码,增加业务逻辑
		long startTime=System.currentTimeMillis();
		System.out.println("日志开始……");
		super.move();
		long endTime=System.currentTimeMillis();
		System.out.println("日志结束……");
	}
}
public class CarTimeProxy implements Moveable {
	public CarTimeProxy(Car car)
	  {
		super();
		this.car=car;
	}
	private Carcar;
	@Override
	  public void move() {
		//分离代码,增加业务逻辑
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始行驶……");
		car.move();
		long endTime=System.currentTimeMillis();
		System.out.println("汽车结束行驶……时间:"+(endTime-startTime)+"ms");
	}
}
@Test:
Car car =new Car();
CarTimeProxy ctp=new CarTimeProxy(car);
CarLogProxy clp=new CarLogProxy(ctp);
clp.move();
//还可以通过接口相互传递代理实例
CarLogProxy clp1=new CarLogProxy(car);
CarTimeProxy ctp1=new CarTimeProxy(clp1);
ctp1.move();

JDK动态代理和CGlib动态代理

JDK动态代理

代理实现

如果不同的对象要实现相同功能的代理类,应该如何处置?

此时可以试着将其集成在同一个代理类中-----动态代理:实现对不同类/不同方法的代理;

大致过程如下:

Java动态代理类位于java.lang.reflect包下,一般主要涉及到一下两个类:

(1)InterfaceInvocationHandler:该接口中仅定义了一个方法Publicobjectinvoke(Objectobj,Methodmethod,Object[]args)

obj:一般是指代理类

method:是被代理的方法

args为该方法的参数数组。

这个抽象的方法在代理类中动态实现。

(2)Proxy:该类即为动态代理类

statixObjectnewProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)

返回甙类类的一个实例,返回后的代理类可以当做被代理类使用(可以使用被代理类在接口中声明过的方法);

实现实例:

@ TimeHandler
public class TimeHandler   implements InvocationHandler {
	public TimeHandler(Object target) {
		super();
		this.target = target;
	}
	private Objecttarget;
	/*
  * 参数:
  * proxy 被代理对象
  * method 被代理对象的方法
  * args 方法的参数
  *
  * 返回值:
  * Object 方法返回值
  */
	@Override
	  public Object invoke(Object proxy, Method method,Object[] args)
	    throws Throwable {
		long startTime=System.currentTimeMillis();
		System.out.println("汽车开始行驶……");
		method.invoke(target);
		long endTime=System.currentTimeMillis();
		System.out.println("汽车结束行驶……时间:"+(endTime-startTime)+"ms");
		return null;
	}
}
@被代理类的接口
public interface Moveable {
  public void move();
}
@被代理的类
public class Car implements Moveable{
	@Override
	  public void move() {
		try {
			Thread.sleep(new Random().nextint(1000));
			System.out.println("……行驶中……");
		}
		catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

@测试

public class Test {
  /**
  * JDk动态代理的测试类
  */
  public static void main(String[] args) {
   Car car=new Car();
   InvocationHandler h=new TimeHandler(car);
   Class<?>cls=car.getClass();
   /*
    * loader 类加载器
    * interfaces 实现接口
    * h InvocationHandler
    */
   Moveable m=(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);
   m.move();
  }
} 

&&测试结果

梳理总结

所为的DynamicProxy是这样一种class:

它是在运行时生成的class,该class需要实现一组interface,使用动态代理类的时候,必须实现InvocationHandler接口。

JDK动态代理的一般步骤

1.创建一个实现接口InvocationHandler的类,它必须实现invoke()

2.创建被代理的类以及接口

3.调用Proxy的静态方法,创建一个代理类

newProxyInstance(ClassLoaderloader,Class[]interfaces,InvocationHandlerh)

4.通过代理调用方法

CGlib动态代理的实现

代理实现

@引入cglib-node-2.2.jar包

@CglibProxy拦截类实现接口MethodInterceptor:重写intercept拦截方法

public class CglibProxy implements MethodInterceptor {
	private Enhancerenhancer=new Enhancer();
	public Object getProxy(Class cl)
	  {
		//设置创建子类的类
		enhancer.setSuperclass(cl);
		enhancer.setCallback(this);
		return enhancer.create();
	}
	/*
  * 拦截所有目标类方法的调用
  * object 目标类的实例
  * m 目标方法的反射对象
  * args 方法的参数
  * proxy 代理类的实例
  *
  */
	@Override
	  public Object intercept(Object obj, Method m,Object[] args,  MethodProxy proxy)throws Throwable
	{
		System.out.println("日志开始……");
		//代理类调用父类的方法
		proxy.invokeSuper(obj, args);
		System.out.println("日志结束……");
		return null;
	}
}

@被代理类Train

public class Train {
  public void move()
  {
   System.out.println("火车行驶中……");
  }
} 

@测试类

public class Test {
  /**
  * cglibProxy动态代理测试类
  */
  public static void main(String[] args) {
   CglibProxy proxy=new CglibProxy();
   Train t=(Train)proxy.getProxy(Train.class);
   t.move();
  }
} 

##测试结果:

梳理总结

使用CglibProxy实现动态代理的一般步骤

1、创建类实现接口MethodInterceptor,并重写intercept方法

2、创建被代理类

3、调用代理类自定义的方法,得到一个代理实例

4、通过代理实例调用被代理类的需要执行的方法

比较总结

JDK动态代理

1、只能代理实现了接口的类

2、没有实现接口的类不能实现JDK的动态代理

CGlib动态代理

1、针对类来实现代理

2、对执行目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。

模拟代理产生步骤

思路:

实现功能:通过Proxy的newProxyInstance返回代理对象

1、声明一段源码(动态产生代理)

2、编译源码(JDKCompilerAPI)产生新的类(代理类)

3、将这个类load到内存当中,产生一个新的对象(代理对象)

4、返回代理对象

完善动态代理实现

首先得到系统编译器,通过编译器得到文件管理者,然后获取文件,然后编译器执行编译任务,完成编译之后,将class文件加载到类加载器中,通过构造方法得到实例,然后调用newInstance()接收一个对象的实例。

(1)拿到编译器JavaCompilercompiler=ToolProvider.getSystemJavaCompiler();

(2)文件管理者StandardJavaFileManagerfileMgr=Compiler.getStandardFileManager(null,null,null);

(3)获取文件Iterableunits=fileMgr.getJavaFileObjects(filename);

(4)编译任务CompilationTaskt=compiler.getTask(null,fileMgr,null,null,null,units);

(5)load到内存

ClassLoadercl=ClassLoader.getSystemClassLoader();

Classc=cl.loadClass(”com.imooc.proxy.$Proxy0”);

(6)通过代理对象的构造器构造实例

Constructorctr=c.getConstructor(infce);

ctr.newInstance(newCar());

-------

上说所说,内部的业务逻辑是硬编码的,如何实现真正的动态代理,动态的指定业务逻辑呢?

1、需要创建一个事务处理器,首先创建一个接口也就是InvocationHandler,为了模拟JDK,这里把接口的名字和JDK事务处理器名称一样,同样写一个方法叫做invoke(),用来表示对某个对象的某个方法进行业务处理,所以需要把某个对象以及对象的方法作为invoke()方法的参数传递进来,invoke(Objectobj,Methodmethod),方法作为参数使用到了java反射,需要把此包引入。这样InvocationHandler接口就完成了。

2、创建事务处理实现类比如说时间代理TimerProxy,实现了InvocationHandler接口,这样结构就成了

——————TimerProxyimplementsInvocationHandler{
————————-@override
————————-voidinvoke(Objectobj,Methodmethod){
———————————//业务逻辑<br>
—————————————method.invoke(目标对象,参数);
————————————//业务逻辑<br>
——————————}
—————————}

需要将目标对象传入,没有参数可以不写参数,创建代理对象的构造方法,初始化目标对象

3、在Proxy类的newProxyInstance()方法中,除了要把目标Class接口作为参数外,还需要把事务处理器InvocationHandler传进去,然后更改创建实例对象中硬编码的部分用事务处理器方法替代即可。难点在于字符串的拼接。

总结

在我们项目中代理模式有自己的实际意义,比如说我们想要调用某个jar包下的某个类,可以在调用这个类之前之后添加一些特殊的业务逻辑,这种方式也叫作AOP面向切面编程。(在不改变原有功能的基础上,添加额外的功能。)

以上就是本文关于Java动态代理(设计模式)代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • Java中的引用和动态代理的实现详解

    我们知道,动态代理(这里指JDK的动态代理)与静态代理的区别在于,其真实的代理类是动态生成的.但具体是怎么生成,生成的代理类包含了哪些内容,以什么形式存在,它为什么一定要以接口为基础? 如果去看动态代理的源代码(java.lang.reflect.Proxy),会发现其原理很简单(真正二进制类文件的生成是在本地方法中完成,源代码中没有),但其中用到了一个缓冲类java.lang.reflect.WeakCache<ClassLoader,Class<?>[],Class<?>

  • Java动态代理机制的实例详解

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

  • Java 动态代理原理分析

    Java 动态代理原理分析 概要 AOP的拦截功能是由java中的动态代理来实现的.说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行.Spring中的动态代理是使用Cglib进行实现的.我们这里分析的是JDK中的动态代理实现机制. 下面我们通过例子快速了解JDK中的动态代理实现方式. 示例 需要代理的接口 public interface IHello { public void sayHel

  • 浅谈Java注解和动态代理

    本文主要介绍Java中与注解和动态代理有关的部分知识,接下来我们看看具体内容. Annotation(注解) 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行. 1. 三个基本的Annotation: Override:限定重写父类方法, 该注解只能用于方法 Deprecated:用于表示某个程序元素(类, 方法等)已过时 SuppressWarnings:抑制编译器警告. 2.自定义Annotati

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

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

  • JAVA中的静态代理、动态代理以及CGLIB动态代理总结

    代理模式是java中最常用的设计模式之一,尤其是在spring框架中广泛应用.对于java的代理模式,一般可分为:静态代理.动态代理.以及CGLIB实现动态代理. 对于上述三种代理模式,分别进行说明. 1.静态代理 静态代理其实就是在程序运行之前,提前写好被代理方法的代理类,编译后运行.在程序运行之前,class已经存在. 下面我们实现一个静态代理demo: 静态代理 定义一个接口Target package com.test.proxy; public interface Target { p

  • JAVA提高第八篇 动态代理技术

    对于动态代理,学过AOP的应该都不会陌生,因为代理是实现AOP功能的核心和关键技术.那么今天我们将开始动态代理的学习: 一.引出动态代理 生活中代理应该是很常见的,比如你可以通过代理商去买电脑,也可以直接找厂商买电脑,最终都是买到了电脑.程序中也一样存在代理的情况,比如要为已经存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理.日志.计算方法耗时等等,那么我们会怎么做呢? 1.会编写一个与目标类拥有相同接口的代理类,代理类的每个方法调用目标类的相同方法,然后在调用方法前后加

  • 详解Java动态代理的实现及应用

    详解Java动态代理的实现及应用 Java动态代理其实写日常业务代码是不常用的,但在框架层一起RPC框架的客户端是非常常见及重要的.spring的核心思想aop的底层原理实现就使用到了java的动态代理技术. 使用代理可以实现对象的远程调用以及aop的实现. java的动态代理的实现,主要依赖InvoctionHandler(接口)和Proxy(类)这两个. 下面是一个例子 实现的代理的一般需要有个接口 package com.yasin.ProxyLearn; public interface

  • Java动态代理的示例详解

    目录 定义 分类 案例 需求 方案一:jdk动态代理 方案二:cglib动态代理 分析 总结 定义 动态代理指的是,代理类和目标类的关系在程序运行的时候确定的,客户通过代理类来调用目标对象的方法,是在程序运行时根据需要动态的创建目标类的代理对象. 分类 jdk动态代理 cglib动态代理 案例 需求 苹果公司通过苹果代理商来卖手机 方案一:jdk动态代理 定义抽象接口 /** * 售卖手机的接口(代理模式--抽象角色) * @author:liyajie * @createTime:2022/2

  • Java动态代理的应用详解

    动态代理其实就是java.lang.reflect.Proxy类动态的根据您指定的所有接口生成一个class byte,该class会继承Proxy类,并实现所有你指定的接口(您在参数中传入的接口数组):然后再利用您指定的classloader将 class byte加载进系统,最后生成这样一个类的对象,并初始化该对象的一些值,如invocationHandler,以即所有的接口对应的Method成员. 初始化之后将对象返回给调用的客户端.这样客户端拿到的就是一个实现你所有的接口的Proxy对象

  • Java编程复用类代码详解

    本文研究的主要是Java编程中的复用类,那么到底复用类是什么东西,又有什么用法,下面具体介绍. 看了老罗罗升阳的专访,情不自禁地佩服,很年轻,我之前以为和罗永浩一个级别的年龄,也是见过的不是初高中编程的一位大牛之一,专访之后,发现老罗也是一步一个脚印的人.别说什么难做,做不了,你根本就没去尝试,也没有去坚持. If you can't fly then run,if you can't run then walk, if you can't walk then crawl,but whateve

  • Spring JDK动态代理实现过程详解

    这篇文章主要介绍了Spring JDK动态代理实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. 创建项目 在 MyEclipse 中创建一个名称为 springDemo03 的 Web 项目,将 Spring 支持和依赖的 JAR 包复制到 Web 项目的 WEB-INF/lib 目录中,并发布到类路径下. 2. 创建接口 CustomerDao 在项目的 src 目录下创建一个名为 com.mengma.dao 的包,在该包下

  • 通过反射实现Java下的委托机制代码详解

    简述 一直对Java没有现成的委托机制耿耿于怀,所幸最近有点时间,用反射写了一个简单的委托模块,以供参考. 模块API public Class Delegater()//空参构造,该类管理委托实例并实现委托方法 //添加一个静态方法委托,返回整型值ID代表该方法与参数构成的实例.若失败,则返回-1. public synchronized int addFunctionDelegate(Class<?> srcClass,String methodName,Object... params)

  • Java回调函数实例代码详解

    首先说说什么叫回调函数? 在WINDOWS中,程序员想让系统DLL调用自己编写的一个方法,于是利用DLL当中回调函数(CALLBACK)的接口来编写程序,使它调用,这个就 称为回调.在调用接口时,需要严格的按照定义的参数和方法调用,并且需要处理函数的异步,否则会导致程序的崩溃. 这样的解释似乎还是比较难懂,这里举个简 单的例子: 程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序.程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法.目的达到

  • java实现队列数据结构代码详解

    什么是队列结构 一种线性结构,具有特殊的运算法则[只能在一端(队头)删除,在另一端(队尾)插入]. 分类: 顺序队列结构 链式队列结构 基本操作: 入队列 出队列 给出一些应用队列的场景 1):当作业被送到打印机的时候,就可以按到达的顺序排起来,因此每一份作业是队列的节点. 2):售票口的人买票的顺序的按照先来先买的顺序售票. 3):当所有的终端被占用,由于资源有限,来访请求需要放在一个队列中等候. 队列是先进先出的! 我们设置一个叫做LinkQueue<T>的泛型集合类,该类里面有 Node

  • java内部测试类代码详解

    我们一般使用的java内部类有4种形式:一般内部类.局部内部类.匿名内部类.静态内部类.以下是我作的一个测试,以说明各种内部类的特性. 有关内部类的特性,代码中有详细说明,如下. /* * java内部类测试 * * InterObj反射结果: * * private int i * private InterObj$InterA ia * public InterObj() * public static void main(java.lang.String[]) * private int

  • 一个通用的Java分页基类代码详解

    分页的基类 import java.util.List; /** * 分页显示的标准类,基本操作,是先给予-当前页数一共的数据条数-每页显示的条数, * 然后在初始化该类,得到总共页数,和开始序号和结束序号, * 然后数据库分页用到开始序号和结束序号,得到数据集合后赋值给该类的list属性, * * 然后把该类发送到jsp页面,进行访问 * @author admin * * @param <T> */ public class PageBean<T> { private int

随机推荐