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 由缓存切点驱动的通知者的主要内容,如果未能解决你的问题,请参考以下文章

观察者模式

Spring Aop切点

Spring切点表达式

Spring AOP

Spring aop 注解参数说明

spring 中aop 切面实践