Sak*_*sho 5 java spring caching redis spring-boot
我想将主数据缓存到Redis.
所以,我写了这些代码.
@Configuration
@EnableCaching
public class AppConfig extends CachingConfigurerSupport {
@Bean
@Autowired
public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
Map<String, Long> expires = new HashMap<>();
expires.put("cache.day", new Long(24 * 60 * 60));
cacheManager.setExpires(expires);
return cacheManager;
}
}
Run Code Online (Sandbox Code Playgroud)
和
package com.taisho.artifacts.repository.impl;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.List;
@Repository
public class TestRepository {
@Cacheable(value = "cache.day", key = "'cache.test'")
public List<String> getTest() {
List<String> list = new ArrayList<>();
list.add("test");
list.add("sample");
return list;
}
public void printTest() {
System.out.println(getTest());
}
}
Run Code Online (Sandbox Code Playgroud)
和ymlfile
spring:
redis:
host: 127.0.0.1
port: 26379
Run Code Online (Sandbox Code Playgroud)
但是,缓存无法正常工作......
每当我调用printTest方法时,"getTest"方法都会执行.Redis没有数据......我的代码中有什么问题?
SpringBoot版本是1.4.0
依赖是
compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-data-redis:${springBootVersion}")
compile("org.springframework.boot:spring-boot-autoconfigure:${springBootVersion}")
Run Code Online (Sandbox Code Playgroud)
Spring AOP是基于代理的,因此当您getTest()
从printTest()
方法调用方法时,getTest()
将在this
引用时调用该方法,而不是能够执行缓存操作的代理版本.通常这是一种设计气味,您最好重新考虑当前的设计.但作为一种解决方法,您可以使用AopContext
:
public void printTest() {
System.out.println(((TestRepository) AopContext.currentProxy()).getTest());
}
Run Code Online (Sandbox Code Playgroud)
假设你有一个具有访问客户端代码TestRepository
通过依赖注入:
@Component
class SomeUnfortunateClient {
// I know field injection is evil!
@Autowired TestRepository testRepository;
void youAreGoingToBeSurprised() {
testRepository.printTest();
}
}
Run Code Online (Sandbox Code Playgroud)
这TestRepository
是一个Spring托管存储库,为了添加其他功能TestRepository
,例如缓存,Spring将为它创建一个代理.这意味着对testRepository
对象引用的方法调用将是代理上的调用,因此代理将能够委托给与该特定方法调用相关的所有拦截器(通知).在您的情况下,这些建议将检查缓存条目是否存在.
但是,一旦调用最终到达目标对象,TestRepository
在这种情况下的引用,它可能对其自身进行的任何方法调用,例如System.out.println(getTest());
,将针对this
引用而不是代理调用. 这意味着自我调用不会导致与方法调用相关的建议有机会执行.
正如Spring文档所述:
好的,那么该怎么办呢?最好的方法(这里松散地使用最好的术语)是重构代码,以便不会发生自我调用.当然,这确实需要你做一些工作,但这是最好的,最少侵入性的方法.接下来的方法是绝对可怕的,我几乎要谨慎地指出它,因为它是如此可怕.你可以(窒息!)通过这样做完全将你的类中的逻辑绑定到Spring AOP:
public class SimplePojo implements Pojo {
public void foo() {
// this works, but... gah!
((Pojo) AopContext.currentProxy()).bar();
}
public void bar() {
// some logic...
}
}
Run Code Online (Sandbox Code Playgroud)
这完全将您的代码耦合到Spring AOP,它使类本身意识到它正在AOP上下文中使用,它在AOP面前飞行.在创建代理时,还需要一些额外的配置.
这个答案很大程度上基于Spring Documentation,所以对于(甚至!)更详细的讨论,你一定要查看Spring Documentation中的Understanding AOP proxyies部分.
归档时间: |
|
查看次数: |
5040 次 |
最近记录: |