Java设计模式模式---动态代理模式

代理模式

代理模式的意图是通过一个接口或者占位符来控制对该对象的访问

代理对象通常拥有一个和真实对象相同的接口,通过控制访问将请求合理的转发给底层真实的对象

动态代理(需要代理的类实现了接口)

通过反射类Proxy以及InvocationHandler回调接口实现的

动态代理是通过代理对象包装实际对象,通过代理对象来拦截对实际对象的请求,然后用代理再转发给实际对象,并且允许你在拦截调用之前或者之后增加自己的代码

创建动态代理

(1)获得实际对象实现的全部接口.obj是实际对象

Class[] classes=obj.getClass().getInterfaces();

(2)获得实际对象所属类的类加载器

ClassLoader loader=obj.getClass().getClassLoader();

(3)创建代理对象自身

这个对象所属类必须实现java.lang.reflect包的InvocationHandler接口。这个接口中定义了一个invoke方法

如下:通过实现InvocationHandler接口,重写invoke方法,result=method.invoke(obj, args)这一行是通过反射把目标调用转发给实际对象,在转发前后增加代码,实现一个简单的日志功能,这样代理类就创建好了

package xidian.lili.edu.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ImpatientProxy implements InvocationHandler{
	private Object obj;
	public ImpatientProxy(Object obj){
		this.obj=obj;
	}
	@Override
	public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
		Object result;
		long t1=System.currentTimeMillis();
		result=method.invoke(obj, args);
		long t2=System.currentTimeMillis();
		System.out.println("It takes "+(t2-t1)+" millis to invoke "+method.getName());
		return result;
	}
}

那么要使用代理类ImpatientProxy的对象,就要用到java.lang.reflect包的Proxy类,这个类需要一组接口,一个类加载器和ImpatientProxy实例对象,所以我们可以在代理类中增加如下方法,这个newInstance的静态方法为我们创建一个静态代理对象,这个方法返回的对象会实现被包装对象的所有接口,可以将其转化为任意类型的对象

package xidian.lili.edu.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ImpatientProxy implements InvocationHandler{
	private Object obj;
	public ImpatientProxy(Object obj){
		this.obj=obj;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result;
		long t1=System.currentTimeMillis();
		result=method.invoke(obj, args);
		long t2=System.currentTimeMillis();
		System.out.println("It takes "+(t2-t1)+" millis to invoke "+method.getName());
		return result;
	}
	public static Object newInstance(Object obj){
		ClassLoader loader=obj.getClass().getClassLoader();
		Class[] classes=obj.getClass().getInterfaces();
		return Proxy.newProxyInstance(loader, classes, new ImpatientProxy(obj));
	}
}

一旦你写了一个动态代理类,如上,只要对象实现了你想拦截的方法所属的接口,就可以使用代理类去包装该对象。

package xidian.lili.edu.proxy;

import java.util.HashSet;
import java.util.Set;

public class ShowDynamicProxy {

	public static void main(String[] args) {
		Set s=new HashSet();
		//用动态代理包装s对象
		s=(Set) ImpatientProxy.newInstance(s);
		s.add("hello world");
		s.isEmpty();
	}

}

在方法的执行前后对调用进行拦截,并创建自己的思想属于面向切片编程(AOP)

没有实现接口(cglib) 

CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。

GLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类

你可能感兴趣的:(java学习笔记)