Spring AOP組件

一、Pointcut

   這個類位於 org.springframework.aop 包中,它的做用就是定義切面的匹配點。(簡單的說就是我去切哪些類、哪些方法…) 在 Spring Aop 中匹配的點主要是 class 與 method 這兩個方面, 分別爲ClassFilter 與 MethodFilter正則表達式

// 由 ClassFilter 與 MethodMatcher 組成的 pointcut
public interface Pointcut {
    // 類過濾器, 能夠知道哪些類須要攔截
    ClassFilter getClassFilter();
    // 方法匹配器, 能夠知道哪些方法須要攔截
    MethodMatcher getMethodMatcher();
    // 匹配全部對象的 Pointcut
    Pointcut TRUE = TruePointcut.INSTANCE;
}
ClassFilter和MethodMatcher分別用於匹配將執行織入操做的對象以及相應的方法。 
在 Spring 中主要有如下幾個類,介紹以下:
一、NameMatchMethodPointcut:經過剛發名進行精確匹配的。 (PS: 其中 ClassFilter = ClassFilter.TRUE)
2、ControlFlowPointcut:根據在當前線程的堆棧信息中的方法名來決定是否切入某個方法(效率較低)
三、ComposablePointcut:組合模式的 Pointcut, 主要分紅兩種: 1.組合中全部都匹配算成功 2. 組合中都不匹配纔算成功
4、JdkRegexpMethodPointcut:經過 正則表達式來匹配方法(PS: ClassFilter.TRUE)
5、AspectJExpressionPointcut:經過 AspectJ 包中的組件進行方法的匹配(切點表達式)
6、TransactionAttributeSourcePointcut:經過 
7、TransactionAttributeSource 在 類的方法上提取事務註解的屬性 @Transactional 來判斷是否匹配, 提取到則說明匹配, 提取不到則說明匹配不成功
八、AnnotationJCacheOperationSource:支持JSR107的cache相關注解的支持

二、Advice

  Advice: 建議忠告, 勸告, 通知。它其實最開始是 aopalliance 包中的一個空接口, 接口的存在主要是爲了標示對應類爲 Advice;spring

 在Spring Aop 中 Advice 其實表示的是在 Pointcut 點上應該執行的方法。而這些方法能夠在目標方法以前、以後、包裹、拋出異常等等任何地方執行。編程

public interface Advice {

}

Advice: 其主要分紅兩類:普通advice 與Interceptor/MethodInterceptor緩存

三、Advisor

  Advisor 其實它就是 Pointcut 與 Advice 的組合, Advice 是執行的方法, 而要知道方法什麼時候執行, 則 Advice 必需與 Pointcut 組合在一塊兒, 這就誕生了 Advisor 這個類框架

1、PointcutAdvisor: 咱們在 Spring 中經常使用的 Advisor, 包含一個 Pointcut 與一個 advice;
二、DefaultPointcutAdvisor: 最經常使用的 Advisor, 在使用編程式aop時, 不少時候會將 Advice / MethodInterceptor 轉換成 DefaultPointcutAdvisor;
3、NameMatchMethodPointcutAdvisor: 這個是在使用 NameMatchPointcutAdvisor時建立的 Advisor, 主要是經過 方法名來匹配是否執行 Advice;
四、DefaultBeanFactoryPointcutAdisor:自身綁定BeanFactory,須要綁定Spring的IOC容器,能夠經過容器中的Advice註冊的beanName來關聯對應的Advice。
        //聲明一個aspectj切點,一張切面
        JdkRegexpMethodPointcut cut = new JdkRegexpMethodPointcut();
        //cut.setPattern("com.fsx.maintest.Person.run"); //它會攔截Person類下全部run的方法(沒法精確到方法簽名)
        //cut.setPattern(".*run.*");//.號匹配除"\r\n"以外的任何單個字符。*號表明零次或屢次匹配前面的字符或子表達式  因此它攔截任意包下任意類的run方法
        cut.setPatterns(new String[]{".*run.*", ".*say.*"}); //能夠配置多個正則表達  式...  sayHi方法也會被攔截
        // 聲明一個通知(此處使用環繞通知 MethodInterceptor )
        Advice advice = (MethodInterceptor) invocation -> {
            System.out.println("============>放行前攔截...");
            Object obj = invocation.proceed();
            System.out.println("============>放行後攔截...");
            return obj;
        };
        //切面=切點+通知
        // 它還有個構造函數:DefaultPointcutAdvisor(Advice advice); 用的切面就是Pointcut.TRUE,因此若是你要指定切面,請使用本身指定的構造函數
        // Pointcut.TRUE:表示啥都返回true,也就是說這個切面做用於全部的方法上/全部的方法
        // addAdvice();方法最終內部都是被包裝成一個 `DefaultPointcutAdvisor`,且使用的是Pointcut.TRUE切面,所以須要注意這些區別  至關於new DefaultPointcutAdvisor(Pointcut.TRUE,advice);
        Advisor advisor = new DefaultPointcutAdvisor(cut, advice);

