黑马程序员----动态代理

来源:互联网 发布:网络流行语大全网站 编辑:程序博客网 时间:2024/06/05 20:27
------- android培训java培训、期待与您交流! ----------

 什么是代理:要为已存在的多个具有相同接口的目标类的方法增加一些系统功能。比如:事物处理,异常处理,日志等。
 也就是业务交叉。面向切面编程AOP(Aspect Oriented program)
  
 什么是动态代理:JVM可以再运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
 两中实现方式:
JVM生成动态类必须实现一个或多个接口,所以jvm生成的动态类只能用作具有相同接口的目标类的代理。

怎么让一个没有实现接口的类生成动态代理类呢?可以使用CGLIB库。他可以动态的生成一个类的子类,一个类的子类也可以用作该类代理类。

动态代理工作原理图:


代码实现:分析JVM生成动态类,以及获取生成动态类的方法信息列表

package Proxy;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.Collection;public class ProxyDemo {/** * @分析JVM生成动态类,以及获取生成动态类的方法信息列表 */public static void main(String[] args)  throws Exception{//通过反射获取jvm生成动态的字节码文件//参数说明: 第一个参数classLoader:一般使用使用接口的类加载器,第二个参数:该动态类需要实现的接口Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy1.getName());//获取构造方法Constructor[] constructors=clazzProxy1.getConstructors();for(Constructor constructor: constructors){System.out.println(constructor);//这个打印出public $Proxy0(java.lang.reflect.InvocationHandler)  。说明只有一个构造方法。}System.out.println("begin new instance-------");Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);Collection proxy1=(Collection) constructor.newInstance(new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {// TODO Auto-generated method stubreturn null;}});System.out.println(proxy1);    //proxy1.size(); size()方法有返回值。报空指针错误System.out.println("第二种创建动态实例对象方法:");Collection proxy2=(Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),new Class[]{Collection.class},new InvocationHandler() {ArrayList traget=new ArrayList();@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {long beginTime=System.currentTimeMillis();                Object retVal=method.invoke(traget, args);                long endTime=System.currentTimeMillis()-beginTime;                System.out.println(method.getName()+"耗时"+(endTime-beginTime));return retVal;}});    proxy2.add("zd");    proxy2.add("lx");    proxy2.add("wcb");    System.out.println(proxy2.size());}}
面向切面实现,把代理类封装使用,可以插入日志信息等:
package Proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.Collection;public class ProxyDemo2 {public static void main(String[] args) {  Collection  traget=new ArrayList();Collection proxy2 = (Collection) getProxy(traget,new AdvicceService());    proxy2.add("zd");    proxy2.add("lx");    proxy2.add("wcb");    System.out.println("---------"+proxy2.size());} /**  * 此方法可以一直使用,动态代理类  * @param traget  * @param advice  * @return proxy2  */private static Object getProxy(final Object traget,final Advice advice) {Object proxy2= Proxy.newProxyInstance(traget.getClass().getClassLoader(), //用什么接口就用它的类加载器traget.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {    advice.beforMethod(method);                 Object retVal=method.invoke(traget, args);                advice.afterMethod(method);return retVal;}});return proxy2;}}
接口:
package Proxy;import java.lang.reflect.Method;public interface Advice { void beforMethod(Method method); void afterMethod(Method method);}
接口实现类:
package Proxy;import java.lang.reflect.Method;public class AdvicceService implements Advice {private long beginTime=0;@Overridepublic void beforMethod(Method method) {beginTime=System.currentTimeMillis();}@Overridepublic void afterMethod(Method method) {  long endTime=System.currentTimeMillis()-beginTime;          System.out.println(method.getName()+"耗时"+(endTime-beginTime));}}
------- android培训java培训、期待与您交流! ----------




0 0
原创粉丝点击