spring-aop原理讲解JDK动态代理和CGLIB动态代理转载

原创
小哥 3年前 (2022-10-27) 阅读数 45 #大杂烩

Spring这两个主要特征IOC和AOP
IOC负责将对象动态注入到容器中,从而达到向需要的人、需要的人注入的效果。理解spring的ioc这也很重要。
但今天我主要跟大家谈一谈。aop。
AOP 广泛用于处理一些具有横切属性的系统级服务, AOP 新技术的出现 OOP 好的补充品 ,用于处理系统中跨模块分布的横切关注点,如事务管理、日志记录、缓存等。

AOP实现以下目标的关键AOP该框架是自动创建的。AOP代理。

AOP代理主要分为静态代理和动态代理,

  • 静态剂的代表是AspectJ;
  • 使用了动态代理。Spring AOP为代表

1,AspectJ

AspectJ是对静态代理的增强,使用编译时生成 AOP 因此,代理类也称为编译时增强,具有更好的性能。
缺点:但是,需要使用特定的编译器进行处理。

2,Spring AOP

Spring AOP使用动态代理,运行时生成 AOP 智能体类,即所谓的动态智能体。AOP框架不会修改字节码,但会在内存中为该方法临时生成一个字节码。AOP对象,则此AOP该对象包含目标对象的所有方法,并在特定切点处增强,并回调原始对象的方法。
劣势:到期 Spring AOP 需要在每次运行时生成 AOP 代理,所以性能略差一些。

由于aspectj使用时还需要使用特定的编译器进行处理,处理起来有点麻烦。今天很重要,需要解释一下Spring AOP

Spring AOP动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。

  • JDK动态代理通过反射接收被代理的类,并要求被代理的类必须实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
  • 如果目标类不实现该接口,则Spring AOP将选择使用CGLIB以动态代理目标类。CGLIB(Code Generation Library)是代码生成的类库,它在运行时动态生成类的子类(通过修改字节码来实现代理)。
    注意,CGLIB是由继承完成的动态代理,因此如果将类标记为final,则它不可用。CGLIB做动态代理。
    jdk和cglib动态代理以联合实现我们的aop面向人脸的功能。

下面是一个简单的代码来演示。jdk和cglib动态代理的实现原理。

一,jdk动态代理实现AOP拦截

  • 1,为target目标类定义一个接口。JdkInterface,这是jdk动态代理实现的前提。

    /**

    • Created by qcl on 2018/11/29
    • desc: jdk动态aop代理需要实现的接口。 */ public interface JdkInterface { public void add(); }
  • 2,使用我们要表示的目标类。JdkClass为了实现我们上面定义的接口,我们的实验目标是不更改。JdkClass在目标类的前提下,在目标类中。add该方法在之前和之后被拦截,添加了自定义切线逻辑。这是aop的魅力:代码和代码之间没有耦合。

    /**

    • Created by qcl on 2018/11/29
    • desc: 表示的类,即目标类。target */ public class JdkClass implements JdkInterface { @Override public void add() { System.out.println("目标类的add方法"); } }

-3 ,到关键的一步,用我们的MyInvocationHandler,实现InvocationHandler接口,并实现该接口。invoke方法。仔细看invoke方法,即向该方法添加切线逻辑。执行目标类方法mehod.invoke(target,args)本声明已完成。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Created by qcl on 2018/11/29
 * desc:这里添加了切线逻辑。
 */
public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before-------面连接逻辑");
        Object invoke = method.invoke(target, args);//目标类的方法由反射执行。
        System.out.println("after-------面连接逻辑");
        return invoke;
    }
}
  • 4,测试结果

    /**

    • Created by qcl on 2018/11/29
    • desc:测试 */ public class JdkTest { public static void main(String[] args) { JdkClass jdkClass = new JdkClass(); MyInvocationHandler handler = new MyInvocationHandler(jdkClass); // Proxy为InvocationHandler实现类动态创建符合接口的代理实例。 //这里的proxyInstance是我们的目标类的增强代理类 JdkInterface proxyInstance = (JdkInterface) Proxy.newProxyInstance(jdkClass.getClass().getClassLoader(), jdkClass.getClass() .getInterfaces(), handler); proxyInstance.add(); //打印增强的类类型 System.out.println("=============" + proxyInstance.getClass());

      } }

