Spring 由缓存切点驱动的通知者
Posted 竺旭东
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring 由缓存切点驱动的通知者相关的知识,希望对你有一定的参考价值。
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 由缓存切点驱动的通知者的主要内容,如果未能解决你的问题,请参考以下文章