Spring AOP CGLib与JDKProxy的区别与示例

1. Spring AOP 的实现主要有两种:CGLib与JDK自带的Proxy。

他们主要的区别是:

  • 1.JDK动态代理它实现了被代理对象的接口,而Cglib是继承了被代理对象。
  • 2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
  • 3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。
  • 4.JDKProxy修改的类必须实现接口(因此也只能代理public方法),在创建Proxy时可以使用class.getInterfaces()获得所有接口并进行代理。而CGLib不受这个限制可以修改任何非private非final方法。

2. JDKProxy

public class JDKProxy {

    /**
     * 代理类,只能放回接口
     * @param object
     * @return
     * @param <T>
     */
    public static <T> T getProxy(Object object) {
        Class<?> klass = object.getClass();
        ClassLoader classLoder = klass.getClassLoader();
        Class<?>[] interfaces = klass.getInterfaces();

        return (T) Proxy.newProxyInstance(classLoder, interfaces, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("前置拦截");
                Object invoke = method.invoke(object, args);
                System.out.println("后置拦截");
                return invoke;
            }
        });
    }

    /**
     * 代理接口
     * @param interfaceClass
     * @return
     * @param <T>
     */
    public static <T> T getProxy(Class<?>  interfaceClass) {

        ClassLoader classLoder = interfaceClass .getClassLoader();

        /**
         * 进行自定义处理,或者交给其他类处理。比如 JDKProxyInvocationHandler
         */
        return (T) Proxy.newProxyInstance(classLoder, new Class[]{interfaceClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("getProxy 前置拦截 " + method.getName());
                //自定义处理逻辑
                Object result;
                if (method.getName().equals("getName")){
                    result= "getName";
                }else{
                    result= 189;
                }
                System.out.println("getProxy 后置拦截 "+ method.getName());
                return result;
            }
        });
    }

    /**
     * 自定义方法拦截器
     */
    class JDKProxyInvocationHandler implements InvocationHandler,JDKProxyInterface{

        @Override
        public int getAge(int age) {
            return age;
        }

        @Override
        public String getName(String name) {
            return name;
        }

        /**
         *
         * @param proxy 当前代理的实例对象
         *
         * @param method  当前执行方法
         *
         * @param args 执行方法参数
         *
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("JDKProxyInvocationHandler 前置拦截");
            Object invoke = method.invoke(this, args);
            //自定义处理逻辑
            System.out.println("JDKProxyInvocationHandler 后置拦截");
            return invoke;
        }
    }
}

3. CGLBProxy

导入依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
public class CGLBProxy {

    public static <T> T getProxy(T object) {
        Class<?> klass = object.getClass();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(klass);
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

                System.out.println("CGLB前置拦截");
                Object result = method.invoke(object, objects);
                System.out.println("CGLB后置拦截");

                return result;
            }
        });
        return (T)enhancer.create();
    }
}

4、两者优缺点

JDK动态代理和CGLIB代理都有它们自己的优缺点。

JDK动态代理的优点:

  • JDK动态代理是Java标准库的一部分,因此它不需要引入任何外部依赖。
  • JDK动态代理只需要实现接口即可生成代理对象,不需要改变原有类的结构。
  • 由于JDK动态代理是基于接口实现的,因此它更适合用于代理接口实现类的场景。

JDK动态代理的缺点:

  • JDK动态代理只能代理实现了接口的类,无法代理没有实现接口的类。
  • JDK动态代理在生成代理对象时,需要使用反射机制,因此它的效率相对较低。

CGLIB代理的优点:

  • CGLIB代理是基于字节码技术实现的,因此它的效率比JDK动态代理更高。
  • CGLIB代理可以代理没有实现接口的类。

CGLIB代理的缺点:

  • CGLIB代理需要引入外部依赖。
  • CGLIB代理在生成代理对象时,需要改变原有类的结构,因此它可能会引起一些问题,例如无法代理final类或final方法等问题。

综上所述,JDK动态代理适用于代理接口实现类的场景,而CGLIB代理适用于代理没有实现接口的类的场景。如果你需要代理接口实现类,而且不想引入额外的依赖,那么JDK动态代理是一个不错的选择;如果你需要代理没有实现接口的类,那么CGLIB代理可能更适合你的需求。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值