一、动态代理的由来
代理是指:给每个具体类写一个代理类,以后要使用某个具体的类时,只要创建它的代理类的对象,然后调用代理类的方法就可以了,可是如果现在有很多具体的类,那就需要创建很多的代理类才可以,这样显然很不合适,那动态代理就应运而生。
二、Java实现动态代理有2种方式:
1、JDK实现动态代理,但是它需要实现类通过接口定义业务方法,对于没有接口的类是无法实现的;
2、CGLib,它采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用。
JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
三、JDK的实现
此类型的动态代理使用到了一个接口InvocationHandler和一个代理类Proxy,这两个类配合使用即可实现动态代理。
//接口
interface InterfaceClass {
void show() ;
}
//具体实现类A
class ClassA implements InterfaceClass {
@Override
public void show(){
System.out.println("class A") ;
}
}
//具体实现类B
class ClassB implements InterfaceClass {
@Override
public void show(){
System.out.println("class B") ;
}
}
//动态代理类,实现InvocationHandler接口
class Invoker implements InvocationHandler {
InterfaceClass ia ;
public Invoker(InterfaceClass ia) {
this.ia = ia ;
}
@Override
public Object invoke(Object proxy, Method method, Object[] arg) throws Throwable {
method.invoke(ia, arg) ;
return null ;
}
}
// Test
class DynamicProxyTest{
public static void main(String[] args){
// 创建具体类ClassA的处理对象
Invoker invoker1 = new Invoker(new ClassA());
// 获得具体类ClassA的代理
InterfaceClass ic1 = (InterfaceClass)Proxy.newProxyInstance(InterfaceClass.class.getClassLoader(), new Class[]{InterfaceClass.class}, invoker1);
ic1.show() ;
// classB也是如此
}
}四、CGLib实现
public class CGLIBProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer() ;
public Object getProxy(Class clazz) {
// 设置父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
// 通过字节码技术动态创建子类实力
return enhancer.create() ;
}
// 所有的方法都会被这个方法所拦截,该类实现了子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class类创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,args为方法动态入参,proxy为代理类实例。
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodproxy) throws Throwable{
Object result = methodproxy.invokerSuper(obj, args) ;
return result ;
}
}
public class UserServiceImpl{
public void sayHello() {
System.out.println("sayHello method") ;
}
public void sayBye() {
System.out.println("sayBye method") ;
}
}
// Test
public class Test{
public static void main(String[] args) {
CGLIBProxy proxy = new CGLIBProxy() ;
UserServiceImpl impl = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class) ;
impl.sayHello() ;
}
}六、比较两种方式的优缺点
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib更合适,反之使用JDK方式要更好些。同时,用于CGLib采用的动态代理创建子类的方式,对于final方法,无法进行处理。
原文:http://lokihjl.blog.51cto.com/10642254/1744937