Java动态代理的之JDK和CGLIB

       代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 按照代理的创建时期,代理类可以分为两种。 

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。 在Java中主要可以分为JDK和CGLIB的方法实现。

下面来看看一些实例吧!

一、JDK方式

1、接口类

package com.func.axc.proxy;

/**
 * 功能概要:
 * 
 * @author linbingwen
 * @since  2016年6月2日 
 */
public interface  Book {
	public void addBook();  

}

2、实现类

package com.func.axc.proxy;

/**
 * 功能概要:
 * 
 * @author linbingwen
 * @since  2016年6月2日 
 */
public class BookJdk implements Book {

	@Override
	public void addBook() {
		System.out.println("添加一本新书");
		
	}

}
3、代理类

package com.func.axc.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 功能概要:
 * 
 * @author linbingwen
 * @since  2016年6月2日 
 */
public class BookProxyJdk implements InvocationHandler  {
	
	   private Object target;  
	    /** 
	     * 绑定委托对象并返回一个代理类 
	     * @param target 
	     * @return 
	     */  
	    public Object bind(Object target) {  
	        this.target = target;  
	        //取得代理对象  
	        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
	                target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
	    } 

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=null;  
        System.out.println("jdk实现的前置代理");  
        //执行方法  
        result=method.invoke(target, args);  
        System.out.println("jdk实现的前置代理");  
        return result; 
	}

}

4、测试

		BookProxyJdk proxy = new BookProxyJdk();  
        Book book = (Book) proxy.bind(new BookJdk());  
        book.addBook();  
结果:

jdk实现的前置代理
添加一本新书
jdk实现的前置代理


二、CGLIB动态代理

1、无继承的类

package com.func.axc.proxy;

/**
 * 功能概要:
 * 
 * @author linbingwen
 * @since  2016年6月2日 
 */
public class BookCglib {
	
	public void addBook() {
		System.out.println("添加一本新书");
		
	}

}
2、代理类

package com.func.axc.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * 功能概要:
 * 
 * @author linbingwen
 * @since  2016年6月2日 
 */
public class BookProxyCglib implements MethodInterceptor {
	
	private Object target;  
	  
    /** 
     * 创建代理对象 
     *  
     * @param target 
     * @return 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  
        // 回调方法  
        enhancer.setCallback(this);  
        // 创建代理对象  
        return enhancer.create();  
    }  
	

	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2,
			MethodProxy arg3) throws Throwable {
		   System.out.println("cglib实现的前置代理");
		    
		    //通过代理类调用父类中的方法
		    Object result = arg3.invokeSuper(arg0, arg2);
		    
		    System.out.println("cglib实现的后置代理");
			return result;
	}

}

3、测试

        BookProxyCglib cglib=new BookProxyCglib();  
        BookCglib bookCglib=(BookCglib)cglib.getInstance(new BookCglib());  
        bookCglib.addBook();  
输出结果:

cglib实现的前置代理
添加一本新书
cglib实现的后置代理



三、JDK动态代理和CGLIB字节码生成的区别? 

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

JDK动态代理和CGLib的性能比较
CGLib所创建的动态代理对象的性能比JDK所创建的代理对象性能高不少,大概10倍,但CGLib在创建代理对象时所花费的时间却比JDK动态代理多大概8倍,所以对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建新的实例,所以比较适合CGLib动态代理技术,反之则适用于JDK动态代理技术。另外,由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行处理。所以,大家需要根据实际的情况选择使用什么样的代理了。

同样的,Spring的AOP编程中相关的ProxyFactory代理工厂内部就是使用JDK动态代理或CGLib动态代理的,通过动态代理,将增强(advice)应用到目标类中。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值