Spring 由緩存切點驅動的通知者
阿新 • • 發佈:2019-01-26
() 獲取 spec lowest eve matcher 緩存 運行 war
Spring 緩存通知者和切點
緩存切點
/** * Spring 核心切點抽象 */ public interface Pointcut { /** * 類過濾器,當前切點是否需要織入在指定的類上 */ ClassFilter getClassFilter(); /** * 方法匹配器,當前切點是否需要織入在指定的方法上 */ MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; } /** * 檢查目標方法是否需要獲得通知 */ public interface MethodMatcher { /** * 目標方法是否需要獲得通知, * isRuntime() 和此方法返回 false 時,不執行通知。 */ boolean matches(Method method, Class<?> targetClass); /** * 是否需要執行運行時匹配【false 表示只需要執行靜態匹配即可】 * 如果 isRuntime() 返回 true,則 * matches(Method method, Class<?> targetClass) * && matches(Method method, Class<?> targetClass, Object... args) * 都返回 true 時才執行通知 */ boolean isRuntime(); /** * 當 matches(Method method, Class<?> targetClass) 和 isRuntime() 都返回 true 時, * 在通知執行前再次進行匹配 */ boolean matches(Method method, Class<?> targetClass, Object... args); /** * 匹配所有方法 */ MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; } /** * 不關心運行時參數的靜態方法匹配器 */ public abstract class StaticMethodMatcher implements MethodMatcher { @Override public final boolean isRuntime() { return false; } @Override public final boolean matches(Method method, Class<?> targetClass, Object... args) { // should never be invoked because isRuntime() returns false throw new UnsupportedOperationException("Illegal MethodMatcher usage"); } } /** * 緩存操作切點抽象 */ @SuppressWarnings("serial") abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { /** * 目標類的指定方法是否需要通知 */ @Override public boolean matches(Method method, Class<?> targetClass) { // 排除緩存管理器 if (CacheManager.class.isAssignableFrom(targetClass)) { return false; } final CacheOperationSource cas = getCacheOperationSource(); // 存在緩存操作源 && 指定方法上能解析到緩存操作 return cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass)); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof CacheOperationSourcePointcut)) { return false; } final CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other; return ObjectUtils.nullSafeEquals(getCacheOperationSource(), otherPc.getCacheOperationSource()); } @Override public int hashCode() { return CacheOperationSourcePointcut.class.hashCode(); } @Override public String toString() { return getClass().getName() + ": " + getCacheOperationSource(); } /** * Obtain the underlying {@link CacheOperationSource} (may be {@code null}). * To be implemented by subclasses. */ @Nullable protected abstract CacheOperationSource getCacheOperationSource(); }
緩存通知者
/** * 持有 AOP 通知的基礎接口 */ public interface Advisor { /** * 如果沒有正確配置通知,則返回一個空通知 * @since 5.0 */ Advice EMPTY_ADVICE = new Advice() {}; /** * 返回切面的通知 */ Advice getAdvice(); /** * 此通知是否與具體的實例關聯【不可共享】 */ boolean isPerInstance(); } /** * 由切入點驅動的通知者接口 */ public interface PointcutAdvisor extends Advisor { /** * 獲取驅動此 Advisor 的切入點 */ Pointcut getPointcut(); } @SuppressWarnings("serial") public abstract class AbstractPointcutAdvisor implements PointcutAdvisor, Ordered, Serializable { /** * 此 Advisor 關聯切面的順序值:值越小,越先執行 */ @Nullable private Integer order; public void setOrder(int order) { this.order = order; } @Override public int getOrder() { if (order != null) { return order; } final Advice advice = getAdvice(); if (advice instanceof Ordered) { return ((Ordered) advice).getOrder(); } return Ordered.LOWEST_PRECEDENCE; } @Override public boolean isPerInstance() { return true; } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof PointcutAdvisor)) { return false; } final PointcutAdvisor otherAdvisor = (PointcutAdvisor) other; return ObjectUtils.nullSafeEquals(getAdvice(), otherAdvisor.getAdvice()) && ObjectUtils.nullSafeEquals(getPointcut(), otherAdvisor.getPointcut()); } @Override public int hashCode() { return PointcutAdvisor.class.hashCode(); } } /** * 以 BeanFactory 為基礎的切點通知者,通知可以配置為 BeanFactory 中的 bean。 */ @SuppressWarnings("serial") public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware { /** * 通知 Bean 的名稱 */ @Nullable private String adviceBeanName; /** * Bean 工廠 */ @Nullable private BeanFactory beanFactory; /** * 延遲初始化的通知對象 */ @Nullable private transient volatile Advice advice; /** * 鎖 */ private transient volatile Object adviceMonitor = new Object(); public void setAdviceBeanName(@Nullable String adviceBeanName) { this.adviceBeanName = adviceBeanName; } @Nullable public String getAdviceBeanName() { return adviceBeanName; } @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; resetAdviceMonitor(); } private void resetAdviceMonitor() { if (beanFactory instanceof ConfigurableBeanFactory) { adviceMonitor = ((ConfigurableBeanFactory) beanFactory).getSingletonMutex(); } else { adviceMonitor = new Object(); } } public void setAdvice(Advice advice) { synchronized (adviceMonitor) { this.advice = advice; } } /** * 從 beanFactory 中讀取通知實例 */ @Override public Advice getAdvice() { Advice advice = this.advice; // 通知已經初始化,則直接返回 if (advice != null) { return advice; } Assert.state(adviceBeanName != null, "‘adviceBeanName‘ must be specified"); Assert.state(beanFactory != null, "BeanFactory must be set to resolve ‘adviceBeanName‘"); // 通知 bean 是單例 if (beanFactory.isSingleton(adviceBeanName)) { // 依賴於 Bean 工廠提供的單例語義 advice = beanFactory.getBean(adviceBeanName, Advice.class); this.advice = advice; return advice; } else { synchronized (adviceMonitor) { advice = this.advice; if (advice == null) { advice = beanFactory.getBean(adviceBeanName, Advice.class); this.advice = advice; } return advice; } } } @Override public String toString() { final StringBuilder sb = new StringBuilder(getClass().getName()); sb.append(": advice "); if (adviceBeanName != null) { sb.append("bean ‘").append(adviceBeanName).append("‘"); } else { sb.append(advice); } return sb.toString(); } } /** * 由 CacheOperationSource 驅動的 Advisor */ @SuppressWarnings("serial") public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private CacheOperationSource cacheOperationSource; /** * 緩存操作切點 */ private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() { @Override @Nullable protected CacheOperationSource getCacheOperationSource() { return cacheOperationSource; } }; public void setCacheOperationSource(CacheOperationSource cacheOperationSource) { this.cacheOperationSource = cacheOperationSource; } public void setClassFilter(ClassFilter classFilter) { pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return pointcut; } }
Spring 由緩存切點驅動的通知者