1

前言

  开启AOP功能后,AOP的逻辑是如何开始进行的。

一、Bean的生命周期

  要讲AOP就必须了解Spring Bean的生命周期,AOP的逻辑是在Bean初始化后这个阶段开始的。Spring Bean的生命周期简单上图:
 
Bean生命周期.jpg

二、AOP

(一)@EnableAspectJAutoProxy

  Spring中使用该注解开启AOP功能。该注解会注册一个AutoProxyCreatorAnnotationAwareAspectJAutoProxyCreatorAspectJAwareAdvisorAutoProxyCreator】相关的类到IOC容器中,AutoProxyCreator相关的类实现了InstantiationAwareBeanPostProcessor接口,即在Bean实例化前后会执行AOP的一些前置准备操作。

  • 其中AbstractAutoProxyCreator实现了BeanFactoryAware接口,是我们事务和aop导入进来的后置处理器的顶级父类;
  • AbstractAutoProxyCreator postProcessBeforeInstantiation实例化前方法中,会进行AOP切面Bean的缓存(是AdvicePointCutAdvisor基础Bean类型就直接跳过不解析);
     

    /**  AbstractAutoProxyCreator
       * 在我们的创建Bean的流程中还没调用构造器来实例化bean的时候进行调用(实例化前后)
       * 我们的aop 解析切面 以及事务解析事务注解都是在这里完成的
       * @param beanClass 当前正在创建的bean的class对象
       * @param beanName beanName
       * @return
       * @throws BeansException
       */
      @Override
      public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
          //构建我们的缓存key
          Object cacheKey = getCacheKey(beanClass, beanName);
    
          if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
              //如果被解析过 直接返回
              if (this.advisedBeans.containsKey(cacheKey)) {
                  return null;
              }
              /**
               * 判断是不是基础的bean
               * 判断是不是应该跳过 (aop解析直接解析出我们的切面信息(并且把我们的切面信息进行保存),而事务在这里是不会解析的)
               */
              if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                  this.advisedBeans.put(cacheKey, Boolean.FALSE);
                  return null;
              }
          }
    
          /**
           * 这个地方一般是不会生成代理对象的,除非我们的容器中有TargetSourceCreator 并且我们的bean需要实现
           * TargetSource接口
           */
          TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
          if (targetSource != null) {
              if (StringUtils.hasLength(beanName)) {
                  this.targetSourcedBeans.add(beanName);
              }
              Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
              Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
              this.proxyTypes.put(cacheKey, proxy.getClass());
              return proxy;
          }
    
          return null;
      }

    (二)创建Proxy代理对象

  • AbstractAutoProxyCreator postProcessAfterInitialization初始化后方法中【每个Bean在创建的时候都会调用】,会进行AOP代理对象的创建,主要方法:wrapIfNecessary
     

    /**  AbstractAutoProxyCreator
       * 在该后置方法中,AOP的代理对象在这生成
       * @param bean bean实例
       * @param beanName bean的名称
       * @return
       * @throws BeansException
       */
      @Override
      public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {
          if (bean != null) {
              //获取缓存key
              Object cacheKey = getCacheKey(bean.getClass(), beanName);
              if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                  //找到合适的就会被代理
                  return wrapIfNecessary(bean, beanName, cacheKey);
              }
          }
          return bean;
      }

    wrapIfNecessary方法如下:
     

    /**  AbstractAutoProxyCreator wrapIfNecessary
       * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
       * @param bean the raw bean instance
       * @param beanName the name of the bean
       * @param cacheKey the cache key for metadata access
       * @return a proxy wrapping the bean, or the raw bean instance as-is
       */
      protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
          //已经被处理过
          if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
              return bean;
          }
          //不需要增强的
          if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
              return bean;
          }
          //是不是基础的bean 是不是需要跳过的
          if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
              this.advisedBeans.put(cacheKey, Boolean.FALSE);
              return bean;
          }
    
          //如果我们有通知的话,就创建代理对象
          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;
      }
  • 创建代理的核心方法:createProxy(基于ProxyFactory)。其中真正的创建代理对象的方法是ProxyFactory.getProxy方法;
     

    /**  
       * Create a new proxy according to the settings in this factory.
       * <p>Can be called repeatedly. Effect will vary if we've added
       * or removed interfaces. Can add and remove interceptors.
       * <p>Uses the given class loader (if necessary for proxy creation).
       * @param classLoader the class loader to create the proxy with
       * (or {@code null} for the low-level proxy facility's default)
       * @return the proxy object
       */
      public Object getProxy(@Nullable ClassLoader classLoader) {
          //createAopProxy() 用来获取我们的代理工厂
          return createAopProxy().getProxy(classLoader);
      }

    createAopProxy方法会判断使用JDK动态代理还是CGLIB
     

    • CGLIB代理方式在第一次执行AOP操作的时候可能耗时会比较长,因为需要生成新的字节码文件;
    • 总的情况,CGLIBJDK的方式性能都差不多;但是相比使用原生的AspectJ,性能还是要差上一些。AspectJ是基于字节码编制技术,不借助于Proxy对象实现。
       
    /**
       * 实现类DefaultAopProxyFactory createAopProxy
       * @param config 用来为我们指定我们advisor信息
       * 该方法用来创建我们的代理对象
       * 所我们的targetClass对象实现了接口,且  ProxyTargetClass 没有指定强制的走cglib代理,那么就是创建jdk代理
       * 我们代理的类没有实现接口,那么会直接走cglib代理
       * 若我们   ProxyTargetClass 指定为false 且代理类是接口才会走jdk代理 否在我们还是cglib代理
       * @return
       * @throws AopConfigException
       */
      @Override
      public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
          //判断我们是否强制指定使用cglib代理ProxyTargetClass =true  fasle
          if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
              Class<?> targetClass = config.getTargetClass();
              if (targetClass == null) {
                  throw new AopConfigException("TargetSource cannot determine target class: " +
                          "Either an interface or a target is required for proxy creation.");
              }
              //所targetClass是接口 使用的就是jdk代理
              if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                  return new JdkDynamicAopProxy(config);
              }
              //cglib代理
              return new ObjenesisCglibAopProxy(config);
          }
          else {
              //动态代理
              return new JdkDynamicAopProxy(config);
          }
      }
    // 实现类JdkDynamicAopProxy getProxy方法
    @Override
      public Object getProxy(@Nullable 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);
      }
    
      /**
       * Finds any {@link #equals} or {@link #hashCode} method that may be defined
       * on the supplied set of interfaces.
       * @param proxiedInterfaces the interfaces to introspect
       */
      private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
          for (Class<?> proxiedInterface : proxiedInterfaces) {
              Method[] methods = proxiedInterface.getDeclaredMethods();
              for (Method method : methods) {
                  if (AopUtils.isEqualsMethod(method)) {
                      this.equalsDefined = true;
                  }
                  if (AopUtils.isHashCodeMethod(method)) {
                      this.hashCodeDefined = true;
                  }
                  if (this.equalsDefined && this.hashCodeDefined) {
                      return;
                  }
              }
          }
      }

    创建完的代理对象就会保存到DefaultSingletonBeanRegistry的单例池singletonObjects中,之后getBean()获取到的就是这个单例池中的代理对象。


  后续思考针对AOP的一些优化措施,特别是环绕通知,在遇到所有AOP的性能瓶颈点的时候基本都是环绕通知。


开翻挖掘机
225 声望26 粉丝

不忘初心❤️,且行且思考