JDK 动态代理

萝らか妹 提交于 2020-03-21 16:42:35

3 月,跳不动了?>>>

JDK 代理

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

静态代理:

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

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<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>();
	
	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
删除用户:1
end 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动态代理只能对实现了接口的类进行代理,这也是其局限性之一.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!