您的位置:首页 > 编程语言 > Java开发

AOP实现--JDK中的动态代理和cglib代理

2012-08-07 17:55 736 查看

java.lang.reflect Interface InvocationHandler

可参考http://www.gznc.edu.cn/yxsz/jjglxy/book/Java_api/java/lang/reflect/InvocationHandler.html

http://www.gznc.edu.cn/yxsz/jjglxy/book/Java_api/java/lang/reflect/Proxy.html

invocation是“调用”的意思。这个类可以让我们在JVM调用某个类的方法时动态的为些方法做些什么事.InvocationHandler接口把我们的代理对象和被代理对象解耦了.动态代理类可以对任何实现某一接口的类进行功能性的增强。

关于Method对象的invoke方法,根据java的反射机制可以获得某个对象的某个方法,也可以动态调用,假设已经获取了这个方法method.那么method.invoke(owner,args)就是动态调用,owner表示方法所属的对象,args为Object[]类型的方法参数。

接口InvocationHandler的方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

proxy:在其上调用方法的代理实例(Proxy类型的对象)。

method:对应于在代理实例上调用的接口方法的
Method
实例。。

args:为方法的参数

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynProxy implements InvocationHandler{
private Object src;//被代理对象
//bind为自定义方法,将src绑定到某个代理中
//把当前对象(实现了InvocationHandler接口)传递给代理对象
//返回代理对象
public Object bind(Object src){
this.src=src;
Object proxy=Proxy.newProxyInstance(
src.getClass().getClassLoader(),//被代理对象的类加载器
src.getClass().getInterfaces(),//被代理对象实现的接口们,代理对象可以实现全部接口
this //当前对象(实现了InvocationHandler接口) 回调,拦截到一个方法后可以触发哪个类中的哪个方法。
);
//返回的是一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
return proxy;
}
//InvocationHandler接口方法
//src(目标对象)中的每个方法会被此方法送去JVM调用,也就是说,src的方法只能通过此方法调用
//此方法不能自己调用
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println(method.getName()+"调用前");
Object result=method.invoke(src, args);
return result;
}
public static void main(String[] args) {
Login src=new Login();  //被代理对象
DynProxy dp=new DynProxy();
ILogin proxy=(ILogin)dp.bind(src);  //返回代理对象
String username="tazi",password="123";
proxy.login(username, password); //在代理实例上调用接口方法
}
}


代理对象实现了目标对象的接口,使用时要用接口来引用代理对象。

以上的代码改个名字更好理解:

package com.tazi.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//JDK方式的动态代理对象的创建工厂
public class JDKProxyFactory implements InvocationHandler{
private Object target;//目标对象
//创建代理对象的方法
//返回的是已经实现了目标对象所有接口的代理对象
public Object createProxy(Object target){
this.target=target;
//以下前两个参数跟目标对象有关
//第三个参数是一个包含回调方法(invoke)的对象(实现InvocationHandler接口)
return Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces(),this);
}
//当拦截到目标对象某个方法时的回调方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("方法执行前");
Object result=method.invoke(target, args);
System.out.println("方法执行后");

return result;
}
}


测试用例:

package junit.test;

import static org.junit.Assert.*;

import org.junit.BeforeClass;
import org.junit.Test;

import com.tazi.aop.JDKProxyFactory;
import com.tazi.aop.PersonService;
import com.tazi.aop.PersonServiceBean;

public class ProxyTest {
private static JDKProxyFactory proxyFactory;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
proxyFactory=new JDKProxyFactory();
}
@Test
public void proxy() throws Exception {
PersonService pService=(PersonService)proxyFactory.createProxy(new PersonServiceBean());
pService.save("xxx");
}
}


CGLIB实现动态代理

但实际中情况会比较复杂,有可能目标对象没有实现接口。如果没有就不能创建代理对象。此时用到第三方的jar包来创建代理对象。cglib.jar。这时目标对象可以不实现接口。

cglib的实现方式是创建被代理对象的子类,这个子类覆盖了目标对象的所有的非final的所有方法。然后设置回调方法。

package com.tazi.aop;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxyFactory implements MethodInterceptor{
private Object target;
public Object createProxy(Object target){
this.target=target;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
System.out.println("方法执行前00");
Object result=method.invoke(target, args);
System.out.println("方法执行后00");
return result;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: