115怎么分享电影

四川建材 2021-09-14 阅读:25

  // 大多数情况需要通过 MethodProxy.invokeSuper 来实现目标类的调用

  // 但实际上会调用代理类的 EnhancerByCGLIB.hello 实现

  // 调用 buttercup.test.Greet$$EnhancerByCGLIB.CGLIB$hello$0

  // 调用 buttercup.test.Greet.hello

  // 调用:根据 index 找到指定的方法,并进行调用

  // 方法调用(硬编码调用)

  // 根据 Class 对象生成 FastClass

  // 根据方法名称以及参数类型,获取到指定方法对应的 index

  // 根据方法签名,获取到指定方法对应的 index

  // 工厂方法,创建增强后的对象

  // 构造函数(硬编码调用)

  // 获取 index 的最大值

  // 切入点

  // 如果已经初始化过,则直接返回

  // 所有生成的代理方法都调用此方法

  // 通过 MethodProxy 代理 Greet.hell 方法

  // 通过 MethodProxy 代理 Greet.hi 方法

  // 通过 super.hello 调用目标类的 Greet.hello 实现

  // 通过 ThreadLocal 传参

  // 通知

  // 映射:根据方法名称与参数类型,获取其对应的 index

  // 增加 :after 后缀(模拟后置通知)

  // 增加 before: 前缀(模拟前置通知)

  // 直接调用目标类的 hello

  // 直接调用目标类的 hi

  // 只在 MethodProxy 被调用时加载 FastClass,减少不必要的类生成(lazy-init)

  // 重写 hello 方法通知 CALLBACK_1

  // 重写 hi 方法通知 CALLBACK_2

  //索引值分别为 0:hello, 1:hi, 2:equals, 3:hasCode, 4:toString

  @Override

  }

  };

  abstract public class FastClass {

  block2: {

  block3: {

  break;

  Callback callbackArray=(Callback)object2; // 初始化 Callback 参数

  Callback 分类

  case "hello" : return 1; // hello 方法植入前置通知

  case "hi" : return 2; // hi 方法植入后置通知

  case 0: { return 0; } // hello 对应 index 为 0

  case 0: { return 1; } // hi 对应 index 为 1

  case 0: { return 10; }

  case 0: { return 9; }

  case 0: { return greet.hello; } // 通过索引 0 调用 hello

  case 0: { return new Greet; }

  case 1: { return greet.hi; } // 通过索引 1 调用 hi

  case 10: { // 调用目标类的原始 Greet.hi 方法

  case 1155503180: {

  case -1632605946: {

  case 1837078673: {

  case 1891304123: {

  case 3329: {

  case 397774237: {

  case 9: { // 调用目标类的原始 Greet.hello 方法

  case 99162322: {

  CGLib 是一款用于实现高效动态代理的字节码增强库,通过字节码生成技术,动态编译生成代理类,从而将反射调用转换为普通的方法调用。

  CGLIB$hello$0$Method=methodArray[0];

  CGLIB$hello$0$Proxy=MethodProxy.create(clazz, clazz2, "Ljava/lang/String;", "hello", "CGLIB$hello$0");

  CGLIB$hi$1$Method=methodArray[1];

  CGLIB$hi$1$Proxy=MethodProxy.create(clazz, clazz2, "Ljava/lang/String;", "hi", "CGLIB$hi$1");

  CGLIB$THREAD_CALLBACKS.set(callbackArray);

  CGLIB$THREAD_CALLBACKS=new ThreadLocal;

  Class c1; // 目标类 buttercup.test.Greet

  Class c2; // 代理类 buttercup.test.Greet$$EnhancerByCGLIB

  class FranceGreeting implements Dispatcher { // 新接口的实现

  class FranceGreetingMatcher implements CallbackFilter { // 将新接口调用委托给 Dispatcher

  class Greet { // 需要被增强目标类

  Class clazz=Class.forName("buttercup.test.Greet");

  Class clazz2=Class.forName("buttercup.test.Greet$$EnhancerByCGLIB");

  default: return 0; // 其他方法不添加通知

  Dispatcher dispatcher=this.CGLIB$CALLBACK_1;

  Dispatcher 指定上下文,将代理方法调用委托给特定对象

  dispatcher=this.CGLIB$CALLBACK_1;

  Enhancer enhancer=new Enhancer;

  enhancer.setCallbackFilter(new FranceGreetingMatcher); // 关联接口与实现

  enhancer.setCallbackFilter(pointCut); // 设置切点 PointCut

  enhancer.setCallbacks(advices); // 设置通知 Advice

  enhancer.setCallbacks(new Callback{ NoOp.INSTANCE, new FranceGreeting}); // 实现新接口

  enhancer.setInterfaces(new Class{FranceGreet.class}); // 扩展新接口

  enhancer.setSuperclass(Greet.class);

  enhancer.setSuperclass(Greet.class); // 设置目标类

  FastClass f1; // 目标类 FastClass :

  FastClass f2; // 代理类 FastClass :

  fastClassInfo=new FastClassInfo;

  fci.f1=helper(ci, ci.c1); //

  fci.f2=helper(ci, ci.c2); //

  fci.i1=fci.f1.getIndex(this.sig1);

  fci.i2=fci.f2.getIndex(this.sig2);

  final String CGLIB$hello$0 {

  final String CGLIB$hi$1 {

  FixedValue 返回固定值,被代理方法的返回值被忽略

  FranceGreet franceGreet=(FranceGreet) greet;

  g.setType(type);

  Generator g=new Generator;

  Greet greet=(Greet) enhancer.create;

  Greet greet=(Greet) enhancer.create; // 创建 Proxy 对象

  Greet greet=(Greet) obj;

  Greet$$EnhancerByCGLIB Greet$$EnhancerByCGLIB;

  Greet$$EnhancerByCGLIB greet$$EnhancerByCGLIB=(Greet$$EnhancerByCGLIB)obj;

  Greet$$EnhancerByCGLIB greet$$EnhancerByCGLIB=Greet$$EnhancerByCGLIB;

  Greet$$EnhancerByCGLIB Greet$$EnhancerByCGLIB=new Greet$$EnhancerByCGLIB;

  Greet$$EnhancerByCGLIB.CGLIB$BIND_CALLBACKS(this);

  Greet$$EnhancerByCGLIB.CGLIB$BOUND=true;

  greet$$EnhancerByCGLIB.CGLIB$CALLBACK_0=(NoOp)callbackArray[0];

  greet$$EnhancerByCGLIB.CGLIB$CALLBACK_1=(MethodInterceptor)callbackArray[1];

  greet$$EnhancerByCGLIB.CGLIB$CALLBACK_2=(MethodInterceptor)callbackArray[2];

  Greet$$EnhancerByCGLIB.CGLIB$SET_THREAD_CALLBACKS(callbackArray);

  Greet$$EnhancerByCGLIB.CGLIB$SET_THREAD_CALLBACKS(null);

  Greet$$EnhancerByCGLIB.CGLIB$STATICHOOK1;

  Greet$$EnhancerByCGLIB=(Greet$$EnhancerByCGLIB) object;

  if (!methodName.equals("CGLIB$hello$0")) break;

  if (!methodName.equals("CGLIB$hi$1")) break;

  if (!methodName.equals("hello")) break;

  if (!methodName.equals("hi")) break;

  if (!sig.equals("CGLIB$hello$0Ljava/lang/String;")) break;

  if (!sig.equals("CGLIB$hi$1Ljava/lang/String;")) break;

  if (!sig.equals("helloLjava/lang/String;")) break;

  if (!sig.equals("hiLjava/lang/String;")) break;

  if ((object2=CGLIB$STATIC_CALLBACKS)==null) break block2;

  if (dispatcher==null) {

  if (fastClassInfo==null) {

  if (Greet$$EnhancerByCGLIB.CGLIB$BOUND) break block2;

  if (methodInterceptor !=null) { // 调用拦截器 Weaving.adviceAfter

  if (methodInterceptor !=null) { // 调用拦截器 Weaving.adviceBefore

  if (methodInterceptor==null) { // 初始化 CALLBACK_1

  if (methodInterceptor==null) { // 初始化 CALLBACK_2

  if (object2=CGLIB$THREAD_CALLBACKS.get) !=null) break block3; // 从 ThreadLocal 获取 Callback 参数

  init;

  int i1; // 方法在 f1 中对应的索引

  int i2; // 方法在 f2 中对应的索引

  interface FranceGreet { // 支持新功能的接口

  java.lang.reflect.Proxy只支持通过接口生成代理类,这意味着 JDK 动态代理只能代理接口,无法代理具体的类。

  JDK 通过反射实现动态,《电影T55B66》[幑“”]这意味着低下的调用效率:

  Method methodArray=ReflectUtils.findMethods(new String, clazz.getDeclaredMethods);

  MethodInterceptor methodInterceptor=this.CGLIB$CALLBACK_1;

  MethodInterceptor methodInterceptor=this.CGLIB$CALLBACK_2;

  MethodInterceptor 调用拦截器,用于实现环绕通知around advice

  methodInterceptor=this.CGLIB$CALLBACK_1;

  methodInterceptor=this.CGLIB$CALLBACK_2;

  MethodProxy.FastClassInfo fci=new 115怎么分享电影 MethodProxy.FastClassInfo;

  MethodProxy.invokeSuper 通过调用代理类中带 $CGLIB$ 前缀的方法,绕过被重写的代理方法,避免出现无限递归。

  NoOp 不使用动态代理,匹配到的方法不会被重写

  Object object2;

  private boolean CGLIB$BOUND; // 判断 Callback 是否已经初始化

  private Dispatcher CGLIB$CALLBACK_1;

  private final FranceGreet delegate=-> "bonjour";

  private final Object initLock=new Object;

  private MethodInterceptor CGLIB$CALLBACK_1; // Weaving.adviceBefore(增加 before: 前缀)

  private MethodInterceptor CGLIB$CALLBACK_2; // Weaving.adviceAfter(增加 :after 后缀)

  private MethodProxy.CreateInfo createInfo;

  private NoOp CGLIB$CALLBACK_0;

  private NoOp CGLIB$CALLBACK_0; // 默认不拦截,直接调用目标类方法

  private Signature sig1; // 目标类方法签名:helloLjava/lang/String;

  private Signature sig2; // 代理类方法签名:CGLIB$hello$0Ljava/lang/String;

  private static class CreateInfo {

  private static class FastClassInfo {

  private static FastClass helper(MethodProxy.CreateInfo ci, Class type) {

  private static final Callback CGLIB$STATIC_CALLBACKS; // 静态 Callback(忽略)

  private static final Method CGLIB$hello$0$Method;

  private static final Method CGLIB$hi$1$Method;

  private static final MethodProxy CGLIB$hello$0$Proxy;

  private static final MethodProxy CGLIB$hi$1$Proxy;

  private static final Object CGLIB$emptyArgs=new Object[0]; // 默认空参数

  private static final ThreadLocal CGLIB$THREAD_CALLBACKS; // 用于给构造函数传递 Callback

  private static final void CGLIB$BIND_CALLBACKS(Object object) {

  private void init {

  private volatile MethodProxy.FastClassInfo fastClassInfo;

  public abstract int getIndex(String methodName, Class argClass);

  public abstract Object invoke(int index, Object obj, Object args) throws InvocationTargetException;

  public class Greet$$EnhancerByCGLIB extends Greet implements Factory {

  public class Greet$$EnhancerByCGLIB extends Greet implements FranceGreet, Factory {

  public class Greet$$EnhancerByCGLIB$$FastClassByCGLIB extends FastClass {

  public class Greet$$FastClassByCGLIB extends FastClass {

  public class Introduction { // 模拟引入新接口

  public class MethodProxy {

  public class Weaving { // 模拟切面织入过程

  public final String bonjour {

  public final String hello {

  public final String hi {

  public Greet$$EnhancerByCGLIB {

  public Greet$$FastClassByCGLIB(Class clazz) {

  public int accept(Method method) {

  public int getIndex(Signature signature) {

  public int getIndex(String methodName, Class argClass) {

  public int getMaxIndex {

  public interface MethodInterceptor extends Callback {

  public Object intercept(Object obj, Method method, Object args, MethodProxy proxy) throws Throwable;

  public Object invoke(int n, Object obj, Object args) throws InvocationTargetException {

  public Object invoke(Object obj, Object args) throws Throwable {

  public Object invokeSuper(Object obj, Object args) throws Throwable {

  public Object loadObject throws Exception {

  public Object newInstance(Callback callbackArray) {

  public Object newInstance(int n, Object argClass) throws InvocationTargetException {

  public static void CGLIB$SET_THREAD_CALLBACKS(Callback callbackArray) {

  public static void main(String args) throws InterruptedException {

  public String hello { return "hello"; }

  public String hi { return "hi"; }

  public String toString { return "@Greet"; }

  return ((FranceGreet)dispatcher.loadObject).bonjour;

  return (String)methodInterceptor.intercept(this, CGLIB$hello$0$Method, CGLIB$emptyArgs, CGLIB$hello$0$Proxy);

  return (String)methodInterceptor.intercept(this, CGLIB$hi$1$Method, CGLIB$emptyArgs, CGLIB$hi$1$Proxy);

  return 0; // hello 对应 index 为 0

  return -1;

  return 1; // hi 对应 index 为 1

  return 10;

  return 4; // 当前 FastClass 总共支持 5 个方法

  return 9;

  return delegate;

  return fastClassInfo.f1.invoke(fci.i1, obj, args);

  return fastClassInfo.f2.invoke(fci.i2, obj, args);

  return g.create;

  return greet$$EnhancerByCGLIB.CGLIB$hello$0;

  return greet$$EnhancerByCGLIB.CGLIB$hi$1;

  return Greet$$EnhancerByCGLIB;

  return method.getDeclaringClass.equals(FranceGreet.class) ? 1 : 0;

  return super.hello;

  return super.hi;

  static {

  static Callback advices=new Callback { NoOp.INSTANCE, adviceBefore, adviceAfter };

  static CallbackFilter pointCut=method -> {

  static MethodInterceptor adviceAfter=(target, method, args, methodProxy) -> methodProxy.invokeSuper(target, args) + ":after";

  static MethodInterceptor adviceBefore=(target, method, args, methodProxy) -> "before:" + methodProxy.invokeSuper(target, args);

  static void CGLIB$STATICHOOK1 { // 静态初始化

  String bonjour;

  String sig=((Object)signature).toString;

  super(clazz);

  switch (argClass.length) {

  switch (method.getName) {

  switch (methodName.hashCode) {

  switch (n) {

  switch (n) { // 通过 index 指定目标函数

  switch (sig.hashCode) {

  synchronized (initLock) {

  System.out.println(franceGreet.bonjour); // 新接口方法正常调用

  System.out.println(greet.hello);

  System.out.println(greet.hello); // 原方法不受影响

  System.out.println(greet.hi);

  System.out.println(greet.toString);

  throw new IllegalArgumentException("Cannot find matching method/constructor");

  TimeUnit.HOURS.sleep(1);

  案例 Introduction 中仅使用了 Dispatcher,因此只生成了代理类,未使用到 FastClass:

  案例二:Introduction

  案例一:Weaving

  本文案例仅涉及 MethodInterceptor 与 Dispatcher,这两个 Callback 也是 Spring AOP 实现的关键,后续将继续分析相关的源码实现。

  编译动态生成的字节码生成代理类

  补充

  创建代理对象

  此外,CGLib 支持多种 Callback,这里简单介绍几种:

  从前面的案例可以看到,CGLib 使用的方式很简单,大致可以分为两步:

  代理类

  代理类 FastClass

  代理类 FastClass:buttercup.test.Greet$$EnhancerByCGLIB$$FastClassByCGLIB(省略后缀)

  代理类:buttercup.test.Greet$$EnhancerByCGLIB(省略后缀)

  代理类就是 Ehancer.create 中为了创建代理对象动态生成的类,该类不但继承了目标类,并且还重写了需要被代理的方法。其命名规则为:目标类 + $$EnhancerByCGLIB。

  但这类 Callback 也是其中最重的,会导致生成更多的动态类,具体原因后续介绍。

  底层通过 Enhancer.generateClass 生成代理类,其具体过程不作深究,可以简单概括为:

  对于一些外部依赖或者现有模块来说,无法通过该方式实现动态代理。

  反射调用涉及动态类解析,这种不可预测性,导致被反射调用的代码无法被 JIT 内联优化,具体参见反射调用方法

  方法调用:通过 switch(index) 的方式,将反射调用转化为硬编码调用

  方法映射:解析 Class 对象并为每个 Constructor 与 Method 指定一个整数索引值 index

  该对象替代了 Method.invoke 功能,是实现高效方法调用的的关键。下面我们以 Greet.hello 为例对该类进行分析:

  继承目标类并重写override方法,在调用代码中嵌入 Callback

  将生成完成的代理类缓存至LoadingCache,避免重复生成

  可以看到 MethodProxy 的调用实际是通过 FastClass 完成的,这是 CGLib 实现高性能反射调用的秘诀,下面来解析这个类的细节。

  可以通过java.lang.invoke.MethodHandle来规避以上问题,但是这不在本文讨论的范围。

  每次调用 Method.invoke 都会检查方法的可见性、校验参数是否匹配,过程涉及到很多 native 调用,具体参见JNI 调用开销

  目标类 FastClass

  目标类 FastClass:buttercup.test.Greet$$FastClassByCGLIB(省略后缀)

  目标类:buttercup.test.Greet

  配置 Enhancer

  其命名规则为:目标类 + $$FastClassByCGLIB。下面具体分析一下对目标类 Greet 对应的 FastClass:

  其中 MethodInterceptor 最为常用,可以实现多种丰富的代理特性。

  设置需要代理的目标类与接口

  生成的类结构

  随着业务发展,系统需要支持法语的问候 FranceGreet,在不修改现有业务代码的前提下,可以通过 CGLib 实现该功能:

  通过 arthas 的 jad 命令可以观察到,案例 Weaving 中实际生成了以下类:

  通过 Callback 设置需要增强的功能

  通过 CallbackFilter 获取方法与 Callback 的关联关系

  通过 CallbackFilter 将方法匹配到具体的 Callback

  通过ClassEmitter调用 asm 库注入增强方法,并生成byte 形式的字节码

  通过ClassVisitor获取目标类信息

  通过反射调用ClassLoader.defineClass将byte转换为Class对象

  通过反射调用构造函数生成代理对象

  为了保证调用效率,需要对代理类也生成 FastClass:

  为了规避反射带来的性能消耗,cglib 定义了 FastClass 来实现高效的方法调用,其主要职责有两个

  下面通过两个案例体验一下 CGLib 的使用方式。

  现有一个输出问候语句的类 Greet,现在有个新需求:在输出内容前后加上姓名,实现个性化输出。下面通过 CGLib 实现该功能:

  应用场景

  原理简析

  在案例一中,我们分别给 Greet.hello 与 Greet.hi 分别添加了拦截器Weaving.adviceBefore 与 Weaving.adviceAfter,下面我们分析代理类是如何完成这一功能的:

  在动态生成的类中,可以看到 CGLib 为每个被代理的方法创建了 MethodProxy 对象。

  之前提及过:使用 MethodInterceptor 会比其他 Callback 生成更多的动态类,这是因为需要支持 MethodProxy.invokeSuper 调用:

  只能代理接口

  字节码生成过程




这是四川苏洋建材有限公司,官网(四川建材公司 16:14:54)

评论(0)