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 cache 缓存介绍
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
- [转]注释驱动的 Spring cache 缓存介绍
原文:http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/ 概述 Spring 3.1 引入了激动人心的基于注释(an ...
- 注释驱动的 Spring cache 缓存介绍--转载
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
- Spring cache 缓存
概述 Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使 ...
- Spring实战——缓存
缓存 提到缓存,你能想到什么?一级缓存,二级缓存,web缓存,redis-- 你所能想到的各种包罗万象存在的打着缓存旗号存在的各种技术或者实现,无非都是宣扬缓存技术的优势就是快,无需反复查询等. 当然 ...
- Spring 对缓存的抽象
Cache vs. Buffer A buffer is used traditionally as an intermediate temporary store for data between ...
- 谈谈spring的缓存
缓存到底扮演了什么角色 请移步: http://hacpai.com/article/1376986299174 在对项目进行优化的时候,我们可以主要从以下三个方面入手: 1 缓存 2 集群 3 异 ...
- Spring之缓存注解@Cacheable
https://www.cnblogs.com/fashflying/p/6908028.html https://blog.csdn.net/syani/article/details/522399 ...
- Java缓存学习之五:spring 对缓存的支持
(注意标题,Spring对缓存的支持 这里不单单指Ehcache ) 从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache ...
随机推荐
- Centos7 配置LAMP+fastcgi(Centos7.2+php7.0+mariadb+httpd)
环境:阿里云centos7.3 一.安装并配置数据库 1.安装数据库 #yum install mariadb-server mariadb -y 2.启动服务并设置开机自启 # systemctl ...
- ActiveMQ利用ajax收发消息
准备工作: 后台需要导包: activemq-all.jar activemq-web.jar jetty-all.jar 如果是maven项目: pom.xml <dependency> ...
- 将本地的java项目提交到github出错解决
1.我们新建一个了java项目后,需要提交到github进行版本控制 2.如果此时github中的仓库不为空,我们在本地使用git push提交时会报以下错误, ! [rejected] ...
- 基于新版 node 的 vue 脚手架搭建
1. node 安装版本 9+ 2. 命令行 创建方式 vue create project 3. 可视化 创建方式 vue ui 4. 扩展 goole 下 vue 调试工具安装 git 资源 ...
- PL/SQL中判断字段为空
功能写完发现数据库里好多关键字段是空的,可以直接删掉,可直接: DELETE FROM 表名 WHERE 字段 IS NULL OR TRIM(字段) = ''
- SOA架构简介
一. 什么是SOA 架构 SOA是一种架构模型,它可以根据需求通过网络对松散耦合的粗粒度应用组件进行分布式部署.组合和使用.服务层是SOA的基础,可以直接被应用调用,从而有效控制系统中与软件代理交互的 ...
- 点亮指路灯led
为什么要使用LED? (bootloader,kernel)开发初期,由于串口等硬件尚未被初始化,因此调试手段相当有限,这时通常会采用LED来做为程序调试的重要手段. LED驱动设计: 1.设置GPI ...
- Codeforces1204C. Anna, Svyatoslav and Maps (贪心 + Floyd)
题目链接:传送门 题目大意: 给出n<=100的有向图,和路径p,求p的最短子序列v,使得依次经过v中所有点的路径为p. 思路: 题意其实就是让我们求路径上的一些关键点v,对于所有的关键点:vi ...
- Anaconda3安装及使用
一.安装及环境变量配置 1.从这里下载Anaconda 2.根据提示安装即可 3.配置环境变量:%Anaconda%\Script 打开命令行,输入:conda --version,回显版本即完成安装 ...
- SpringBoot框架(6)--事件监听
一.场景:类与类之间的消息通信,例如创建一个对象前后做拦截,日志等等相应的事件处理. 二.事件监听步骤 (1)自定义事件继承ApplicationEvent抽象类 (2)自定义事件监听器,一般实现Ap ...