java动态代理

来源:互联网 发布:java组件化开发 编辑:程序博客网 时间:2024/06/03 17:12

参考:

反射:

http://doc.java.sun.com/DocWeb/api/all/java.lang.reflect.Proxy

http://doc.java.sun.com/DocWeb/api/all/java.lang.reflect.InvocationHandler

cglib:

http://blog.csdn.net/xiaohai0504/article/details/6833822

两者方式实现:

反射的方式:

  通过反射可以动态写一个接口的实现类,并把这个类进行实例化。这里必须有接口,没有接口,无法动态创建子类型。

 InvocationHandler handler = new MyInvocationHandler(...);//一个用来处理方法调用的类,充当了代理类的所有方法     Class proxyClass = Proxy.getProxyClass(         Foo.class.getClassLoader(), new Class[] { Foo.class });//创建代理类,实现了Foo接口     Foo f = (Foo) proxyClass.         getConstructor(new Class[] { InvocationHandler.class }).         newInstance(new Object[] { handler });//实例化代理对象,这时就可以调用代理对象中的方法了,调用方法时会调用handler中的invoke方法

上面的代码简写:

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),                                          new Class[] { Foo.class },                                          handler);

其中handler的接口(InvocationHandler)中的方法介绍:

public Object invoke(Objectproxy,Methodmethod,Object[] args) throwsThrowable

在代理对象上调用方法并返回结果时用这个方法。调用代理对象的方法都会调用这个方法。

参数介绍:

proxy代理对象method要调用的 Method 实例。Method对象的声明是在该代理对象实现的接口中定义了的。args包含传入代理实例上方法调用的参数值数组,如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类(如java.lang.Integerjava.lang.Boolean)的实例中。return从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为null并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出ClassCastExceptionThrowsThrowable:从代理实例上的方法调用抛出的异常。该异常的类型必须可以分配到在接口方法的throws子句中声明的任一异常类型或未经检查的异常类型java.lang.RuntimeExceptionjava.lang.Error。如果此方法抛出经过检查的异常,该异常不可分配到在接口方法的throws子句中声明的任一异常类型,代理实例的方法调用将抛出包含此方法曾抛出的异常的UndeclaredThrowableExceptionSee alsojava.lang.reflect.UndeclaredThrowableException

那么在这个invoke方法里写什么内容,调用代理对象的方法时就会执行什么代码。

例如Foo接口中有一个f()方法和oo()方法,而代理对象中用来处理方法调用的handle=new InvocationHandler(){  

public Object invoke(Objectproxy,Methodmethod,Object[] args) throwsThrowable{    System.out.println("foo"); }}

那么在调用代理对象的f()方法和oo()方法时都是打印了foo字符串

为了表示一个代理对象代理了某个目标对象,那么在invoke代码中应该调用目标对象中相应的方法

UserDao target=new UserDaoImpl();InvocationHandler handler=new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//some codeObject obj=method.invoke(target, args);//some codereturn obj;}};UserDao proxy=(UserDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);


上面UserDao表示目标对象实现的接口,UserDaoImpl是目标对象,proxy是代理对象,调用代理对象中的方法时会调用handler中的invoke方法。这里如果invoke中写代码method.invoke(proxy,args)会出现死循环,因为是自己调用自己

 

cglib的方式:

cglib是通过操作字节码实现的,所以可以动态创建一个非final类的子类,不需要依赖接口

UserDaoImpl dao=new UserDaoImpl();//要代理的对象,也就是创建这个类的子类Enhancer hancer=new Enhancer();//一个用来创建代理对象的工具类hancer.setSuperclass(dao.getClass());//设置代理对象的父类是谁//设置调用代理对象中的方法时,由谁来处理,这里用Callback的子接口MethodInterceptor的实现类对象来处理hancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object target, Method method, Object[] args,MethodProxy proxyMethod) throws Throwable {//somecodeObject result=proxyMethod.invokeSuper(target, args);//调用代理对象的父类中的方法//somecodereturn result;}});Object proxy=hancer.create();UserDaoImpl proxyDao=(UserDaoImpl)proxy;

MethodInterceptor:

General-purpose Enhancer callback which provides for "around advice".

intercept方法介绍:

public java.lang.Object intercept(java.lang.Object obj,                                  java.lang.reflect.Method method,                                  java.lang.Object[] args,                                  MethodProxy proxy)                           throws java.lang.Throwable
All generated proxied methods call this method instead of the original method. The original method may either be invoked by normal reflection using the Method object, or by using the MethodProxy (faster).

Parameters:
obj - "this", the enhanced object
method - intercepted Method
args - argument array; primitive types are wrapped
proxy - used to invoke super (non-intercepted method); may be called as many times as needed
Returns:
any value compatible with the signature of the proxied method. Method returning void will ignore this value.
Throws:
java.lang.Throwable - any exception may be thrown; if so, super method will not be invoked

 

ProxyMethod:

.Classes generated by Enhancer pass this object to the registered MethodInterceptor objects when an intercepted method is invoked. It can be used to either invoke the original method, or call the same method on a different object of the same type.

invokeSuper方法介绍:

public java.lang.Object invokeSuper(java.lang.Object obj,                                    java.lang.Object[] args)                             throws java.lang.Throwable
Invoke the original (super) method on the specified object.

Parameters:
obj - the enhanced object, must be the object passed as the first argument to the MethodInterceptor
args - the arguments passed to the intercepted method; you may substitute a different argument array as long as the types are compatible
Throws:
java.lang.Throwable - the bare exceptions thrown by the called method are passed through without wrapping in an InvocationTargetException