A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 长沙-小知姐姐 于 2020-7-24 15:55 编辑


完整版视频及笔记资料 回帖可见提取码 若失效请联系微信 itxiaozhi666

https://pan.baidu.com/s/1lnf4buCVHgX4mMN2F1Zdbw
nweh


# CGLIB动态代理

## 是什么?

-  [Code Generation Library](https://github.com/cglib/cglib)。翻译:代码生成库。

- 底层使用的是ASM。 ASM是一个Java字节码操纵框架 ,它能被用来动态生成类或者增强既有类的功能。

  > 首先看下官方中的说明 ASM a very small and fast Java bytecode manipulation framework。
  >
  > ASM是一个JAVA字节码分析、创建和修改的开源应用框架。
  >
  > ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

## 能干吗?

- 可以实现动态代理。
- 不要求委托类需要实现接口,没有接口照样能实现代理业务。
- 实现基于方法级别的拦截处理。

## 如何用?

### // Simple code

#### // 委托类

```java
// 被代理类,不需要实现接口
public class SimpleRealSubject {
    public String f1(String str) {
        System.out.println("SimpleRealSubject public f1 " + str);
        return "public f1";
    }
}
```

#### // 方法拦截器

```java
// 方法增强逻辑拦截器
public class SimpleMethodInterceptor implements MethodInterceptor {
    private SimpleMethodInterceptor() {}
    private static SimpleMethodInterceptor myMethodInterceptor = new SimpleMethodInterceptor();
    // 这里提供单例即可
    public static SimpleMethodInterceptor getInstance() {
        return myMethodInterceptor;
    }
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        // 执行基类的方法(也就是委托类)的真实业务逻辑
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("after");
        return result;
    }
}
```

#### // 获取代理对象

```java
public class SimpleProxyInstanceFactory {
    public static <T> T getProxyInstance(Class<T> cls) {
        // 构建增强器
        Enhancer enhancer = new Enhancer();
        // 需要传入具体的 cglib动态代理回调处理类
        enhancer.setCallback(SimpleMethodInterceptor.getInstance());
        // 指定被代理的类的类信息对象
        enhancer.setSuperclass(cls);
        // 创建具体的代理类对象实例
        return (T) enhancer.create();
    }
}
```

#### // 客户端测试

```java
public class SimepleClient {
    public static void main(String[] args) {
        SimpleRealSubject simpleRealSubject =
                SimpleProxyInstanceFactory.getProxyInstance(SimpleRealSubject.class);
        simpleRealSubject.f1("黑马程序员");
    }
}
```

![image-20200321095642669](..\素材\image-20200321095642669.png)

### // Another way

#### // 获取代理对象的方式变更

```java
    public static <T> T getProxyInstance2(Class<T> cls) {
        Enhancer enhancer = new Enhancer();
        //2.设置父类
        enhancer.setSuperclass(cls);
        // 设置拦截回调类型
        enhancer.setCallbackType(SimpleMethodInterceptor.class);
        // 创建代理类Class
        Class proxyClass = enhancer.createClass();
        // 给类中注册拦截回调
        Enhancer.registerCallbacks(proxyClass,
                new Callback[]{SimpleMethodInterceptor.getInstance()});
        // 针对构造不做拦截
        enhancer.setInterceptDuringConstruction(false);
        //使用objenesis+cglib构造代理对象
        Objenesis objenesis = new ObjenesisStd(true);
        return (T) objenesis.newInstance(proxyClass);
    }
```

### // 有何区别?

>  [Objenesis](https://link.zhihu.com/?target=http%3A//objenesis.org/)是一个小的Java库,它有一个用途:实例化一个特定类的新对象。 详细参见: https://zhuanlan.zhihu.com/p/27220411。使用`enhancer.createClass();objenesis.newInstance(proxyClass);`在构建生成代理对象的时候不会执行委托类的构造方法,会绕过父类构造,直接产生代理类(子类)对象。而使用`enhancer.create();`构建的代理对象,则是走的JVM正常构建对象的流程。

#### // 区别演示

// 在委托类中添加一个public成员属性

```java
public class SimpleRealSubject {
    public String name = "SimpleRealSubject";
    // ...略
```

// Client中使用代理对象,直接访问name

```java
System.out.println(simpleRealSubject.name);
```

#### // 结果展示

// 第一种方式,使用`enhancer.create();`

```java
    public static void main(String[] args) {
        // 这里用的getProxyInstance
        SimpleRealSubject simpleRealSubject =
                SimpleProxyInstanceFactory.getProxyInstance(SimpleRealSubject.class);
        simpleRealSubject.f1("黑马程序员");
        // 打印代理对象的成员属性,实则是访问的父类(委托类)的成员属性
        System.out.println(simpleRealSubject.name); // 可访问到(委托类)父类public成员属性
    }
```

![image-20200321155546985](..\素材\image-20200321155546985.png)

// 第二种方式,使用`enhancer.createClass();Enhancer.registerCallbacks;objenesis.newInstance`构建代理对象;

```java
    public static void main(String[] args) {
        // 这里用的getProxyInstance2
        SimpleRealSubject simpleRealSubject =
                SimpleProxyInstanceFactory.getProxyInstance2(SimpleRealSubject.class);
        simpleRealSubject.f1("黑马程序员");
        // 打印代理对象的成员属性,实则是访问的父类(委托类)的成员属性
        System.out.println(simpleRealSubject.name); // null
    }
```

![image-20200321155511827](..\素材\image-20200321155511827.png)

#### // Spring中用的是哪一种?

#### // Objenesis方式的意义

.....

1 个回复

倒序浏览
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马