本帖最后由 长沙-小知姐姐 于 2020-7-24 15:55 编辑
完整版视频及笔记资料 回帖可见提取码 若失效请联系微信 itxiaozhi666
https://pan.baidu.com/s/1lnf4buCVHgX4mMN2F1Zdbw nweh
# 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); } ```
### // 有何区别?
#### // 区别演示
// 在委托类中添加一个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方式的意义
.....
|