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

AOP编程之JDK动态代理和Cglib动态代理

2013-08-17 01:31 453 查看
最近开发过程中遇到一些问题,为了可以好好的解决,研究了几天的动态代理。记下来,怕以后忘记了。

动态代理适用的情景:

某个类的某个方法已经做好了,你在不想或者不能改动源代码的情况下,要做一些额外的操作,这时候就可以使用代理设计模式。

例如,周杰伦要举行新唱片的的签名发布会,他总不能自己去布置会场吧。所以他就请了他的经理人Kim去帮忙布置场地罗,这个Kim就是属于代理的角色了。他要在Joy签名会之前去布置场地,签名会之后清理场地。

下面我们来看看JDK代理怎么做的。

1.首先Joy同学需要先声明自己有一个签名会,也就是interface。然后再去开这个签名会。

public interface Joy {
public void holdSignature();
}


public class JoyImpl implements Joy{
public void holdSignature() {
System.out.println("joy say:大家好,我是Joy,今天我在这里举行签名会哦...");
}
}


2.然后我们的JDK代理就出场了
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//这是专门帮人家布置场地的JDK代理
public class JDKProxy implements InvocationHandler{
//要代理的对象,也即是帮哪个明星做场地啦,今天可能是Joy,明天可能就是SHE了
private Object star;
public JDKProxy(Object star) {
this.star = star;
}

public Object getProxySatr(){
return Proxy.newProxyInstance(
star.getClass().getClassLoader(),
star.getClass().getInterfaces(),
this);
}
public Object invoke(Object obj, Method method, Object[] params)
throws Throwable {
System.out.println("jdk say:签名会开始之前,我要帮忙布置场地...");
//明星开始他的签名会了
Object result = method.invoke(star, params);
System.out.println("jdk say:签名会结束了,我要清理场地。");
return result;
}

}


3.双方都准备就绪了,我们现在开始签合同工作了。

public static void main(String[] args) {
//jdkProxy代理接到order是帮joy布置场地呢。
JDKProxy jdkProxy = new JDKProxy(new JoyImpl());
//请出代理的明星,让他签名去咯
Joy joy = (Joy) jdkProxy.getProxySatr();
joy.holdSignature();
}

可以看到最后的结果是:

jdk say:签名会开始之前,我要帮忙布置场地...
joy say:大家好,我是Joy,今天我在这里举行签名会哦...
jdk say:签名会结束了,我要清理场地。

大家可以发现,Joy开演唱会之前还有做一次声明,多么让人不爽快的interface啊。所以SHE开签名会的时候就换了一个叫cglib的代理。
下面来看cglib代理是怎么做的。
1.首先,SHE的演唱会还是要自己去开的。

public class SHE {
public void musicShow() {
System.out.println("she say:大家好,我们是SHE,下面为大家带来《星光》....");
}
}


2.然后我们的Cglib其实是一家公司来的员工了,他可以为好多的明星布置会场的。成立这个比较好使代理公司,总的多投入点成本吧。
引入asm-3-3-1.jar和cglib-2.2.jar

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

public class CglibProxy implements MethodInterceptor{
public Enhancer enhancer = new Enhancer();

public<T> Object getCglibProxy(Class<T> star){
//指定这次要伺候的明星
enhancer.setSuperclass(star);
//要做什么呢?就是下面的intercept里面干的事
enhancer.setCallback(this);
//合约签订,把你的暂时仆人送过去服务你了。
return enhancer.create();
}

public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("cglib say:我在布置演唱会的场地.....");
//boss可以开演唱会了
Object result = proxy.invokeSuper(obj, args);

System.out.println("cglib say:演唱会结束了,我在清理场地.....");
return result;
}
}


3.接下来就是签约工作了

public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
SHE she = (SHE) cglibProxy.getCglibProxy(SHE.class);
she.musicShow();
}


4.最后你会发现,演唱会灰常的成功啦。

cglib say:我在布置演唱会的场地.....
she say:大家好,我们是SHE,下面为大家带来《星光》....
cglib say:演唱会结束了,我在清理场地.....

对比JDK代理和Cglib代理可以发现,JDK多了一个接口。
为什么JDK代理只能针对接口呢?
JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类,有兴趣的自己去查源代码哈。
而Cglib则采用ASM工具,直接修改字节码。所以不用接口规范。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: