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

标签: 代理 剑客 jdk | 发表时间:2013-09-09 16:32 | 作者:wwwwenhuan
出处:http://blog.csdn.net

背景:


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


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

核心代码片段

ProxySubject-->>doOperation()

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

2.继承父类



核心代码片段

ProxySubject-->>doOperation()

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

总结:

相同点

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

不同点

1.灵活性

“接口实现”的方式更加灵活,代理类可以代理所有实现了ISubject接口的类;

“继承父类”的方式代理类只能代理它的父类,因为java中只支持单继承

2.可行性

如果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接口

用于处理方法请求

 

代码演示

ISubject接口,RealSubject类同上

 

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);
		
		ISubject proxySubject=(ISubject)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方案了。





作者:wwwwenhuan 发表于2013-9-9 8:32:23 原文链接
阅读:19 评论:0 查看评论

相关 [代理 剑客 jdk] 推荐:

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

- - CSDN博客推荐文章
研究过设计模式的同胞们都知道代理模式可以有两种实现方案:. 1.接口实现(或继承抽象类). 都可以通过Proxy控制对Target的访问. “接口实现”的方式更加灵活,代理类可以代理所有实现了ISubject接口的类;. “继承父类”的方式代理类只能代理它的父类,因为java中只支持单继承. 如果Target有直接接口,那么这两种方式都可以;.

JDK动态代理机制

- - CSDN博客编程语言推荐文章
    代理模式有两种,一种是静态代理,这种方式需要为每一个被代理类写一个代理类,显示比较麻烦. 还一种是动态代理,动态代理实现方式一般有两种,JDK动态代理与CGLIB动态代理,这里说一下对JDK动态代理的理解.     JDK动态代理最核心的就类就是java.lang.reflect.Proxy,可调用Proxy.newInstance(..)生成动态代理.

JAVA之JDK动态代理

- - Java - 编程语言 - ITeye博客
在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和接口,可以生成JDK动态代理类或动态代理对象. Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类,如果在程序中为一个或多个接口动态的生成实现类,就可以使用Proxy来创建动态代理类,.

Spring AOP 代理机制 JDK&CGLIB

- - 开源软件 - ITeye博客
Spring AOP使用JDK动态代理或者CGLIB来为目标对象创建代理. (建议优先使用JDK的动态代理). 如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理. 所有该目标类型实现的接口都将被代理. 若该目标对象没有实现任何接口,则创建一个CGLIB代理. 如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法) 那也可以.

实现动态代理的两种方式介绍+例子demo(JDK、CGlib)

- - CSDN博客架构设计推荐文章
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢. CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑. JDK动态代理与CGLib动态代理均是实现Spring AOP的基础.

Sun JDK 1.6内存管理

- 小丑鱼 - 淘宝JAVA中间件团队博客
分为使用篇、调优篇和实现篇三个部分,使用篇为填鸭式,调优篇为pattern式,实现篇为启发式,三个PPT的目标为:. 1.掌握Sun JDK的内存区域的划分;. 2.掌握Sun JDK垃圾收集器的使用方法和触发时机;. 4.掌握一些基本的GC调优的方法;. 5.了解自动内存管理的常见实现方法,以及Sun JDK所做的优化.

JDK自带监控工具

- - ITeye博客
         系统在生产运行过程中最重要的工作莫过于监控与问题的处理,监控是预防问题产生很重要的手段. 在监控过程中可以发现那些模块或进程出现了问题,出现问题后会及时通知问题负责人.         实现监控的手段非常多,有系统级别监控系统,也有监控小工具等等. Java 就已经自带了一些监控工具,可以不借助外部软件的情况下简单、快速查看相应监控信息.

赵雅智_Java JDK 5.0 内省

- - CSDN博客推荐文章
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦. 所以sun公司开发了一套API,专门用于操作java对象的属性. 什么是Java对象的属性和属性的读写方法?. 内省访问JavaBean属性的两种方式:. 通过PropertyDescriptor类操作Bean的属性.

Hadoop 2.7.0 发布,不再支持 JDK 6

- - 开源中国社区最新新闻
Apache Hadoop 2.7.0 发布,包括大量显著改进,值得关注的改进如下:. 此版本不再支持 JDK 6 运行时,仅支持 JDK 7+. 还有一些重要的问题需要通过测试,用于生产环境的用户请等待 2.7.1/2.7.2. 支持 Windows Azure 存储 —— Blob. 自动分享,全局缓存 YARN 本地化资源(测试阶段).

常用的JDK自带命令行工具

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 在 这里可以找得到这些工具的列表,虽然官网上免责声明为 “The tools described in this section are unsupported and experimental in nature and should be used with that in mind.