代理二:深入研究InvocationHandler、动态代理类工作原理、实现AOP框架
2014-03-29 14:43
447 查看
9 通过实例深入研究InvocationHandler
先看如下代码:import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Collection; public class ProxyDemo4 { public static void main(String[] args) throws Exception { //动态生成代理类的Class实例,此代理类实现Collection接口并调用目标类的方法 Class clazzProxy = Proxy.getProxyClass(Collection. class.getClassLoader(), Collection.class ); System.out.println("--------begin create instance object-------"); //获得此代理类的构造方法 Constructor constructor = clazzProxy.getConstructor(InvocationHandler. class) ; //生成一个代理类对象,InvocationHandler用匿名内部类。invoke方法封装了要执行的目标代码 Collection proxy = ( Collection)constructor.newInstance( new InvocationHandler(){ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null ; } }); System.out.println(proxy); //结果:null proxy.clear(); //执行没有返回值的方法,不会报告异常 proxy.size(); //执行有返回值的方法,会报告空指针异常 System.out.println(proxy.getClass()); //class $Proxy0 } }
(1)分析上面打印动态类的实例对象时,结果为什么会是null呢?
答:打印动态类的示例对象实际上就是打印proxy的toString方法,也就是执行代理对象中的如下代码:
String toString(){
return handler.invoke(this, this.getClass().getMethod("toString"), null);
}
由于invoke方法返回的是null,打印出来的结果肯定是null。
(2)调用有基本类型返回值的方法时为什么会出现NullPointerException异常?
答:执行proxy.size()方法,就是执行下面的代码:
int size(){
return handler.invoke(this, this.getClass().getMethod("size"), null);
}
由于invoke方法返回的是null,要将null转换为int类型,肯定会报告空指针异常。
(3)分析为什么动态类的实例对象的getClass()方法返回了正确结果呢?
答:调用代理对象的从Object类继承的hashCode, equals, 或toString这几个方法时,代理对象将调用请求转发给InvocationHandler对象,
对于其他方法,则不转发调用请求,比如getClass方法,所以它会返回正确的结果。
10 总结分析动态代理类的设计原理与结构
动态代理类的工作原理图:简单总结:
代理类和目标类都实现了同一个接口,目标类中有具体实现,
而代理类中是通过InvocationHandler对像调用目标类中的具体实现:
即,代理类的方法中,通过调用InvocationHandler对象的invoke方法,指向目标类的相应方法(具体实现)。
当然,前面的例子中,是直接在InvocationHandler对象的invoke方法内,完成了具体实现,这样就没有目标类。
注意:目标类必须自己定义时就实现接口,从该类的祖辈类上继承的接口是无效的。
将创建代理的过程改为一种更优雅的方式,Eclipse重构出一个getProxy方法绑定接收目标,
同时返回代理对象,让调用者更懒惰,更方便,调用者甚至不用接触任何代理的API。
将系统功能代码模块化,即将切面代码也改为通过参数形式提供,怎样把要执行的系统功能代码以参数形式提供?
把要执行的代码装到一个对象的某个方法里,然后把这个对象作为参数传递,
接收者只要调用这个对象的方法,即等于执行了外界提供的代码!为方法增加一个Advice参数。
代码示例:
package mypkg; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.Collection; interface Advice { void beforeAdvice(Method method); void afterAdvice(Method method); } //封装了切面代码: class MyAdvice implements Advice { private long beginTime = 0; public void afterAdvice(Method method) { long endTime = System.currentTimeMillis(); System.out.println(method.getName()+"running out of"+(endTime - beginTime)); } public void beforeAdvice(Method method) { beginTime = System.currentTimeMillis(); } } public class ProxyTest { public static void main(String[] args) throws Exception { final ArrayList target = new ArrayList(); //目标类 //通过自定义的getProxy方法,生成代理类对象,并添加切面代码。 Collection collection = (Collection) getProxy(target,new MyAdvice()); collection.add("zxx" ); //结果:add running out of 0 } //实现框架功能,生成代理只需要传递target目标类,和封装了系统功能的对象MyAdvice public static Object getProxy(final ArrayList target,final Advice advice) { Object proxy = Proxy.newProxyInstance( //生成代理类对象 target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { advice.beforeAdvice(method); //切面代码 Object retVal = method.invoke(target ,args);//调用目标类的方法 advice.afterAdvice(method); //切面代码 return retVal; } } ); return proxy; } }
11 实现类似spring的可配置的AOP框架
AOP是指面向方面的编程,Aspect Oriented Program,简称AOP,见第2节。实现一个AOP的框架,可以根据配置文件获取动态代理或其他结果。
工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换。
其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象,即动态代理类实例。
该动态代理类中插入了切面代码。
BeanFactory的构造方法接收代表配置文件的输入流对象,配置文件格式如下:
xxx=mypkg.aop.ProxyFactoryBean
xxx.advice=mypkg.aop.MyAdvice
xxx.target=java.util.ArrayList
ProxyFacotryBean充当封装生成动态代理的工厂,需要为工厂类提供哪些配置参数信息?
目标类、封装了切面代码的对象(添加系统功能)。
编写客户端应用:
编写实现Advice接口的类和在配置文件中进行配置,
调用BeanFactory获取对象。
所有源文件及配置文件的包结构:
即在同一个包下。
AopFrameworkTest.java 文件:
/* AopFrameworkTest.java */ package mypkg.aop; import java.io.InputStream; //AOP框架,框架原理。通过修改配置文件中的内容,获取不同的结果 public class AopFrameworkTest { public static void main(String[] args) throws Exception{ InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");//相对路径,同一个包下 Object bean = new BeanFactory(ips).getBean("xxx" ); //返回目标类或代理类的实例 System. out.println(bean.getClass().getName()); } }
BeanFactory.java 文件:
/* BeanFactory.java */ package mypkg.aop; import java.io.IOException; import java.io.InputStream; import java.util.Properties; //BeanFactory类负责创建目标类或代理类的实例对象,并通过配置文件实现切换。 public class BeanFactory { Properties props = new Properties(); public BeanFactory(InputStream ips){ try{ props.load(ips); //通过IO流加载配置文件的内容 }catch (IOException e) { e.printStackTrace(); } } public Object getBean(String name) { //返回目标类或代理类的实例 String className = props.getProperty(name); Object bean = null; try{ Class clazz = Class.forName(className);//获取Class类 bean = clazz.newInstance(); //创建此类的实例 } catch (Exception e) { e.printStackTrace(); } if(bean instanceof ProxyFactoryBean){ ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean; Object proxy = null; try{ Advice advice = (Advice) Class.forName( props.getProperty(name + ".advice")).newInstance(); Object target = Class. forName( props.getProperty(name + ".target")).newInstance();//目标类 proxyFactoryBean.setAdvice(advice); proxyFactoryBean.setTarget(target); proxy = proxyFactoryBean.getProxy();//生成动态代理 } catch (Exception e) { e.printStackTrace(); } return proxy; } return bean; } }
ProxyFactoryBean.java 文件:
/* ProxyFactoryBean.java */ package mypkg.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;//动态代理类 /*ProxyFactoryBean类是一个生产动态代理类的工厂。 需要提供目标Target对象、Advice对象(封装了系统功能代码)。 此类是一个JavaBean。*/ public class ProxyFactoryBean { private Advice advice; //封装了系统功能的对象 private Object target; //目标类 public Advice getAdvice() { return advice ; } public void setAdvice(Advice advice) { this.advice = advice; } public Object getTarget() { return target ; } public void setTarget(Object target) { this.target = target; } public Object getProxy(){ //获取动态代理类的实例 Object proxy = Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { advice.beforeAdvice(method); //切面代码 Object retVal = method.invoke( target ,args); //调用目标类的方法 advice.afterAdvice(method); //切面代码 return retVal; } } ); return proxy; } }
Advice.java 文件:
/* Advice.java */ package mypkg.aop; import java.lang.reflect.Method; public interface Advice { //要添加的系统功能,即切面代码 void beforeAdvice(Method method); void afterAdvice(Method method); }
MyAdvice.java 文件:
/* MyAdvice.java */ package mypkg.aop; import java.lang.reflect.Method; public class MyAdvice implements Advice { //封装了切面代码: private long beginTime = 0; public void afterAdvice(Method method) { long endTime = System.currentTimeMillis(); System.out.println(method.getName()+"running out of"+(endTime - beginTime)); } public void beforeAdvice(Method method) { beginTime = System.currentTimeMillis(); } }
配置文件“config.properties”中的内容:
xxx=mypkg.aop.ProxyFactoryBean
xxx.advice=mypkg.aop.MyAdvice
xxx.target=java.util.ArrayList
编译运行结果:
相关文章推荐
- Spring AOP的底层实现技术 Proxy InvocationHandler
- 黑马程序员--代理+AOP--实现一个类似spring的可配置的简单AOP框架
- 黑马程序员-代理、实现类似Spring的可配置AOP框架
- Java 基于JDK中的InvocationHandler实现动态代理
- 基础加强____【动态代理 & AOP】【实现类Spring的AOP框架】
- 004-搭建框架-实现AOP机制【一】代理技术
- java基础知识学习之代理深入学习(用动态代理实现AOP,FacotryBean)
- JAVA动态代理实现 Proxy InvocationHandler
- [置顶] Java的静态代理、动态代理,CGLib的动态代理,使用动态代理基于AOP的AspectJ框架—深入探究
- 黑马程序员--09.动态与代理AOP--06【动态代理实例化的过程升级--目标对象+系统功能的参数化】【实现类似Spring的可配置AOP框架】
- java中InvocationHandler 用于实现代理。
- 【框架】[Spring]AOP拦截-三种方式实现自动代理
- JDBC/InvocationHandler动态代理实现数据库连接池、数据源
- 代理模式及JDK动态代理(InvocationHandler)的简单实现与分析
- 学习笔记--代理与AOP及实现类似SPRING的可配置的AOP框架
- Java的静态代理、动态代理,CGLib的动态代理,使用动态代理基于AOP的AspectJ框架—深入探究
- 深入研究Netty框架之ChannelHandler和ChannelPipeline
- Java的静态代理、动态代理,CGLib的动态代理,使用动态代理基于AOP的AspectJ框架—深入探究
- java中InvocationHandler 用于实现代理。
- Spring AOP的底层实现技术 Proxy InvocationHandler