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

原文地址:https://www.cnblogs.com/zhuxudong/p/10322618.html

时间: 2024-10-06 04:15:11

Spring 由缓存切点驱动的通知者的相关文章

注释驱动的 Spring cache 缓存介绍--转载

概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果. Spring 的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存

注释驱动的 Spring cache 缓存介绍

概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果. Spring 的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存

[转]注释驱动的 Spring cache 缓存介绍

原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/ 概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果. Spring 的缓存技术还具备相当的灵活性,不仅能

使用 Spring 2.5 注释驱动的 IoC 功能

使用 Spring 2.5 注释驱动的 IoC 功能 原文链接 :http://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/ 文中对Spring 2.5新引入的注解配置做了详细的讲解以及实例,包括 @Autowired  @Qualifier @Resource @PostConstruct 和 @PreDestroy <context:annotation-config/> <context:component-scan/&

使用 Spring 2.5 注释驱动的 IoC 功能(转)

基于注释(Annotation)的配置有越来越流行的趋势,Spring 2.5 顺应这种趋势,提供了完全基于注释配置 Bean.装配 Bean 的功能,您可以使用基于注释的 Spring IoC 替换原来基于 XML 的配置.本文通过实例详细讲述了 Spring 2.5 基于注释 IoC 功能的使用. 陈 雄华 ([email protected]), 技术总监, 宝宝淘网络科技有限公司 2008 年 2 月 28 日 内容 概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 J

spring的缓存机制

在Spring缓存机制中,包括了两个方面的缓存操作:1.缓存某个方法返回的结果:2.在某个方法执行前或后清空缓存. spring是怎么进行缓存的,白话点讲就是:一个map来进行缓存,当调用aop时访问缓存,判断是否有对应数据存在.具体如下: 1.EHCache Spring仅仅是提供了对缓存的支持,但它并没有任何的缓存功能的实现,spring使用的是第三方的缓存框架来实现缓存的功能.其中,spring对EHCache提供了很好的支持.下面我们以EHCache为例来介绍spring的缓存配置. 在

Spring Boot 缓存的基本用法

目录 一.目的 二.JSR-107 缓存规范 三.Spring 缓存抽象 四.Demo 1.使用 IDEA 创建 Spring Boot 项目 2.创建相应的数据表 3.创建 Java Bean 封装数据 4.整合 MyBatis 1.配置数据源信息 2.使用注解版 MyBatis 5.实现 Web 访问 6.缓存初体验 7.使用 redis 缓存中间件 1.使用 docker 安装 redis(阿里云服务器) 2.使用 Redis Desktop Manager 连接阿里云服务器 3.引入 r

Ajax登陆,使用Spring Security缓存跳转到登陆前的链接

Spring Security缓存的应用之登陆后跳转到登录前源地址 什么意思? 用户访问网站,打开了一个链接:(origin url)起源链接 请求发送给服务器,服务器判断用户请求了受保护的资源. 由于用户没有登录,服务器重定向到登录页面:/login 填写表单,点击登录 浏览器将用户名密码以表单形式发送给服务器 服务器验证用户名密码.成功,进入到下一步.否则要求用户重新认证(第三步) 服务器对用户拥有的权限(角色)判定.有权限,重定向到origin url; 权限不足,返回状态码403( "禁

Spring Boot缓存注解@Cacheable、@CacheEvict、@CachePut使用

从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回.所以在使用Spring Cache的时候我们要保证我们缓存的方法对于相同的方法参数要有相同的返回结果. 使用Spring Cache需要我们做两方面的事: