0
点赞
收藏
分享

微信扫一扫

jdk与cglib动态代理

AbrahamW 2022-02-20 阅读 66

1. jdk 与 cglib 动态代理对比


    1.1 都会将生成的代理类缓存起来,先从缓存中获取,没有才生成,得到代理类后,生成代理类的实例
    1.2 jdk动态代理只能生成接口的代理类,cglib可以生成普通类的代理类,但不能生成final类的代理类
    1.3 cglib代理类比jdk代理类占用更多的内存空间(通过为同一个实现类生成代理类,然后对比输出的class)
    1.4 cglib代理类继承被代理类,jdk代理类继承Proxy并实现被代理类实现的接口

2. jdk动态代理使用方式及流程分析

    2.1 需要用到类:Proxy, InvocationHandler
        Proxy: 负责代理类及其实例的创建, 其字段InvocationHandler h 用来调用被代理对象对应的方法,
            生成的代理类继承Proxy,代理类通过super.h.invoke(Object proxy, Method method, Object[] args)
            调用被代理对象的对应方法;
            代理类由 ProxyBuilder.defineProxyClass(Module m, List<Class<?>> interfaces) 调用
            ProxyGenerator.generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags)
            生成            
        InvocationHandler: 保存被代理类实例的引用

2.2 code

DailyLife target = new ConcreteDailyLife();

        DailyLife proxy = (DailyLife) Proxy.newProxyInstance(
                JdkProxyDemo.class.getClassLoader(),		// the class loader to define the proxy class
                ConcreteDailyLife.class.getInterfaces(),	// the list of interfaces for the proxy class to implement
                new MyInvocationHandler(target));			// the invocation handler to dispatch method invocations to

        proxy.eat();
        proxy.sleep();

2.3 写出生成的代理类到磁盘文件

byte[] concreteDailyLife = MyProxyGenerator.generateProxyClass(
                "JdkConcreteDailyLifeProxy",
                ConcreteDailyLife.class.getInterfaces());
        FileUtil.write("C:\\Users\\output\\JdkConcreteDailyLifeProxy.class", concreteDailyLife);

3. cglib使用方式及流程分析

3.1 添加maven依赖

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

3.2 需要用到类:Enhancer, MethodInterceptor, Callback

3.3 code

public class CglibDemo {
			public static void main(String[] args) throws Exception {
				CustomerService target = new CustomerService();
				Callback[] callbacks = new Callback[] {
						new RefundInterceptor(target),		// RefundInterceptor实现 MethodInterceptor
						new CommonInterceptor(target) };	// CommandInterceptor MethodInterceptor
						
				// 构造Enhancer: 初始化 EnhancerKey KEY_FACTORY,通过调用 AbstractClassGenerator.create(Object key)
				// 创建 EnhancerKey 的实例;
				Enhancer enhancer = new Enhancer();
				// 设置被代理类为父类
				enhancer.setSuperclass(CustomerService.class);
				// 设置回调
				enhancer.setCallbacks(callbacks);
				// 设置回调过滤器
				enhancer.setCallbackFilter(method -> {
					// refund 方法调用 RefundInterceptor,其他方法调用 CommonInterceptor
					if (method.getName().endsWith("refund")) { 
						return 0;	// 0 对应callbacks里面的第一个Callback,即 RefundInterceptor
					}
					return 1;		// 1 对应callbacks里面的第二个Callback,即 CommonInterceptor
				});

				// 创建代理实例, 流程说明参考 "3.4 cglib 创建代理实例执行流程"
				CustomerService proxy = (CustomerService) enhancer.create();
				proxy.refund();
				proxy.pack();
			}
		}

3.4 cglib 创建代理实例执行流程
        step1: Enhancer:: create >> createHelper
        step2: AbstractClassGenerator:: create 
        step3: 使用 AbstractClassGenerator$ClassLoaderData, LoadingCache 获取缓存
        step4: 构建 FutureTask, 通过 FutureTask 异步创建代理类实例
        step5: Enhancer::generate
        step6: AbstractClassGenerator::generate
        step7: DefaultGeneratorStrategy::generate(ClassGenerator cg)
        step8: Enhancer::generateClass(ClassVisitor v)
        step9: AbstractClassGenerator::generate
        step10: 返回创建好的代理类实例

3.5 写出生成的代理类到磁盘文件

// 需要创建代理类实例成功后才能写出代理类到磁盘
CustomerService proxy = (CustomerService) enhancer.create();

// 代理类实例已生成是以下输出的前提条件
FileUtil.write(
    "C:\\Users\\output\\CglibCustomerServiceProxy.class",
    DefaultGeneratorStrategy.INSTANCE.generate(enhancer));
举报

相关推荐

0 条评论