博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JDK 动态代理
阅读量:6496 次
发布时间:2019-06-24

本文共 6240 字,大约阅读时间需要 20 分钟。

hot3.png

JDK 代理

  java中的代理是指某个对象的一个替代者,该替代者暂时担任了被代理对象的职责,代理对象包含了原始对象的所有方法,而且还有可能会附加一些额外的方法。代理对象就是在不破坏原始对象的前提下发挥和原始对象相同甚至更多的功能,Java中的代理分为静态代理和动态代理两种。

124821_qcMr_820500.jpg

静态代理:

    在为某个对象生成代理对象之前,就已经知道代理对象要实现的功能或者发挥的作用,那么只需要重新写一个代理类,该类和原始类实现了相同的接口,然后在代理类的方法中加入某些附加的处理操作,这种代理类对象的行为是确定的,所以称为静态代理。

public interface Eatable{     void eat();}class Person implements Eatable{     public void eat(){          System.out.println("吃饭");     }}class ProxyPerson implements Eatable{     private Person person;     public ProxyPerson(Person person){          this.person = person;     }     public void eat(){          System.out.println("吃饭之前先要洗手!");          person.eat();     }}

   上述代码中,先定义了一个接口Eatable.该接口中有一个eat方法,然后有一个原始类Person实现了该接口,但是此时我们不想用Person对象的eat()方法,因为这种Person在吃饭的时候总是不洗手,这种Person太恶心了!很明确,我们需要一个洗手的Person,这就出现了ProxyPerson,ProxyPerson中组合了Person,ProxyPerson的eat方法中先执行附加的操作,然后在执行真正的eat操作。这就是静态代理。

     但是有一个问题,假如我们又要在吃饭之后洗碗,那又得重新写一个ProxyPerson2,包含一个eat方法,该方法先吃饭,然后在洗碗,如果又出现一个需求,我们要的这个Person既要能饭前洗手,还能饭后洗碗,那怎么办?再写一个ProxyPerson3?这样下去,随着我们的需求越来越多,我们的类就会膨胀到爆。这时候动态代理就发挥作用了。

动态代理:

    动态代理跟静态代理的区别是代理类不是开发者用源代码定义出的,而是通过java的反射机制在程序运行期生成的。jdk动态代理的主要靠InvocationHandler借口和Proxy类配合来实现的。JDK动态代理的被代理对象一定要有接口,通过动态生成接口实现类然后通过组合的方式实现在方法前后do something.

InvocationHandler接口主要方法:

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

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

Proxy类主要属性和方法: 

public class Proxy {    protected InvocationHandler h;     private Proxy() {    }     protected Proxy(InvocationHandler h) {        this.h = h;    }     public static Class
 getProxyClass(ClassLoader loader,Class
... interfaces) throws IllegalArgumentException {     }     public static Object newProxyInstance(ClassLoader loader,Class
[] interfaces,InvocationHandler h)throws IllegalArgumentException {     }}

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

代码实例为一个方法性能监视:

    接口:

package com.qding.agency.service;public interface UserService {	public int addUser(String name);		public void delUser(Long userId);}

  接口实现类:

package com.qding.agency.service.impl;import com.qding.agency.service.UserService;public class UserServiceImpl implements UserService {	@Override	public int addUser(String name) {		System.out.println("新增用户:"+name);		try {			Thread.currentThread().sleep(20);		} catch (InterruptedException e) {			e.printStackTrace();		}		return 1;	}	@Override	public void delUser(Long userId) {		System.out.println("删除用户:"+userId);		try {			Thread.currentThread().sleep(40);		} catch (InterruptedException e) {			e.printStackTrace();		}	}	}

代理处理类:

package com.qding.agency.hander;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import com.qding.agency.monitor.PerformanceMonitor;public class PerformanceHander implements InvocationHandler {		private Object target;		public PerformanceHander(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;	}}

监视类:

package com.qding.agency.monitor;public class PerformanceMonitor {		//通过一个Threadlocal保存调用线程的相关的性能监视信息	private static ThreadLocal
 performanceRecord = new ThreadLocal
(); public static void begin(String method){ System.out.println("begin Monitor"+method); MethodPerformance mp =new MethodPerformance(method); performanceRecord.set(mp); } public static void end(){ System.out.println("end Monitor...."); MethodPerformance mp =performanceRecord.get(); mp.printPerformance(); }}

方法耗时计时:

