• Cglib 动态代理


    • 介绍

    JDK 动态代理有一个最致命的问题是其只能代理实现了接口的类。

    为了解决这个问题,我们可以用 CGLIB 动态代理机制来避免。

    CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB 通过继承方式实现代理。很多知名的开源框架都使用到了CGLIB, 例如 Spring 中的 AOP 模块中:如果目标对象实现了接口,则默认采用 JDK 动态代理,否则采用 CGLIB 动态代理

    在 CGLIB 动态代理机制中 MethodInterceptor 接口和 Enhancer 类是核心。

    自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法。

    public interface MethodInterceptor
    extends Callback{
        // 拦截被代理类中的方法
        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                   MethodProxy proxy) throws Throwable;
    }
    
    1. obj :被代理的对象(需要增强的对象)
    2. method :被拦截的方法(需要增强的方法)
    3. args :方法入参
    4. methodProxy :用于调用原始方法

    可以通过 Enhancer类来动态获取被代理类,当代理类调用方法的时候,实际调用的是 MethodInterceptor 中的 intercept 方法。

    • 使用步骤

    1. 定义一个类
    2. 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和 JDK 动态代理中 invoke 方法类似
    3. 通过 Enhancer 类的 create() 创建代理类
    • 代码示例

    不同于 JDK 动态代理不需要额外的依赖。CGLIB(Code Generation Library) 实际是属于一个开源项目,如果你要使用它的话,需要手动添加相关依赖。

    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.3.0</version>
    </dependency>
    

    1. 定义实现发送消息的类

    package com.format.service;
    
    public class SmsCglibService {
    
        public String send(String message) {
            System.out.println("send message : " + message);
            return message;
        }
    
    }
    
    

    2. 自定义 MethodInterceptor(方法拦截器)

    package com.format.proxy;
    
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class DynamicMethodInterceptor implements MethodInterceptor {
    
        /**
         * @param o           被代理的对象(需要增强的对象)
         * @param method      被拦截的方法(需要增强的方法)
         * @param objects     方法入参
         * @param methodProxy 用于调用原始方法
         */
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            //真实方法调用前
            System.out.println("before method : " + method.getName());
            Object result = methodProxy.invokeSuper(o,objects);
            //真实方法调用后
            System.out.println("end method : " + method.getName());
            return result;
        }
    }
    
    

    3. 获取代理类

    package com.format.proxy;
    
    import net.sf.cglib.proxy.Enhancer;
    
    public class CglibProxyFactory {
        public static Object getProxy(Class<?> clazz){
            // 创建动态代理增强类
            Enhancer enhancer = new Enhancer();
            //设置类加载器
            enhancer.setClassLoader(clazz.getClassLoader());
            //设置被代理类
            enhancer.setSuperclass(clazz);
            //设置方法拦截器
            enhancer.setCallback(new DynamicMethodInterceptor());
            //创建代理类
            return enhancer.create();
        }
    }
    
    

    4. 使用

    package com.format.main;
    
    import com.format.proxy.CglibProxyFactory;
    import com.format.service.SmsCglibService;
    
    public class ProxyTestMain {
    
        public static void main(String[] args) {
            SmsCglibService cglibService = (SmsCglibService)CglibProxyFactory.getProxy(SmsCglibService.class);
            cglibService.send("hello");
        }
    
    }
    
    

    控制台打印出

    before method : send
    send message : hello
    end method : send
    
  • 相关阅读:
    管理表空间和数据文件——维护表空间——改变表空间的读写状态和改变表空间名称
    管理表空间和数据文件——数据库逻辑结构
    管理用户和PROFILE ——管理PROFILE——使用PROFILE管理口令
    管理对象空间——管理存储参数
    管理表空间和数据文件——显示表空间和数据文件信息
    oracle Wallet的使用
    管理表空间和数据文件——维护表空间——设置默认表空间和删除表空间和删除数据文件盒临时文件
    管理用户和PROFILE——用户方案和profile
    管理表空间和数据文件——建立表空间——建立临时表空间
    启动和停止数据库——停顿和暂停数据库
  • 原文地址:https://www.cnblogs.com/format-ch/p/14978042.html
Copyright © 2020-2023  润新知