黑马程序员技术交流社区
标题: 面试官系列之二CGLIB动态代理 [打印本页]
作者: 长沙-小知姐姐 时间: 2020-4-29 15:35
标题: 面试官系列之二CGLIB动态代理
本帖最后由 长沙-小知姐姐 于 2020-7-24 15:55 编辑
完整版视频及笔记资料 回帖可见提取码 若失效请联系微信 itxiaozhi666
https://pan.baidu.com/s/1lnf4buCVHgX4mMN2F1Zdbw
[hide=d30]nweh[/hide]
# 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("黑马程序员");
}
}
```

### // 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);
}
```
### // 有何区别?
#### // 区别演示
// 在委托类中添加一个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成员属性
}
```

// 第二种方式,使用`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
}
```

#### // Spring中用的是哪一种?
#### // Objenesis方式的意义
.....
作者: lusaisai 时间: 2020-5-21 17:27
多谢分享
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |