Java动态代理学习2——静态代理和动态代理

一、代理模式

代理模式是常用的java设计模式,特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

按照代理的创建时期,代理类可以分为两种:

静态代理:由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。动态代理:在程序运行时运用反射机制动态创建而成。

二、静态代理

    publicinterfaceCountDao { //查看账户方法 publicvoidqueryCount(); //修改账户方法 publicvoidupdateCount(); } publicclassCountDaoImplimplementsCountDao { publicvoidqueryCount() { System.out.println("查看账户方法..."); } publicvoidupdateCount() { System.out.println("修改账户方法..."); } } publicclassCountProxyimplementsCountDao { privateCountDaocountDao; publicCountProxy(CountDaocountDao) { this.countDao=countDao; } @OverridepublicvoidqueryCount() { System.out.println("事务处理之前"); countDao.queryCount(); System.out.println("事务处理之后"); } @OverridepublicvoidupdateCount() { System.out.println("事务处理之前"); countDao.updateCount(); System.out.println("事务处理之后"); } } publicclassTestCount { publicstaticvoidmain(String[]args) { CountProxycountProxy=newCountProxy(newCountDaoImpl()); countProxy.updateCount(); countProxy.queryCount(); } }

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。

三、动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

1 JDK动态代理

JDK动态代理中包含一个类和一个接口

InvocationHandler接口

    publicinterfaceInvocationHandler{ publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable; }

Object proxy:指被代理的对象。Method method:要调用的方法Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject

Proxy类

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

    publicstaticObjectnewProxyInstance(ClassLoaderloader,Class<?>[]interfaces, InvocationHandlerh)throwsIllegalArgumentException

ClassLoader loader:类加载器Class<?>[] interfaces:得到全部的接口InvocationHandler h:得到InvocationHandler接口的子类实例

    publicinterfacePersonService { publicvoidsave(); } publicclassPersonServiceImplimplementsPersonService { publicvoidsave() { System.out.println("人员增加"); } } importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; importjava.lang.reflect.Proxy; publicclassPersonProxyimplementsInvocationHandler { //目标对象 privateObjecttarget; //返回一个代理类对象 publicObjectcreateProxyInstance(Objecttarget) { this.target=target; returnProxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //上述代码中调用的this就是当前代理对象,会自动调用该方法 publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable { Objectresult=null; System.out.println("前置通知"); try{ result=method.invoke(target,args); System.out.println("后置通知"); } catch(Exceptione) { System.out.println("例外通知——出错啦"); } finally{ System.out.println("最终通知——结束啦"); } returnresult; } } publicclassTestProxy { publicstaticvoidmain(String[]args) { PersonProxybp=newPersonProxy(); PersonServiceps=(PersonService)bp.createProxyInstance(newPersonServiceImpl()); ps.save(); } }

前置通知人员增加后置通知最终通知——结束啦

JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。

2 CGLIB动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承所以不能对final修饰的类进行代理。

    publicinterfacePersonService { publicvoidsave(); } publicclassPersonServiceImplimplementsPersonService { publicvoidsave() { System.out.println("人员增加"); } } importjava.lang.reflect.InvocationHandler; importjava.lang.reflect.Method; importjava.lang.reflect.Proxy; /** *使用CGLIB动态代理 */publicclassPersonProxyimplementsMethodInterceptor { privateObjecttarget; //返回一个代理类对象 publicObjectcreateProxyInstance(Objecttarget) { this.target=target; Enhancerenhancer=newEnhancer(); //设置目标类为父类,会覆盖目标类的非final方法 enhancer.setSuperclass(this.target.getClass()); //回调方法 enhancer.setCallback(this); //创建代理对象 returnenhancer.create(); } //上述代码中调用的this就是当前代理对象,会自动调用该方法 //方法一 @OverridepublicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxyproxy)throwsThrowable { Objectresult=null; System.out.println("前置通知"); try{result=method.invoke(target,args); System.out.println("后置通知"); } catch(Exceptione) { System.out.println("例外通知——出错啦"); } finally{ System.out.println("最终通知——结束啦"); } returnresult; } } publicclassPersonProxy2implementsMethodInterceptor { privateObjecttarget; //返回一个代理类对象 publicObjectcreateProxyInstance(Objecttarget) { this.target=target; Enhancerenhancer=newEnhancer(); //设置目标类为父类,会覆盖目标类的非final方法 enhancer.setSuperclass(this.target.getClass()); //回调方法 enhancer.setCallback(this); //创建代理对象 returnenhancer.create(); } //方法二 publicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxyproxy)throwsThrowable { Objectresult=null; System.out.println("前置通知"); try{ result=proxy.invokeSuper(obj,args); System.out.println("后置通知"); } catch(Exceptione) { System.out.println("例外通知——出错啦"); } finally{ System.out.println("最终通知——结束啦"); } returnresult; } } publicclassTestProxy { publicstaticvoidmain(String[]args) { PersonProxycglib=newPersonProxy(); PersonServiceClassps1=(PersonServiceClass)cglib.createProxyInstance(newPersonServiceClass()); ps1.save(); System.out.println("--------------------"); PersonProxy2cglib2=newPersonProxy2(); PersonServiceClassps2=(PersonServiceClass)cglib2.createProxyInstance(newPersonServiceClass()); ps2.save(); } }

前置通知增加人员后置通知最终通知——结束啦——————–前置通知增加人员后置通知最终通知——结束啦

参考并演绎自地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

IT徐胖子的专栏” 博客,请务必保留此出处http://woshixy.blog.51cto.com/5637578/1066208

如果心在远方,只需勇敢前行,梦想自会引路,

Java动态代理学习2——静态代理和动态代理

相关文章:

你感兴趣的文章:

标签云: