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

动态代理双剑客--JDK Proxy与CGLIB

2013-09-09 08:32 351 查看

背景:

研究过设计模式的同胞们都知道代理模式可以有两种实现方案:

1.接口实现(或继承抽象类)



核心代码片段
ProxySubject-->>doOperation()

//dosomething before
realSubject.doOperation()
//dosomething after


2.继承父类



核心代码片段
ProxySubject-->>doOperation()

//dosomething before
super.doOperation()
//dosomething after


总结:

相同点
都可以通过Proxy控制对Target的访问

不同点

可行性
如果Target实现了接口,那么这两种方式都可以;
如果没有实现任何接口,那只能采取“继承父类”的方式了

正文

Java中动态代理对应着也有两种实现方式

1.“接口实现"---JDK Proxy

用到JDK提供的InvocationHandler接口和Proxy类

类之间的关系如下



InvocationHandler接口
用于处理方法请求
Proxy类
用于生成代理对象

代码演示
ISubject接口

public interface ISubject {

public void showName(String name);
}


RealSubject类
public class RealSubject implements ISubject {

@Override
public void showName(String name) {
System.out.println(name+"闪亮登场");
}

}

LogHandler类
为了更明确的说明动态代理的工作原理,将代理的创建过程放到了LogHandler的外部,即main方法中
public class LogHandler implements InvocationHandler {

Object target=null;

public Object getTarget() {
return target;
}

public void setTarget(Object target) {
this.target = target;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
//调用目标对象方法前的逻辑
System.out.println("下面有一个大人物要出现");
//调用目标对象的方法,这句代码将代理与目标类联系了起来
method.invoke(target, args);
//调用目标对象方法后的逻辑
System.out.println("大家鼓掌欢迎");
return result;

}

}


客户端类Client

public class Client {

/**
* @param args
*/
public static void main(String[] args) {

LogHandler logHandler=new LogHandler();
logHandler.setTarget(new RealSubject());
//创建代理对象
ISubject proxySubject=(ISubject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), logHandler);
System.out.println("-------JDK Proxy-------------");
proxySubject.showName("委座");

}

}


执行结果



调用过程时序图



2.“继承父类”---CGLIB

用到了CBLIB提供的Enhancer类和MethodInterceptor接口 

类之间的关系如下



需要引入第三方jar包

cglib-2.2.jar
asm-3.1.jar

Enhancer类
用于创建代理对象
MethodInterceptor接口
用于处理方法请求
 
代码演示
RealSubject类同上,但是个pojo类

public class RealSubject {

public void showName(String name) {
System.out.println(name+"闪亮登场");
}

}


 
LogIntercept类
public class LogIntercept implements MethodInterceptor {
Object target=null;

public Object getTarget() {
return target;
}

public void setTarget(Object target) {
this.target = target;
}

@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {

Object result=null;
//调用目标对象方法前的逻辑
System.out.println("下面有一个大人物要出现");
//调用目标对象的方法,这句代码将代理与目标类联系了起来
arg3.invoke(target, arg2);
//调用目标对象方法后的逻辑
System.out.println("大家鼓掌欢迎");
return result;
}

}


客户端类Client
public class Client {

/**
* @param args
*/
public static void main(String[] args) {

LogIntercept logIntercept=new LogIntercept();
logIntercept.setTarget(new RealSubject());
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(logIntercept);

<pre name="code" class="java">                RealSubject proxySubject=(RealSubject )enhancer.create();
System.out.println("-------CBLIB-------------");
proxySubject.showName("委座");

}

}





调用过程时序图



总结

大家可以看到JDK Proxy和CGLIB这两种动态代理的实现过程是非常相似的,但也有区别

相同点:
都用到了一个接口一个类;
接口用于处理方法调用,类用于创建代理对象

JDK Proxy
InvocationHandler接口
Proxy类

CGLIB
MethodIntercept接口
Enhancer类
不同点:

JDK Proxy
使用目标类的接口创建动态代理

CBLIB
使用目标类的子类创建动态代理
 

最后

          JDK Proxy和CGLIB两种动态代理各有千秋,具体用哪个方案要看具体情况。如果目标类实现了对应接口,两种方案都可以;如果没有实现任何接口则要使用CBLIB。比如Hibernate中的实体类是POJO类,没有实现任何接口,那么要通过代理实现延迟加载就只能采用CGLIB方案了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: