`
836811384
  • 浏览: 545796 次
文章分类
社区版块
存档分类
最新评论

深入研究java中的静态代理和动态代理

 
阅读更多
java编码中经常用到代理,代理分为静态代理和动态代理。其中动态代理可以实现spring中的aop。
一、静态代理:程序运行之前,程序员就要编写proxy,然后进行编译,即在程序运行之前,代理类的字节码文件就已经生成了
被代理类的公共父类
packagestaticproxy;
publicabstractclassBaseClass{
publicabstractvoidadd();
}
被代理类
packagestaticproxy;
publicclassAextendsBaseClass{
publicvoidadd(){
System.out.println("Aadd!");
}
}
代理类
packagestaticproxy;
publicclassProxy{
BaseClassbaseClass;
publicvoidadd(){
baseClass.add();
}
publicvoidsetBaseClass(BaseClassbaseClass){
this.baseClass=baseClass;
}
publicstaticvoidmain(String[]args){
BaseClassbaseClass=newA();
Proxyproxy=newProxy();
proxy.setBaseClass(baseClass);
proxy.add();
}
}
二、动态代理:实际的代码在编译期间并没有生成,而是在运行期间运用反射机制动态的生成
被代理类接口
packagejdkproxy;
publicinterfaceService{
publicvoidadd();
publicvoidupdate();
}
被代理类A
packagejdkproxy;
publicclassAServiceimplementsService{
publicvoidadd(){
System.out.println("AServiceadd>>>>>>>>>>>>>>>>>>");
}
publicvoidupdate(){
System.out.println("AServiceupdate>>>>>>>>>>>>>>>");
}
}
被代理类B
packagejdkproxy;
publicclassBServiceimplementsService{
publicvoidadd(){
System.out.println("BServiceadd---------------");
}
publicvoidupdate(){
System.out.println("BServiceupdate---------------");
}
}
代理类
packagejdkproxy;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.Method;
publicclassMyInvocationHandlerimplementsInvocationHandler{
privateObjecttarget;
MyInvocationHandler(){
super();
}
MyInvocationHandler(Objecttarget){
super();
this.target=target;
}
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
//程序执行前加入逻辑
System.out.println("before-----------------------------");
//程序执行
Objectresult=method.invoke(target,args);
//程序执行后加入逻辑
System.out.println("after------------------------------");
returnresult;
}
publicObjectgetTarget(){
returntarget;
}
publicvoidsetTarget(Objecttarget){
this.target=target;
}
}
测试类
packagejdkproxy;
importjava.lang.reflect.Proxy;
publicclassTest{
publicstaticvoidmain(String[]args){
ServiceaService=newAService();
MyInvocationHandlerhandler=newMyInvocationHandler(aService);
//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例
ServiceaServiceProxy=(Service)Proxy.newProxyInstance(aService
.getClass().getClassLoader(),aService.getClass()
.getInterfaces(),handler);
//由动态生成的代理对象来aServiceProxy代理执行程序,其中aServiceProxy符合Service接口
aServiceProxy.add();
System.out.println();
aServiceProxy.update();
//以下是对B的代理
//ServicebService=newBService();
//MyInvocationHandlerhandler=newMyInvocationHandler(bService);
//ServicebServiceProxy=(Service)Proxy.newProxyInstance(bService
//.getClass().getClassLoader(),bService.getClass()
//.getInterfaces(),handler);
//bServiceProxy.add();
//System.out.println();
//bServiceProxy.update();
}
}
输出结果:
before-----------------------------
AServiceadd>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
AServiceupdate>>>>>>>>>>>>>>>
after------------------------------
其中上述标红的语句是产生代理类的关键代码,可以产生一个符合Service接口的代理对象,newProxyInstance这个方法会做这样一件事情,他将把你要代理的全部接口,用一个由代码动态生成的类来实现,该类中所有的接口中的方法都重写为调用InvocationHandler.invoke()方法。
下面详细介绍是如何实现代理对象的生成的
Proxy的newProxyInstance方法,其中,为了看起来方便,已经将该方法中的异常处理语句删减
下下面public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws
publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces,InvocationHandlerh)throwsIllegalArgumentException
{
if(h==null){
thrownewNullPointerException();
}
//生成指定的代理类
Classcl=getProxyClass(loader,interfaces);
Constructorcons=cl.getConstructor(constructorParams);
//生成代理类的实例,并把MyInvocationHandler的实例传给它的构造方法,代理类对象实际执行都会调用MyInvocationHandler的invoke方法,所以代理类对象中维持一个MyInvocationHandler引用
return(Object)cons.newInstance(newObject[]{h});
}
其中getProxyClass方法返回代理类的实例
Proxy的getProxyClass方法
publicstaticClass<?>getProxyClass(ClassLoaderloader,Class<?>...interfaces)throwsIllegalArgumentException
{
//前面省略很多缓存、异常处理、判断逻辑代码,为了使程序更加突出
byte[]proxyClassFile=ProxyGenerator.generateProxyClass(proxyName,interfaces);
proxyClass=defineClass0(loader,proxyName,proxyClassFile,0,proxyClassFile.length);
proxyClasses.put(proxyClass,null);
returnproxyClass;
}
下面看ProxyGenerator的generateProxyClass方法,该方法最终产生代理类的字节码文件:
publicstaticbyte[]generateProxyClass(finalStringname,Class[]interfaces)
{
ProxyGeneratorgen=newProxyGenerator(name,interfaces);
//这里动态生成代理类的字节码
finalbyte[]classFile=gen.generateClassFile();
//如果saveGeneratedFiles的值为true,则会把所生成的代理类的字节码保存到硬盘上
if(saveGeneratedFiles){
java.security.AccessController.doPrivileged(
newjava.security.PrivilegedAction<Void>(){
publicVoidrun(){
try{
FileOutputStreamfile=
newFileOutputStream(dotToSlash(name)+".class");
file.write(classFile);
file.close();
returnnull;
}catch(IOExceptione){
thrownewInternalError(
"I/Oexceptionsavinggeneratedfile:"+e);
}
}
});
}
//返回代理类的字节码
returnclassFile;
}
那么最终生成的代理类到底是什么样子呢,如下(省略了一下equals,hashcode,toString等方法,只展示构造函数和add方法):
  1. publicfinalclass$Proxy11extendsProxyimplementsService
  2. {
  3. //构造方法,参数就是刚才传过来的MyInvocationHandler类的实例
  4. public$Proxy11(InvocationHandlerinvocationhandler)
  5. {
  6. super(invocationhandler);
  7. }
  8. /**
  9. *继承的add方法,重写,调用MyInvocationHandler中的invoke方法
  10. */
  11. publicfinalvoidadd()
  12. {
  13. try
  14. {
  15. //实际上就是调用MyInvocationHandler中的invoke方法
  16. super.h.invoke(this,m3,null);
  17. return;
  18. }
  19. catch(Error_ex){}
  20. catch(Throwablethrowable)
  21. {
  22. thrownewUndeclaredThrowableException(throwable);
  23. }
  24. }
  25. }
注意:java的jdk中得动态代理有一个限制条件,就是必须要被代理的类基于统一的接口,否则不能够实现。如果必须要使代理突破这个限制,那么可以尝试运用cglib来实现动态代理。cglib能够使方法执行更加高效,但是可能在动态创建类的过程中效率会稍微低一些,缓存该过程生成的类即可。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics