Proxy代理详解:什么是cglib代理

由于静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理

Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。

  • JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现。

  • Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)

  • Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。

Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可。
2.引入功能包后,就可以在内存中动态构建子类
3.代理的类不能为final,否则报错
4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。


这里,我们定义三个类:User类、JdkProxyFactory JDK动态代理类、CglibProxyFactory代理类。具体的使用方式如下:

无接口类:User

package com.codedocs.net.proxy;

public class User {

    public void save() {
        System.out.println("(不使用接口)保存用户");
    }
}

JDK动态代理类:

/**
 * 动态代理对象(代理对象不需要像静态代理那样实现接口)
 */
public class JdkProxyFactory{

    /**
     * 目标对象(目标对象一定要实现接口,否则会报错)
     */
    private Object target;
    public JdkProxyFactory(Object target){
        this.target=target;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("动态代理开启事务");
                        Object returnValue = method.invoke(target, args);
                        System.out.println("动态代理提交事务");
                        return returnValue;
                    }
                }
        );
    }

}

Cglib代理类:CglibProxyFactory

package com.codedocs.net.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
 * cglib代理
 */
public class CglibProxyFactory implements MethodInterceptor {
    // 目标对象
    private Object target;

    public CglibProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 给目标对象创建一个代理对象
     * @return
     */
    public Object getProxyInstance() {
        // 1.工具类
        Enhancer en = new Enhancer();
        // 2.设置父类
        en.setSuperclass(target.getClass());
        // 3.设置回调函数
        en.setCallback(this);
        // 4.创建子类(代理对象)
        return en.create();

    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");
        // 执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("提交事务...");
        return returnValue;
    }
    
    public static void main(String[] args) {
        //代理对象
        User target = new User();
        
        /**
         * Cglib代理(Cglib代理的目标对象User没有实现任何接口,执行正常)
         */
        User cglibProxy = (User)new CglibProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        cglibProxy.save();
        /**
         * JDK动态代理(Jdk代理的目标对象User没有实现任何接口,执行会报错)
         */
        User jdkProxy = (User)new JdkProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        jdkProxy.save();
    }
}

CglibProxyFactory的main方法执行结果:

开始事务...
(不使用接口)保存用户
提交事务...
Exception in thread "main" java.lang.ClassCastException: $Proxy0 cannot be cast to com.codedocs.net.proxy.User
    at com.codedocs.net.proxy.CglibProxyFactory.main(CglibProxyFactory.java:57)

不难看出Jdk代理和Cglib代理的区别:无接口实现的User,jdk动态代理失败,cglib代理成功。

(JDK代理详解:http://www.codedocs.net/doc/arch-proxy-dynamic)

经验总结:

在Spring的AOP编程中:
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理

评论

*
*