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;
}
}