源码地址 https://github.com/alibaba/jetcache
示例代码地址:https://gitee.com/youxiaxiaomage/java-practices/tree/master/yxxmg-jetcache-sample
核心代码
@EnableMethodCache
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({CommonConfiguration.class, ConfigSelector.class})
public @interface EnableMethodCache {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}. <strong>
* Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with {@code @Cacheable}.
* For example, other beans marked with Spring's {@code @Transactional} annotation will
* be upgraded to subclass proxying at the same time. This approach has no negative
* impact in practice unless one is explicitly expecting one type of proxy vs another,
* e.g. in tests.
*/
boolean proxyTargetClass() default false;
/**
* Indicate how caching advice should be applied. The default is
* {@link AdviceMode#PROXY}.
*
* @see AdviceMode
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* Indicate the ordering of the execution of the caching advisor
* when multiple advices are applied at a specific joinpoint.
* The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
String[] basePackages();
}
@Import的关键类ConfigSelector
public class ConfigSelector extends AdviceModeImportSelector<EnableMethodCache> {
@Override
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return getProxyImports();
case ASPECTJ:
// return getAspectJImports();
default:
return null;
}
}
private String[] getProxyImports() {
List<String> result = new ArrayList<String>();
result.add(AutoProxyRegistrar.class.getName());
result.add(JetCacheProxyConfiguration.class.getName());
return result.toArray(new String[result.size()]);
}
}
其中JetCacheProxyConfiguration
为jetcache
核心配置类
@Configuration
public class JetCacheProxyConfiguration implements ImportAware, ApplicationContextAware {
protected AnnotationAttributes enableMethodCache;
private ApplicationContext applicationContext;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.enableMethodCache = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableMethodCache.class.getName(), false));
if (this.enableMethodCache == null) {
throw new IllegalArgumentException(
"@EnableMethodCache is not present on importing class " + importMetadata.getClassName());
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Bean(name = CacheAdvisor.CACHE_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public CacheAdvisor jetcacheAdvisor(JetCacheInterceptor jetCacheInterceptor) {
CacheAdvisor advisor = new CacheAdvisor();
advisor.setAdvice(jetCacheInterceptor);
advisor.setBasePackages(this.enableMethodCache.getStringArray("basePackages"));
advisor.setOrder(this.enableMethodCache.<Integer>getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public JetCacheInterceptor jetCacheInterceptor() {
return new JetCacheInterceptor();
}
}
核心类JetCacheInterceptor
public class JetCacheInterceptor implements MethodInterceptor, ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(JetCacheInterceptor.class);
@Autowired
private ConfigMap cacheConfigMap;
private ApplicationContext applicationContext;
private GlobalCacheConfig globalCacheConfig;
ConfigProvider configProvider;
CacheManager cacheManager;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
if (configProvider == null) {
configProvider = applicationContext.getBean(ConfigProvider.class);
}
if (configProvider != null && globalCacheConfig == null) {
globalCacheConfig = configProvider.getGlobalCacheConfig();
}
if (globalCacheConfig == null || !globalCacheConfig.isEnableMethodCache()) {
return invocation.proceed();
}
if (cacheManager == null) {
cacheManager = applicationContext.getBean(CacheManager.class);
if (cacheManager == null) {
logger.error("There is no cache manager instance in spring context");
return invocation.proceed();
}
}
Method method = invocation.getMethod();
Object obj = invocation.getThis();
CacheInvokeConfig cac = null;
if (obj != null) {
String key = CachePointcut.getKey(method, obj.getClass());
cac = cacheConfigMap.getByMethodInfo(key);
}
if (cac == null || cac == CacheInvokeConfig.getNoCacheInvokeConfigInstance()) {
return invocation.proceed();
}
CacheInvokeContext context = configProvider.newContext(cacheManager).createCacheInvokeContext(cacheConfigMap);
context.setTargetObject(invocation.getThis());
context.setInvoker(invocation::proceed);
context.setMethod(method);
context.setArgs(invocation.getArguments());
context.setCacheInvokeConfig(cac);
context.setHiddenPackages(globalCacheConfig.getHiddenPackages());
return CacheHandler.invoke(context);
}
public void setCacheConfigMap(ConfigMap cacheConfigMap) {
this.cacheConfigMap = cacheConfigMap;
}
}
核心注解
@Cached
@CacheUpdate
@CacheInvalidate
@CacheRefresh