四、Advised

   承載一個代理對象須要的必要信息:如相關目標類、Advice、Advisoride

// 這個 Advised 接口的實現着主要是代理生成的對象與AdvisedSupport (Advised的支持器)
public interface Advised extends TargetClassAware {
     // 這個 frozen 決定是否 AdvisedSupport 裏面配置的信息是否改變,設置爲true,那麼一旦代理對象生成的各項代理信息配置完成,不允許進行更改
    boolean isFrozen();
     //若是該值爲true,那麼就是用CGLIB對對象進行代理,默認值爲false
    boolean isProxyTargetClass();
     // 返回代理的接口
    Class<?>[] getProxiedInterfaces();
    // 判斷這個接口是不是被代理的接口
    boolean isInterfaceProxied(Class<?> intf);
    // 設置代理的目標對象
    void setTargetSource(TargetSource targetSource);
    // 獲取代理的對象
    TargetSource getTargetSource();
    // 判斷是否須要將代理的對象暴露到 ThreadLocal中,若是目標對象但願獲取代理對象,則能夠經過AopContext.currentProxy()取得默認值false
    void setExposeProxy(boolean exposeProxy);
    // 返回是否應該暴露代理對象
    boolean isExposeProxy();
     // 設置 Advisor 是否已經在前面過濾過是否匹配 Pointcut (極少用到)
    void setPreFiltered(boolean preFiltered);
    // 獲取 Advisor 是否已經在前面過濾過是否匹配 Pointcut (極少用到)
    boolean isPreFiltered();
    // 獲取全部的 Advisor
    Advisor[] getAdvisors();
    // 增長 Advisor 到鏈表的最後
    void addAdvisor(Advisor advisor) throws AopConfigException;
    // 在指定位置增長 Advisor
    void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
    // 刪除指定的 Advisor
    boolean removeAdvisor(Advisor advisor);
    // 刪除指定位置的 Advisor
    void removeAdvisor(int index) throws AopConfigException;
    // 返回 Advisor 所在位置的index
    int indexOf(Advisor advisor);
    // 將指定的兩個 Advisor 進行替換
    boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
     // 增長 Advice <- 這個Advice將會包裹成 DefaultPointcutAdvisor
    void addAdvice(Advice advice) throws AopConfigException;
    // 在指定 index 增長 Advice <- 這個Advice將會包裹成 DefaultPointcutAdvisor
    void addAdvice(int pos, Advice advice) throws AopConfigException;
    // 刪除給定的 Advice
    boolean removeAdvice(Advice advice);
    // 獲取 Advice 的索引位置
    int indexOf(Advice advice);
    // 將 ProxyConfig 經過 String 形式返回
    String toProxyConfigString();
}

五、TargetSource

 TargetSource(目標源)是被代理的target(目標對象)實例的來源。函數

public interface TargetSource extends TargetClassAware {
   //目標對象類型
   Class<?> getTargetClass();
   // 這個方法用戶返回當前bean是否爲靜態的,好比常見的單例bean就是靜態的,而prototype就是動態的,
   // 這裏這個方法的主要做用是,對於靜態的bean,spring是會對其進行緩存的,在屢次使用TargetSource
   // 獲取目標bean對象的時候,其獲取的老是同一個對象,經過這種方式提升效率
   boolean isStatic();
   //獲取目標對象
   Object getTarget() throws Exception;
   // Spring在完目標bean以後會調用這個方法釋放目標bean對象,對於一些須要池化的對象,這個方法是必須
   // 要實現的,這個方法默認不進行任何處理
   void releaseTarget(Object target) throws Exception;
}

 TargetSource最主要的特性:每次方法調用都會觸發TargetSource的getTarget()的方法,該方法會從TargetSource中獲取類中具體的目標對象;this

  在一般狀況下,不管是使用setTarget(),仍是經過setTargetName()方法等設置的目標對象,在框架內部都會經過一個TargetSource實現類對這個設置的目標對象進行封裝,框架內部會以統一的方式處理調用鏈終點的目標對象。spa

 

public void setTarget(Object target) {
        setTargetSource(new SingletonTargetSource(target));
    }

  TargetSource的實現類:prototype

  (1)、SingletonTargetSource

    在經過ProxyFactoryBean的setTarget()方法設置目標對象就是使用SingletonTargetSource,ProxyFactoryBean內部會自行使用一個SingletonTargetSource對設置的目標對象進行封裝。

