下面的代码实现一个简单的代理类,代码来自《java与模式》,该例子的任务是为一个Vector对象提供一个代理对象,当Vector的任何方法被调用之前和调用之后,分别打印出两条信息,这表明这个代理对象有能力截获和控制这个Vector对象。
/*
* 实现一个简单的代理类,代码来自《java与模式》该例子
* 的任务是为一个Vector对象提供一个代理对象,当Vector
* 的任何方法被调用之前和调用之后,分别打印出两条信息,
* 这表明这个代理对象有能力截获和控制这个Vector对象。
*/
public class VectorProxy implements InvocationHandler{
//包含被代理的对象,这里是一个Vector
private Object targetObj;
//为被代理对象设置一个get方法,这里只是我用来测试所用
public Object getTargetObj() {
return targetObj;
}
//构造方法,并接受被代理对象作为参数
public VectorProxy(Object targetObj) {
this.targetObj = targetObj;
}
//一个静态工厂方法,用来获得代理对象,传递被代理对象作为参数
public static Object factory(Object obj) {
Class clazz = obj.getClass();
//调用newProxyInstance方法得到一个代理对象,这个方法下面会详述
Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new VectorProxy(obj));
return proxy;
}
//实现InvocationHandler接口的invoke方法,该方法会被自动调用
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before invoke:" + method.getName()); //调用被代理对象某方法之前执行一句打印
if(args != null) {
for(Object o:args)
System.out.println(o);
}
//通过代理对象获得被代理对象,首先调用Proxy的静态方法getInvocationHandler,并传递代理对象获得代理类中
//关联的InvaocationHandler的实现类对象,再接着调用我们上面定义的获取被代理对象的get方法
Object tarObj = ((VectorProxy)(Proxy.getInvocationHandler(proxy))).getTargetObj();
System.out.println(tarObj == targetObj); //测试通过上面方法获得的被代理对象是否就是当前VectorProxy实例中的对象
Object resultObj = method.invoke(tarObj, args); //这里直接传递targetObj即可,对被代理对象调用某方法,并传递参数
System.out.println("after invoke:" + method.getName()); //调用被代理对象某方法之后执行一句打印
return resultObj;
}
public static void main(String[] args) {
List v = null;
//new Vector(10)是被代理对象,它被传入InvocationHandler中,作为成员变量,InvocationHandler的实现类也会作为Proxy的成员变量
v = (List) factory(new Vector(10));
//对代理对象调用被代理对象所拥有的方法,此时会自动调用Proxy中关联的VectorProxy实例的invoke方法
v.add("NEW");
System.out.println(v.get(0));
}
}
上面的代码中我们创建类VectorProxy并实现InvocationHandler接口,当然它需要实现InvocationHandler接口中的invoke方法了。
我们首先需要创建一个代理对象,并在代理对象中指定被代理对象,以及指定被代理对象的所有实现接口:
Class clazz = obj.getClass();
//obj为被代理对象
Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new VectorProxy(obj)); //传递三个参数:被代理对象的类加载器,被代理对象所实现的接口数组以及一个InvocationHandler实现类对象,注意这个实现类对象中包含了被代理对象。
现在我们就用生成的代理对象来代替被代理对象,直接对代理对象进行操作。
当Client需要调用被代理对象中的方法时,这些方法是它所实现接口中的方法(
getInterfaces()
),此时我们是对代理对象调用这些方法,代理对象便会自动调用代理对象中相关联的InvocationHandler实现类的invoke方法,即我们实现的
public Object invoke(Object proxy, Method method, Object[] args)
我们可以在invoke方法中实现我们需要的逻辑,包括调用被代理对象对应的方法:
method.invoke(targetObject,args) //targetObject为被代理对象,被代理对象是作为InvocationHandler实现类的成员变量,args为传递给方法的参数,
还可以在调用被代理对象相关方法之前和之后执行某些操作。
当我们对代理对象执行某些操作,这些操作和对被代理对象执行的操作一样,其实我们的本意也是对被代理对象进行某些操作,在本例中,即在vector中添加,删除,获取对象等。此时会自动调用代理对象中相关联的InvocationHandler接口的实现类的invoke方法,同时将代理对象,被调用的方法以及方法的参数作为参数传递给invoke,因此我们便可以在invoke中实现我们需要的操作。
JDK
中具体的动态代理类是怎么产生的呢?
1.
产生代理类$Proxy0
类
执行了
Proxy.
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0
类,它继承Proxy
对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode
,toString
和equals
三个方法),但是还没有具体的实现体;
2.
将代理类$Proxy0
类加载到JVM
中
这时候是根据
Proxy.
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
它的第一个参数----
就是被代理类的类加载器,把当前的代理类加载到JVM
中
3.
创建代理类$Proxy0
类的对象
调用的$Proxy0
类的$Proxy0
(InvocationHandler
)构造函数,生成$Proxy0
类的对象
参数就是
Proxy.
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
它的第三个参数
这个参数就是我们自己实现的InvocationHandler
对象,我们知道InvocationHandler
对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0
对象调用所有要实现的接口的方法,都会调用InvocationHandler
对象的invoke
()方法实现;
4.
生成代理类的class byte
动态代理生成的都是二进制class
字节码
----------------------------------------------------------------
我们下面来简单看一下Proxy类,Proxy类位于java.lang.reflect中,
首先看看它的成员变量和构造函数:
private final static Class[] constructorParams = { InvocationHandler.class };
protected InvocationHandler h;
private Proxy() {
}
protected Proxy(InvocationHandler h) {
this.h = h;
}
上面的成员变量和第二个构造函数相信大家应该不会陌生吧,在一个Proxy实例中包含了一个InvocationHandler的实例。
接下来我们再看Proxy类的静态方法
newProxyInstance
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
//通过被代理的类加载器和接口数组来动态生成一个代理类Class
Class cl = getProxyClass(loader, interfaces);
try {
//通过Class的getConstructor方法获得相关的Constructor对象,注意传递的参数是一个Class数组
Constructor cons = cl.getConstructor(constructorParams);
//利用Constructor创建一个代理类实例,并将InvocatioHandler实例作为参数传递给它
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
//省略相关代码
}
接下来关注更重要的getProxyClass方法:
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
} //这段代码大家应该都能看懂,规定实现的借口不能超过65535个
Class proxyClass = null;
//定义一个接口名字数组和一个接口Set
String[] interfaceNames = new String[interfaces.length];
Set interfaceSet = new HashSet(); // for detecting duplicates
//遍历接口数组,将通过getName方法获得接口的名字,并通过被代理对象的类加//载器加载接口生成Class对象,即生成Class字节码
for (int i = 0; i < interfaces.length; i++) {
String interfaceName = interfaces[i].getName();
Class interfaceClass = null;
try {
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != interfaces[i]) {
...
}
if (!interfaceClass.isInterface()) {
...
}
if (interfaceSet.contains(interfaceClass)) {
...
}
//将接口字节码Class对象保存到Set中,并将接口名保存到接口名数组中
interfaceSet.add(interfaceClass);
interfaceNames[i] = interfaceName;
}
//将接口名字数组转化为一个List
Object key = Arrays.asList(interfaceNames);
//loaderToCache也是一个Map.它的key是classloader,对应的value是对应的缓存,也是一个HashMap.他把对应的不同的classloader放到loaderToCache里,如果下次还要调用这个方法创建代理,并传入的是同一个classloader,那么可以直接从cache里取..增加速度.当然,如果没有,则创建一条记录,放到loaderToCache里
Map cache;
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
}
synchronized (cache) {
do {
//这里从cache里获取对应的Object..第一次执行的话,明显获取到的是Null..key表示的是用接口名字转换而来的list.
Object value = cache.get(key);
if (value instanceof Reference) {
proxyClass = (Class) ((Reference) value).get();
}
if (proxyClass != null) {
// proxy class already generated: return it
return proxyClass;
} else if (value == pendingGenerationMarker) {
// proxy class being generated: wait for it
try {
cache.wait();
} catch (InterruptedException e) {
}
continue;
} else {
cache.put(key, pendingGenerationMarker);
break;
}
} while (true);
}
try {
String proxyPkg = null; // package to define proxy class in
for (int i = 0; i < interfaces.length; i++) {
int flags = interfaces[i].getModifiers();
if (!Modifier.isPublic(flags)) {
String name = interfaces[i].getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) { // if no non-public proxy interfaces,
proxyPkg = ""; // use the unnamed package
}
{
long num;
synchronized (nextUniqueNumberLock) {
num = nextUniqueNumber++;
}
String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
} finally {
synchronized (cache) {
if (proxyClass != null) {
cache.put(key, new WeakReference(proxyClass));
} else {
cache.remove(key);
}
cache.notifyAll();
}
}
return proxyClass;
}
分享到:
相关推荐
代理模式java代码 Proxy(4) 开发宝典......
代理模式java代码 Proxy(1) java 学习必备......
代理模式java代码 Proxy(5) 2个代理类 开发宝典
我自己用eclipse写的java代码,可以直接用eclipse导入,也可以直接用java -jar proxy_sample.jar执行 代码量很小,尽量通过注释进行说明 本例实现了InvocationHandler...在研究代理模式(Proxy模式)的朋友可以交流一下
利用JAVA代理Proxy机制实现spring对ibaits的MapperScannerConfigurer功能 详细:http://blog.csdn.net/wq105032007067/article/details/8812598
JAVA 通过proxy代理方式访问internet资源,
NULL 博文链接:https://cn-done.iteye.com/blog/1743191
代理模式java代码 Proxy(3) 开发必备宝典......
代理模式java代码 Proxy(2) 开发必备宝典......
设计模式C++学习之代理模式(Proxy)
java三种代理模式的源码,包含泛型改写
- 代理模式 - 静态代理与动态代理 - 常见的动态代理实现 - JDK Proxy - CGLIB - JDK Proxy 和 CGLIB 的对比 - 动态代理的实际应用 - Spring AOP 说在前面:今天我们来聊一聊 Java 中的代理,先来聊聊故事...
全部高质量代理模式proxy的java源程序 java.proxy,代理模式源码,设计模式,apache开源项目源码commons-proxy-1.0-src 各种代理模式操作的工具类源码以及代理模式案例源码,你会从中得到意想不到的效果! apache...
JAVA Proxy 代理模式
Proxy 模式学习代码,包括静态代理,动态代理,cglib等
java 代理模式实现代码及设计详解:动态代理模式、静态代理模式
用sun的JDK API实现java的动态代理类
获取网络资源,使用动态代理ip解决单个ip访问次数限制问题
NULL 博文链接:https://sunlibao123.iteye.com/blog/1837500
代理模式又叫Proxy模式(英文)。所谓的代理,就是一个人或者一个机构代替另一个人或者另一个机构去做一些事情。(类似于中介或者代理商)。