package com.qding.agency.monitor;public class MethodPerformance {	private long begin;	private long end;	private String serviceMethod;	public MethodPerformance(String serviceMethod) {		this.serviceMethod = serviceMethod;		// 记录方法开始时间		this.begin = System.currentTimeMillis();	}	public void printPerformance() {		// 计算方法耗时并打印		end = System.currentTimeMillis();		long elapsed = end - begin;		System.out.println(serviceMethod + "花费" + elapsed + "毫秒");	}}

测试类:

package com.qding.agency.test;import java.lang.reflect.Proxy;import com.qding.agency.hander.PerformanceHander;import com.qding.agency.service.UserService;import com.qding.agency.service.impl.UserServiceImpl;public class TestUserPerformanceinfo {	public static void main(String[] args) {		UserService userservice = new UserServiceImpl();		PerformanceHander ph = new PerformanceHander(userservice);		UserService proxy = (UserService) Proxy.newProxyInstance(userservice.getClass()				.getClassLoader(), userservice.getClass().getInterfaces(), ph);		proxy.addUser("张三");		proxy.delUser(1l);	}}

运行结果:

begin Monitorcom.qding.agency.service.impl.UserServiceImpl.addUser新增用户:张三end Monitor....com.qding.agency.service.impl.UserServiceImpl.addUser花费31毫秒begin Monitorcom.qding.agency.service.impl.UserServiceImpl.delUser删除用户:1end Monitor....com.qding.agency.service.impl.UserServiceImpl.delUser花费47毫秒

以上代码小实例是在学习spring AOP时看到的,对于理解动态代理有点小绕,其实jdk动态代理就是要有一个接口,然后接口实现类,最重要的是代理处理类要实现InvocationHandler 接口,然后在invoke方法中写些 do something 

       beofor do something

    Object result = paramMethod.invoke(object, paramArrayOfObject);

        after do something

在使用时,创建需要被代理的目标类。将目标类放入代理处理类,创建代理类实例,调用代理实例。

       

//希望被代理的目标类UserService userservice = new UserServiceImpl();//将目标类放入代理处理类中PerformanceHander ph = new PerformanceHander(userservice);//创建代理实例UserService proxy = (UserService) Proxy.newProxyInstance(userservice.getClass().getClassLoader(), userservice.getClass().getInterfaces(), ph);//调用代理实例		proxy.addUser("张三");proxy.delUser(1l);

proxy在运行时其实是JDK动态生成的一个代理类($proxy0)

(1)newProxyInstance方法调用getProxyClass方法,返回代理类的class:$Proxy0类。同时,java还让这个动态生成的$Proxy0类实现了newProxyInstance方法接收的所有接口,并继承了Proxy类。 得到的其实是一个类名叫$Proxy0 extends Proxy implements counter.getClass().getInterfaces()的类

(2)实例化这个动态生成的$Proxy0类的一个实例。因为$Proxy0类也继承了Proxy类,所以可以调用Proxy类的protected Proxy(InvocationHandler h)构造函数,并将我们定义的InvocationHandler子类的一个实例作为参数。

(3)通过第二步骤,我们拥有了一个代理类的实例,并且这个代理类的实例包含一个InvocationHandler实例。将该代理类实例返回,并且强制类型转换为接口类型:UserService。

(4)调用代理类实例的addUser()方法。在调用add方法时,其实是调用了代理类实例包含的那个InvocationHandler实例的invoke方法,即super.h.invoke(this, , )。

JDK动态代理只能对实现了接口的类进行代理,这也是其局限性之一.

转载于:https://my.oschina.net/u/2489481/blog/535165

你可能感兴趣的文章
R语言画曲线图
查看>>
Python培训 之二 Python基础语法
查看>>
C#多线程开发
查看>>
.net连接oracle数据库
查看>>
java代码实现从键盘输入编号,输出价格,并且不再编号内的,无效输入!!!!...
查看>>
java代码多线程实现如下
查看>>
vue.js
查看>>
linux命令(4):top 命令(性能分析工具)
查看>>
Error:UNEXPECTED TOP-LEVEL ERROR:
查看>>
egg框架实现表单验证及获取验证的错误信息
查看>>
根据判断数组不为空然后取他的值----数组不会为空---只能判断其size是否大于0...
查看>>
c#多线程2
查看>>
Eclipse 安装 SVN 插件的两种方法
查看>>
Microsoft Visual Studio Ultimate 2012 旗舰版 有效注册密钥
查看>>
嵌入式驱动开发之sensor---"VIP0 PortA", "VIP0 PortB", "VIP1 PortA", "VIP1 PortB",dvo0(vout1) dvo1(vout0)...
查看>>
c# 扩展方法奇思妙用基础篇三:byte 常用扩展
查看>>
jsp运行原理分析
查看>>
数据库SQL语句中 查询选修了全部课程的学生的学号和姓名
查看>>
Prometheus监控etcd存储
查看>>
士兵杀敌 三 --- O( 1 ) 的时间复杂度 .
查看>>