Spring技术原理之Spring AOP

静态代理:
  1. image-20210601103153495
  2. 问题:
    1. 每个RealSubject对应编写一个Proxy类,比较麻烦。
    2. 大量的Proxy类会导致类规模增大不易维护,影响编译
动态代理:
  1. image-20210601103246821

  2. 两个问题:

    1. 自动生成的Proxy类如何代理实体类?
    2. 运行时如何生成Proxy类?
  3. 自动生成的Proxy类如何代理实体类?

    1. 定义一个全局的公共代理类:Proxy

    2. Proxy类可以根据实体类RealSubject或者实体类的接口来生成一个功能增强的具体代理类(xxxProxy)。注:通过接口生成-JDK动态代理,通过继承生成-CgLib动态代理。

    3. 还有一个问题,这个功能增强的类需要我们在每一个被代理的方法上添加自己的业务逻辑,怎么实现?

    4. 聪明的你肯定可以想到:抽象出一个公共的业务处理接口类InvocationHandler,每个实体类实现这个接口类,定义自己的增强逻辑。

    5. 调用时直接调用生成的xxxProxy对象就好了,因为他和原始的RealSubject具有同样的功能。

    6. JDK动态代理的核心类

      public interface InvocationHandler {
          /**
          * 统一代理接口
          * @param proxy 动态代理生成的对象实例
          * @param method 被代理对象的方法,用于区分哪个对象
          * @param args 调用时传入的参数,用于调用时传入的参数
          * @return
          * @throws Throwable
          */
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
      }
      public class Proxy implements java.io.Serializable {
          @CallerSensitive
          public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
          throws IllegalArgumentException{
          //...
          }
      }
      
    7. 例子

      /*** @Description 实体类*/
      public class ProxyTest implements ProxyTestInterface{
          @Overridepublic 
          Integer add(Integer a, Integer b) {return a+b;}
      }
      //下面分别通过静态代理和动态代理来实现代理功能
      
      //静态代理
      /**
      * @Description 静态代理类
      */
      public class StaticProxyTest implements ProxyTestInterface {
          public StaticProxyTest(ProxyTest proxyTest){
          	this.proxyTest = proxyTest;
          }
          private ProxyTest proxyTest;
          @Override
          public Integer add(Integer a, Integer b) {
          	return proxyTest.add(a,b);
          }
          public void main(String[] args){
              ProxyTest proxyTest = new ProxyTest();
              StaticProxyTest staticProxyTest = new StaticProxyTest(proxyTest);
              Integer ret = staticProxyTest.add(1,2);
              System.out.println(ret);
          }
      }
      
      //动态代理
      /**
      * @Description 动态代理测试类
      */
      public class DynamicProxyTest {
          public static void main(String[] args){
              ProxyTest proxyTest = new ProxyTest();
              InvocationHandler handler = new MyInvocationHandler(proxyTest);
              ProxyTestInterface proxyTestInterface =
              (ProxyTestInterface) Proxy.newProxyInstance(proxyTest.getClass().getClassLoader(),ProxyTest.class.getInterfaces(),handler);
              Integer ret = proxyTestInterface.add(1,2);
              System.out.println(ret);
              //将动态代理生成的类输出到硬盘上,便于查看
           	ProxyUtils.generateClassFile(proxyTest.getClass(),"test");
          }
          
          static class MyInvocationHandler implements InvocationHandler{
              public MyInvocationHandler(ProxyTest test){
              	proxyTest = test;
              }
              ProxyTest proxyTest;
              @Override
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                  System.out.println(method.getName());
                  Object obj = method.invoke(proxyTest,args);
                  return obj;
              }
          }
      }
      
      
    8. 动态代理源码分析

      public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
          Objects.requireNonNull(h);
          final Class<?>[] intfs = interfaces.clone();
          //此处省略一些代码
          /*
          * 此处是关键,生成代理类,是jdk按照class文件的格式,生成二级制数据流,然后再调用native方法生成运行时的Class的
          */
          Class<?> cl = getProxyClass0(loader, intfs);
          //Invoke its constructor with the designated invocation handler.
          try {
              if (sm != null) {
                  checkNewProxyPermission(Reflection.getCallerClass(), cl);
              }
              final Constructor<?> cons = cl.getConstructor(constructorParams);
              final InvocationHandler ih = h;
              if (!Modifier.isPublic(cl.getModifiers())) {
                  AccessController.doPrivileged(new PrivilegedAction<Void>() {
                      public Void run() {
                          cons.setAccessible(true);
                          return null;
                      }
                  });
              }
              //通过反射,调用有参构造函数完成实例化,此处的参数h就是我们自定义的MyInvocationHandler的实例,那这个构造函数是从哪里生成的?目前猜想肯定是生成的代理的.
              return cons.newInstance(new Object[]{h});
          } catch (IllegalAccessException|InstantiationException e) {
              throw new InternalError(e.toString(), e);
          }
          //...
      }
      
      
      
    9. 生成代理类的class文件

      public class ProxyUtils {
      
          /**
           * 将根据类信息动态生成的二进制字节码保存到硬盘中,默认的是clazz目录下
           * @param clazz 需要生成动态代理类的类
           * @param proxyName 生成的代理类的名称
           */
          public static void generateClassFile(Class clazz,String proxyName)
          {
              //根据类信息和提供的代理类名称,生成字节码
              byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
              String paths = clazz.getResource(".").getPath();
              System.out.println(paths);
              FileOutputStream out = null;
      
              try {
                  //保留到硬盘中
                  out = new FileOutputStream(paths+proxyName+".class");
                  out.write(classFile);
                  out.flush();
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  try {
                      out.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
    10. 运行时生成的代理类

      public final class jdkProxyTest extends Proxy implements ProxyTestInterface {
          private static Method m1;
          private static Method m2;
          private static Method m3;
          private static Method m0;
          
      	public jdkProxyTest(InvocationHandler var1) throws  {
              super(var1);
          }
          
           public final Integer add(Integer var1, Integer var2) throws  {
              try {
                  return (Integer)super.h.invoke(this, m3, new Object[]{var1, var2});
              } catch (RuntimeException | Error var4) {
                  throw var4;
              } catch (Throwable var5) {
                  throw new UndeclaredThrowableException(var5);
              }
          }
          
          static {
              try {
                  m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
                  m2 = Class.forName("java.lang.Object").getMethod("toString");
                  m3 = Class.forName("com.javhl.course.dynamicproxy.ProxyTestInterface").getMethod("add", Class.forName("java.lang.Integer"), Class.forName("java.lang.Integer"));
                  m0 = Class.forName("java.lang.Object").getMethod("hashCode");
              } catch (NoSuchMethodException var2) {
                  throw new NoSuchMethodError(var2.getMessage());
              } catch (ClassNotFoundException var3) {
                  throw new NoClassDefFoundError(var3.getMessage());
              }
          }
      
      }
      
    11. JDK动态代理为什么要求被代理类必须实现接口: Java只支持单继承,可以实现多接口.

  4. CGLIB动态代理:

    /**
     * @Description cglib代理测试类
     */
    public class CGLibProxyTest{
    
        public static void main(String[] args){
            // 代理类class文件存入本地磁盘方便我们反编译查看源码
            			System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
            MethodInterceptor methodInterceptor = new MyMethodInterceptor();
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(ProxyTest.class);
            enhancer.setCallback(methodInterceptor);
    
            ProxyTest proxyTest = (ProxyTest) enhancer.create();
            Integer ret = proxyTest.add(1,2);
            System.out.println(ret);
        }
    
        /**
         * 业务增强类,实现耗时时间统计的功能
         */
        static class MyMethodInterceptor implements MethodInterceptor{
            
    		@Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                long curTime = System.nanoTime();
                //调用父类的方法
                Object ret = methodProxy.invokeSuper(o,objects);
                System.out.println(String.format("耗时:%s 纳秒",System.nanoTime()-curTime));
                return ret;
            }
    
        }
    }
    
    
    1. CGLIB动态代理类源码

      public interface Factory {
          Object newInstance(Callback var1);
          Object newInstance(Callback[] var1);
          Object newInstance(Class[] var1, Object[] var2, Callback[] var3);
          Callback getCallback(int var1);
          void setCallback(int var1, Callback var2);
          void setCallbacks(Callback[] var1);
          Callback[] getCallbacks();
      }
      
      
      /**
       * Cglib运行时生成的动态代理源码
       */
      public class ProxyTest$$EnhancerByCGLIB$$17e654b8 extends ProxyTest
        implements Factory{
           public final Integer add(Integer paramInteger1, Integer paramInteger2){
              MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
              if (tmp4_1 == null)
              {
                tmp4_1;
                CGLIB$BIND_CALLBACKS(this);
              }
              MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
              //如果自己设置了MethodInterceptor那么就使用MethodInterceptor的intercepor方法,否则就使用父类的方法
              if (tmp17_14 != null)
                return (Integer)tmp17_14.intercept(this, CGLIB$add$0$Method, new Object[] { paramInteger1, paramInteger2 }, CGLIB$add$0$Proxy);
              //调用父类ProxyTest的方法,其实此时跟没应用代理是一样的
              return super.add(paramInteger1, paramInteger2);
          }
      }
      
  5. JDK动态代理 VS CGLIB动态代理:

    1. JDK动态代理基于接口,动态代理类和被代理类实现同样的接口。
    2. CGLIB动态代理基于继承,动态代理类继承被代理类,是被代理类的子类。
    3. 两者都需要一个中间类来实现具体的代理逻辑,JDK动态代理的中间类必须实现InvocationHandler接口;CGLIB动态代理的中间类必须实现MethodInterceptor接口。
    4. 在InvocationHandler中JDK动态代理通过反射调用被代理类的接口,必须持有被代理类的实例引用;在MethodInterceptor中CGLIB动态代理通过继承显示调用被代理类的接口。
Spring AOP
  1. AOP相关概念

    1. **Aspect:**切面,一系列Pointcut和Advice的组合。可以想象成多个切点组成了一个切面。
    2. **Joinpoint :**连接点,主要是指类的方法,一个方法就是一个连接点。
    3. **Advice:**当切点与joinpoint匹配时,对joinpoint所采取的行动。具体来说这个Advice就是一个方法,当joinpoint匹配时,就执行这个方法。在Spring AOP中可以用@Before,@After,@Around,@AfterReturn,@AfterThrow注解来定义一个Advice。
    4. **Pointcut:**与 joinpoint 匹配的正则表达式,用于判断连接点是否被命中的规则。主要通过包路径和注解等方式来定义配置规则。
    5. Weaving:将Advice植入到Joinpoint中,具体的方法是代理模式,在Spring中采用的是动态代理,具体有JDK动态代理和CGLib动态代理。
  2. 工作原理

    image-20210601171109562

  3. 面向切面编程机制

    image-20210601171212797

  4. 例子

    /**
     * @Description AOP测试类,统计接口运行时长
     */
    @Component
    @Aspect
    public class MethodCallTimeAspect {
    
        @Pointcut("execution(* com.javhl..*.*(..))")
        private void myPointCut(){
    
        }
    
        @Around("myPointCut()")
        public Object advice (ProceedingJoinPoint joinPoint) throws Throwable{
    
            //方法调用开始时间
            long startTime = System.nanoTime();
            Object result = null;
            try {
                result = joinPoint.proceed();
            }finally {
                long timeUsed = System.nanoTime() - startTime;
                StringBuilder sb = new StringBuilder();
                sb.append("class name = [ ").append(joinPoint.getTarget().getClass().getName()).append(" ] ");
                sb.append("methd name = [ ").append(joinPoint.getSignature().getName()).append(" ]")
                        .append(" 耗时: ").append(timeUsed).append(" 纳秒");
                System.out.println(sb.toString());
            }
            return result;
        }
    }
    
    
  5. Spring框架在创建bean的过程中,当bean完成了初始化后,会用AnnotationAwareAspectJAutoProxyCreator的后置处理器判断bean是否需要代理,如果需要代理(表明配置的Pointcut命中了bean)那么会根据切面中配置的advice为bean创建一个动态代理对象,并将这个对象放到Spring容器中,以后就用这个代理对象来代理具体的bean完成相关业务逻辑。

  6. AbstractAutoProxyCreator源码分析

    public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
        implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware{
        
        //BeanPostProcessor的前置处理,这里不做任何处理原样返回
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
          return bean;
        }
    
        /**
         * 在bean实例化完成之后,对bean进行包装,生成代理对象。
         */
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
          if (bean != null) {
            //获取bean的缓存名称
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //判断之前创建的代理引用对象中是否包含当前bean,若有:说明bean已经被包装过了直接返回;否则:调用wrapIfNecessary方法对bean进行包装
            //earlyProxyReferences主要是用来解决Spring中的bean循环依赖时(A依赖B,B依赖A),为需要代理的bean创建代理对象的
            if (!this.earlyProxyReferences.contains(cacheKey)) {
              return wrapIfNecessary(bean, beanName, cacheKey);
            }
          }
          return bean;
        }
        
        /*
        Spring容器启动创建循环依赖的bean的时候,会调用该方法给存在循环依赖的Bean一个创建AOP代理的机会,如果bean满足AOP的条件则创建,否则不创建。
        */
        @Override
        public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //如果引用不存在则添加
            if (!this.earlyProxyReferences.contains(cacheKey)) {
              this.earlyProxyReferences.add(cacheKey);
            }
            //调用包装方法创建代理对象
            return wrapIfNecessary(bean, beanName, cacheKey);
          }
        
        /**
         * 判断bean是否需要被包装,如果需要返回代理后的对象,否则返回原对象
         */
        protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
          return bean;
        }
        if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
          return bean;
        }
        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
          this.advisedBeans.put(cacheKey, Boolean.FALSE);
          return bean;
        }
        // 判断该bean是否有匹配的切点,如果有则根据pointcut和advise生成advisors
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
        if (specificInterceptors != DO_NOT_PROXY) {
          this.advisedBeans.put(cacheKey, Boolean.TRUE);
          //真正的创建代理的方法,下文会重点分析该方法
          Object proxy = createProxy(
              bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
          this.proxyTypes.put(cacheKey, proxy.getClass());
          return proxy;
        }
        this.advisedBeans.put(cacheKey, Boolean.FALSE);
        return bean;
       }
        
        protected Object createProxy(
          Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
         //...
            
        //此句代码是关键,获取具体的代理对象,下面我们继续分析该代码
        //DefaultAopProxyFactory ==>proxyFactory
        return proxyFactory.getProxy(getProxyClassLoader());
      }
     }
    
  7. DefaultAopProxyFactory源码分析

    public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
    
      @Override
      public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
          Class<?> targetClass = config.getTargetClass();
          //判断目标对象是否为空,为空则抛出异常
          if (targetClass == null) {
            //...
          }
          //判断目标对象是否是接口或者JDK动态代理动态生成的对象,
          //若是则构造一个JDK动态代理对象返回,否则构造一个Cglib动态代理对象返回
          if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
          }
          return new ObjenesisCglibAopProxy(config);
        }
        else {
          return new JdkDynamicAopProxy(config);
        }
      }
    
    
    }
    
  8. JdkDynamicAopProxy 源码分析:

    //这个类实现了InvocationHandler接口
    final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
      @Override
      public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
      }
    
      @Override
      public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
          logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        //此处获取目标对象的接口
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        //生成具体的代理对象
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
      }
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隐 风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值