public class SingletonTargetSource implements TargetSource, Serializable {
    /** use serialVersionUID from Spring 1.2 for interoperability */
    private static final long serialVersionUID = 9031246629662423738L;
    /** Target cached and invoked using reflection */
    private final Object target;
    /**
     * Create a new SingletonTargetSource for the given target.
     * @param target the target object
     */
    public SingletonTargetSource(Object target) {
        Assert.notNull(target, "Target object must not be null");
        this.target = target;
    }
    @Override
    public Class<?> getTargetClass() {
        return this.target.getClass();
    }

    @Override
    public Object getTarget() {
        return this.target;
    }

    @Override
    public void releaseTarget(Object target) {
        // nothing to do
    }

    @Override
    public boolean isStatic() {
        return true;
    }
    /**
     * Two invoker interceptors are equal if they have the same target or if the
     * targets or the targets are equal.
     */
    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof SingletonTargetSource)) {
            return false;
        }
        SingletonTargetSource otherTargetSource = (SingletonTargetSource) other;
        return this.target.equals(otherTargetSource.target);
    }
    /**
     * SingletonTargetSource uses the hash code of the target object.
     */
    @Override
    public int hashCode() {
        return this.target.hashCode();
    }
    @Override
    public String toString() {
        return "SingletonTargetSource for target object [" + ObjectUtils.identityToString(this.target) + "]";
    }

}

(2)、PrototypeTargetSource 

   每次getTarget()將生成prototype類型的bean,即其生成的bean並非單例的,於是使用這個類型的TargetSource時須要注意,封裝的目標bean必須是prototype類型的。PrototypeTargetSource繼承了AbstractBeanFactoryBasedTargetSource擁有了建立bean的能力。

public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource {
   @Override
   public Object getTarget() throws BeansException {
      return newPrototypeInstance();
   }
   @Override
   public void releaseTarget(Object target) {
      destroyPrototypeInstance(target);
   }
   @Override
   public String toString() {
      return "PrototypeTargetSource for target bean with name '" + getTargetBeanName() + "'";
   }
}
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource {
   @Override
   public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      super.setBeanFactory(beanFactory);
      // Check whether the target bean is defined as prototype.
      if (!beanFactory.isPrototype(getTargetBeanName())) {
         throw new BeanDefinitionStoreException(
               "Cannot use prototype-based TargetSource against non-prototype bean with name '" +
               getTargetBeanName() + "': instances would not be independent");
      }
   }
   /**
    * Subclasses should call this method to create a new prototype instance.
    * @throws BeansException if bean creation failed
    */
   protected Object newPrototypeInstance() throws BeansException {
      if (logger.isDebugEnabled()) {
         logger.debug("Creating new instance of bean '" + getTargetBeanName() + "'");
      }
      //使用容器建立一個bean,若是getTargetBeanName()是prototype的,則target目標對象也是prototype的
      return getBeanFactory().getBean(getTargetBeanName());
   }
   /**
    * Subclasses should call this method to destroy an obsolete prototype instance.
    * @param target the bean instance to destroy
    */
   protected void destroyPrototypeInstance(Object target) {
      if (logger.isDebugEnabled()) {
         logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'");
      }
      if (getBeanFactory() instanceof ConfigurableBeanFactory) {
         ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target);
      }
      else if (target instanceof DisposableBean) {
         try {
            ((DisposableBean) target).destroy();
         }
         catch (Throwable ex) {
            logger.warn("Destroy method on bean with name '" + getTargetBeanName() + "' threw an exception", ex);
         }
      }
   }
   //---------------------------------------------------------------------
   // Serialization support
   //---------------------------------------------------------------------
   private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
      throw new NotSerializableException("A prototype-based TargetSource itself is not deserializable - " +
            "just a disconnected SingletonTargetSource or EmptyTargetSource is");
   }
 
   /**
    * Replaces this object with a SingletonTargetSource on serialization.
    * Protected as otherwise it won't be invoked for subclasses.
    * (The {@code writeReplace()} method must be visible to the class
    * being serialized.)
    * <p>With this implementation of this method, there is no need to mark
    * non-serializable fields in this class or subclasses as transient.
    */
   protected Object writeReplace() throws ObjectStreamException {
      if (logger.isDebugEnabled()) {
         logger.debug("Disconnecting TargetSource [" + this + "]");
      }
      try {
         // Create disconnected SingletonTargetSource/EmptyTargetSource.
         Object target = getTarget();
         return (target != null ? new SingletonTargetSource(target) :
               EmptyTargetSource.forClass(getTargetClass()));
      }
      catch (Exception ex) {
         String msg = "Cannot get target for disconnecting TargetSource [" + this + "]";
         logger.error(msg, ex);
         throw new NotSerializableException(msg + ": " + ex);
      }
   }
}
相關文章
相關標籤/搜索