【引用】模拟JDK实现动态代理(自写Proxy类和InvocationHandler接口)
来源:互联网 发布:微信双人夺宝源码 编辑:程序博客网 时间:2024/05/23 01:23
这个模拟实现,非常感谢马士兵老师的视频..在此,谢谢他的帮助.
首先明确下动态代理的用处..我们创建代理的用处就是,在不修改被代理对象源代码的情况下,为被代理对象添加一些其他的附属功能..通俗一点说,.我们想给某个方法的前后加一些逻辑,但是,我又不想修改原代码..然后,我们就想到了代理(可以用继承和聚合两种方式实现),但是,静态代理是我们需要手工的创建某个JAVA类,这样的话,很容易造成类膨胀.于是,又有了动态代理..让JDK自动帮我们生成class文件
最后,提醒下,注意看代码里的注释..因为都蛮重要的
在上一节中,我是这个需求,,一个接口Store.java,表示所有的商店,里面有一个方法sell()..然后有个具体的实现类Supermarket.java.这个类实现了Store.java接口.其实这个类也是被代理类,我们要做的就是,动态创建一个Supermarket的代理类...我们在代理类中动态的添加事务的代码...需求差不多就是这样了..
//我把动态生成的class文件放在D:\src\com\cjb\proxy下,所以,如果需要运行我下面写的这个小程序,必须先创建这个目录.
1 Store.java 和Supermarket.java
package com.cjb.proxy;
/**
* 类说明
* 表示商店
* @creator 陈静波
* @email
* @create-time May 20, 2010 9:43:40 AM
*/
public interface Store
{
public void sell();
}
package com.cjb.proxy;
/**
* 类说明
* @creator 陈静波
* @email
* @create-time May 20, 2010 9:54:48 AM
*/
public class Supermarket implements Store
{
@Override
public void sell()
{
System.out.println("sel in supermarket.....");
}
}
2 首先放上来客户端的调用方法.
可以看到,从客户端的情况来看,基本和我们用JDK的动态代理没什么区别了..
package com.cjb.proxy;
/**
* 类说明
* @creator 陈静波
* @email
* @create-time May 20, 2010 4:48:15 PM
*/
public class Test2
{
/**
* @param args
*/
public static void main(String[] args)
{
try
{
Supermarket sk = new Supermarket();//创建一个被代理对象..其实也就是真实对象..
Store s = (Store)Proxy.newInstance(Store.class, new TransactionInvocation(sk));//这个是代理对象,可以看出来,完全是动态创建出来的.我们根本没有创建这个类..
s.sell();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
3 InvocationHandler接口.从字面的意思来看,这个接口是 执行管理者 ..也就是,动态代理里面,方法如何执行通过这个接口来管理..动态代理可以认为是面向切面的编程..,我们对于方法的前后所做的逻辑是可以动态改变的..比如说,我们今天需要在被代理类的方法前后加一个事务管理,但是下次,我们需要加权限管理..为了满足这个需求,所以我们将如何执行(是添加事务管理还是添加权限管理)抽象出一个接口,然后我们去实现这个接口..在上面那个客户端的代码里,我们是 TransactionInvocation ,表示事务管理,如果明天我需要改成权限管理,那我们只需要实现一个 AuthorityInvocation,然后给Proxy.newInstance方法中传入这个参数就OK..而且,TransactionInvocation 和 AuthorityInvocation都是可以复用的..不只是创建Supermarket的动态代理里才可以用这个Handler..
package com.cjb.proxy;
import java.lang.reflect.Method;
/**
* 类说明
* @creator 陈静波
* @email
* @create-time May 20, 2010 3:29:51 PM
*/
public interface InvocationHandler
{
/**
*
* @param m 这个表示的是被代理的方法.我们可以理解为切入的方法
* Invoke方法表示执行方法,m就是指定了执行哪个方法
*/
void invoke(Method m);
}
4 TransactionInvocation 这个表示事务的管理..在第三条里面可以很清楚的说明了InvocationHandler是干什么用的..
package com.cjb.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 类说明
* @creator 陈静波
* @email
* @create-time May 20, 2010 3:56:43 PM
*/
public class TransactionInvocation implements InvocationHandler
{
Object target;
public TransactionInvocation(Object target)
{
super();
this.target = target;
}
@Override
public void invoke(Method m)
{
try
{
System.out.println("trasaction begin....");
m.invoke(target, new Object[]{});//这里必须是target,在JDK提供的invoke方法中,还有一个object
//这里必须澄清下,我在看马士兵老师说的模拟实现里,他加了一个object类型的参数,表示我们动态产生的
//代理对象..但是,我在实现以后发现不需要这个参数..
System.out.println("trasaction commit....");
} catch (IllegalArgumentException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (InvocationTargetException e)
{
e.printStackTrace();
}
}
}
5 最后就是最重要的Proxy类..在这个类里面用到了动态的创建java文件并编译它.这个我在上一节说明了..
package com.cjb.proxy;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;
/**
* 类说明
* @creator 陈静波
* @email
* @create-time May 20, 2010 3:17:18 PM
*/
public class Proxy
{
//动态产生对应的方法实现.这个比较重要..必须看懂
private static String getMethodStr(Class c)
{
Method[] methods = c.getMethods();
StringBuilder methodStr = new StringBuilder();
String rt = "\r\n";
for(Method m : methods)//遍历接口里的所有方法
{
methodStr.append("public void ").append(m.getName())//因为这个是模拟,所以直接写了void..呵呵
.append("()").append("{").append(rt)
.append("try{")
.append("Method method = ").append(c.getName()).append(".class.getMethod(\""+m.getName()+"\");").append(rt)
.append("h.invoke(method);").append(rt)
.append("}").append("catch (Exception e){e.printStackTrace();}").append(rt)
.append("}").append(rt);
}
return methodStr.toString();
}
/**
* @param c 表示被代理类接口对应的Class对象,我们这里是Store.class.注意,这里是个接口
* @param h 表示实现了invacationHandler接口的对象
* 这个就是我们实现切面的地方.这里定义了我们在被代理方法的前后添加什么功能
* 比如这里我们就是需要添加事务,那么,添加事务的代码就是写在这个对象里面
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Object newInstance(Class c,InvocationHandler h) throws Exception
{
String rt = "\r\n";
String source = "package com.cjb.proxy;"+rt
+ "import java.lang.reflect.Method;"+rt
+ "/**" + " * 类说明"+ rt
+ "* @creator 陈静波" + " * @email "+ rt
+ " * @create-time May 20, 2010 10:05:23 AM " + " */"+ rt
+ "public class Proxy1 implements "+c.getName()+ rt + "{"+ rt + "private InvocationHandler h;" + rt +
"public Proxy1(InvocationHandler h)"+ rt + " {" + " this.h = h;"+ rt
+ " }" + rt +
Proxy.getMethodStr(c) + rt+
"}";
String fileName = "d:/src/com/cjb/proxy/Proxy1.java";//在JDK的实现里,类名是$Proxy1,但是,可以发现,我们在使用的时候,这个类名无关紧要.
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(source);
fw.flush();
fw.close();
// compile
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,
null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null,
units);
t.call();
fileMgr.close();
// load into memory and create an instance
URL[] urls = new URL[] { new URL("file:/d:/src/") };//最后的"/"别忘记加
URLClassLoader ul = new URLClassLoader(urls);
Class claz = ul.loadClass("com.cjb.proxy.Proxy1");
System.out.println(claz.getName());
Constructor ctr = claz.getConstructor(InvocationHandler.class);
return ctr.newInstance(h);
}
}
- 【引用】模拟JDK实现动态代理(自写Proxy类和InvocationHandler接口)
- JDK自带的动态代理Proxy类和InvocationHandler接口
- 动态代理两个类Proxy和InvocationHandler的模拟实现
- JDK使用InvocationHandler和Proxy实现动态代理
- JDK动态代理proxy,InvocationHandler
- jdk proxy invocationhandler (jdk动态代理)
- 使用JDK中的InvocationHandler、Proxy实现动态代理
- JAVA JDK 动态代理 proxy invocationHandler
- java动态代理实现Proxy和InvocationHandler cglib
- 动态代理 Proxy InvocationHandler
- 动态代理proxy ,InvocationHandler
- 动态代理 Proxy InvocationHandler
- JAVA动态代理实现 Proxy InvocationHandler
- 使用反射生成JDK动态代理---使用Proxy和InvocationHandler创建动态代理
- 使用Proxy和InvocationHandler创建动态代理
- 使用java.lang.reflect.Proxy和InvocationHandler创建动态代理(仅代理接口)
- Proxy和InvocationHandler模拟Aop底层实现
- JDK的动态代理深入解析(Proxy,InvocationHandler)
- Spring注解入门
- 【引用】[转]my sql存储过程,触发器
- 【引用】struts2标签不显示Label的解决方法
- 万亿级调用系统:微信序列号生成器架构设计及演变
- 【引用】读JDK动态代理源码(Proxy类)
- 【引用】模拟JDK实现动态代理(自写Proxy类和InvocationHandler接口)
- Java数字格式化
- Hibernate级联删除提示约束失败DELETE
- 【引用】Spring MVC快速上手教程(转)
- 【引用】ORACLE 10G 的安装过程
- Oracle数据库监听配置
- Spring
- Struts2使用 -- Convention插件
- Android中Context详解 ---- 你所不知道的Context