← 返回首页
Spring基础教程(十四)
发表时间:2020-05-14 23:44:22
讲解cglib动态代理

CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它被许多 AOP 框架所使用,其底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码反编译框架)转换字节码并生成新的类。因此 CGLIB 要依赖于 ASM 的包,查看 Spring 的核心包 spring-core-5.2.5.RELEASE.jar,文件目录如图所示。

Spring5.2.5.RELEASE 版本的核心包已经集成了 CGLIB 所需要的包,所以在开发中不需要另外导入 ASM 的 JAR 包了。下面通过案例演示实现 CGLIB 代理实现上节案例的过程。

CGLIB 动态代理即支持接口也支持抽象类的方式实现。本节使用抽象类方式演示。

项目结构图如下:

1.设计演员抽象类

package com.entity;

public abstract class Actor  {

    protected String name; //演员的名字
    protected String type; //出演影片的类型

    public Actor() {
    }

    public Actor(String name, String type) {
        this.name = name;
        this.type = type;
    }
    //演戏抽象方法
    public abstract void act() ;
}

2.设计影星类

package com.entity;

public class MovieStar extends Actor {

    public MovieStar() {
    }

    public MovieStar(String name, String type) {
        super(name, type);
    }

    public void act() {
        System.out.println(this.name + "正在出演" + this.type + "影片...");
    }
}

3.设计影星代理类

package proxy;

import com.entity.Actor;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;


//成龙经纪人类(代理类)
public class ActorProxy implements MethodInterceptor {

    // 目标对象
    private Object targetObject; //成龙经纪人目标对象肯定是成龙

    //传入一个代理之前的对象,返回一个被代理对象。
    public Object newProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(this.targetObject.getClass().getSuperclass());
        // 设置enhancer的回调对象
        enhancer.setCallback(this);
        // 创建代理对象
        return (Actor)enhancer.create();

    }

    //演戏之前要做的事情
    private void beforeAct(){
        System.out.println("洽谈档期..");
        System.out.println("洽谈片酬..");
        System.out.println("洽谈广告合作..");
    }

    //演戏之后要做的事情
    private void afterAct(){
        System.out.println("洽谈首映仪式..");
        System.out.println("洽谈颁奖典礼..");
    }


    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object ret = null;

        this.beforeAct();
        //调用成龙真正的演戏方法
        ret =method.invoke(this.targetObject,objects);
        this.afterAct();
        return ret;
    }
}

4.测试类

package com.test;

import com.entity.Actor;
import com.entity.MovieStar;
import proxy.ActorProxy;

public class ActorDemo {

    public static void main(String[] args) {

        Actor actor = new MovieStar("成龙","功夫片");
        actor = (Actor) new ActorProxy().newProxyInstance(actor);
        actor.act();
    }
}

运行结果:
洽谈档期..
洽谈片酬..
洽谈广告合作..
成龙正在出演功夫片影片...
洽谈首映仪式..
洽谈颁奖典礼..

MethodInterceptor 这个接口只有一个intercept()方法,这个方法有4个参数,含义如下:

public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;

1)obj表示增强的对象,即实现这个接口类的一个对象; 2)method表示要被拦截的方法; 3)args表示要被拦截方法的参数; 4)proxy表示要触发父类的方法对象;

感兴趣的同学可自行把Actor 设计为接口,实现效果完全相同。

JDK动态代理与CGLIB动态代理的区别

名称 区别
jdk动态代理 JDK动态代理只能对实现了接口的类生成代理,而不能针对类,例如:mybatis的mapper文件是代理。使用反射完成。使用了动态生成字节码技术。
cglib动态代理 CGLIB是针对类实现代理,接口和抽象类都可以使用,可以直接代理类,使用字节码技术,不能对 final类进行继承。使用了动态生成字节码技术。