执行上述测试类将产生以下结果

结果

如您所见,目标类的add在该方法之前和之后添加了自定义切线逻辑,AOP拦截机制已经生效。再看一眼class com.sun.proxy.$Proxy0。它在这里得到了进一步的展示 JDK动态代理的核心是InvocationHandler接口和Proxy类

二,cglib动态代理实现AOP拦截

  • 1,定义要代理的。Base目标类(cglib不需要接口定义)

    /**

    • Created by qcl on 2018/11/29
    • desc:要代理的类 */ public class Base { public void add(){ System.out.println("目标类的add方法"); } }
  • 2,定义CglibProxy类,实现MethodInterceptor接口,实现intercept方法。代理的目的也是add在方法之前和之后添加自定义切线逻辑,目标类add方法执行语句为proxy.invokeSuper(object, args)

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

    /**

    • Created by qcl on 2018/11/29
    • desc:这里添加了切线逻辑。 */ public class CglibProxy implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before-------面连接逻辑"); methodProxy.invokeSuper(object, args); System.out.println("after-------面连接逻辑"); return null; } }
  • 3,测试类

    /**

    • Created by qcl on 2018/11/29
    • desc:测试类 */ public class CglibTest { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Base.class); //回调方法的参数是代理类对象。CglibProxy,最后,增强目标类调用代理类对象。CglibProxy中的intercept方法 enhancer.setCallback(proxy); //此刻,base不是自行车的目标类,而是增强的目标类 Base base = (Base) enhancer.create(); base.add();

      Class baseClass = base.getClass();
      //查看增强类的父类是否未增强。Base类
      System.out.println("增强类的父类:"+baseClass.getSuperclass().getName());
      System.out.println("============打印增强类的所有方法。==============");
      FanSheUtils.printMethods(baseClass);
      
      //未增强base类
      Base base2 = new Base();
      System.out.println("未增强类的父类:"+base2.getClass().getSuperclass().getName());
      System.out.println("=============打印添加不强的目标类的方法。===============");
      FanSheUtils.printMethods(base2.getClass());//打印未增强的类的所有方法。

      } }

以下是打印结果

结果

您可以通过打印结果来查看。

  • cglib动态拦截成功接入
  • cglib动态代理是在运行时动态生成的目标类(Base)的子类,并向目标类的现有方法添加了许多内容。cglib独一无二的方法。
    下面发布带有反射的Print类的所有方法的Tool类。

    public class FanSheUtils {

    //打印类的所有方法。
    public static void printMethods(Class cl) {
        System.out.println();
        //获取包含类的所有其他方法的数组。
        Method[] methods = cl.getDeclaredMethods();
        //遍历数组
        for (Method method : methods) {
            System.out.print("  ");
            //获取该方法的修饰符并打印它。
            String modifiers = Modifier.toString(method.getModifiers());
            if (modifiers.length() > 0) {
                System.out.print(modifiers + " ");
            }
            //打印方法名称
            System.out.print(method.getName() + "(");
    
            //获取包含所有参数类型的方法。Class一组对象
            Class[] paramTypes = method.getParameterTypes();
            //遍历数组
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {
                    System.out.print(",");
                }
                System.out.print(paramTypes[i].getName());
            }
            System.out.println(");");
        }
    }

    }

注:以上使用cglib.jar和asm.jar。在我们的maven的pom.xml可以将以下类库引入

        
            org.springframework.boot
            spring-boot-starter-aop
        

作者:编程小石头
链接:https://www.jianshu.com/p/49ebf34afd03
资料来源:简讯
版权归作者所有。请联系作者以获得商业转载的授权,并注明非商业转载的来源。

版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

热门