AOP realiza negócios de cache
Necessidades de negócios
-
1 Use anotações personalizadas para representar métodos de negócios, e o valor de retorno do negócio é armazenado no cache
-
2 Use AOP para interceptar anotações e usar métodos de notificação surround para fazer negócios
Prepare com antecedência
1. Crie o arquivo de configuração do Redis (prepare o nó do redis)
创建properties配置文件,里面存入Redis节点
#准备redis的节点信息
redis.host=192.168.126.129
redis.port=6379
2. Crie uma classe de configuração Redis (o nó é entregue ao contêiner de primavera para gerenciamento)
创建class类 里面导入配置文件存储的节点信息并且交给spring管理
@Configuration //表示一个配置类 一一般会@bean的注解关联
@PropertySource("classpath:/redis.properties") //导入配置文件
public class redis {
@Value("${redis.host}")
private String host;
@Value("${redis.port}")
private Integer port;
@Bean //将方法的返回值结果,交给spring容器进行管理.
public Jedis jedis(){
return new Jedis(host, port);
}
}
3. Crie uma classe de ferramenta Redis (usada para converter objetos em formato JSON e converter objetos em JSON)
把数据库的对象格式转换JSON格式存储缓存中,把缓存的JSON格式转换对象格式传入客户端
public class RedisUtl {
private static final ObjectMapper MAPPER=new ObjectMapper();
//对象转json
public static String toJSON(Object object) {
try {
return MAPPER.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
//2.JSON转化为对象 要求用户传递什么类型就返回什么对象??
public static <T> T toObject(String json,Class<T> target){
try {
return MAPPER.readValue(json, target);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
Caso inicial
1. Crie anotações personalizadas
注解是接口,用来指定目标业务方法,并且拦截
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisAopFind {
String key();
int seconds() default -1;
}
Notas usadas
@Target () ----- Esta anotação descreve o escopo de uso da anotação, onde esta anotação é usada
ElementType ----- valor
MÉTODO ----- Esta anotação é usada para descrever o método
@Retention () ----- A função é definir por quanto tempo as anotações anotadas por ela são retidas
RetentionPolicy ----- valor
RUNTIME ----- as anotações não são apenas salvas no arquivo de classe, mas ainda existem após o jvm carregar o arquivo de classe
String key (); ---- define o valor da chave
segundos int () padrão -1; ---- tempo limite padrão -1 não é tempo limite por padrão
2. As anotações indicam métodos de negócios
-
Aqui está nossa anotação personalizada
-
a chave é o nome do nosso método de negócios
-
O método descrito em nossa anotação personalizada é interceptado no AOP
3. AOP inicial
3.1 Crie uma classe Java, o que significa que a classe criada é uma classe de negócios de Aop
当前的类是处理AOP业务的类
@Component
@Aspect
public class RedisAOP {
@Autowired
private Jedis jedis;
}
@Component ----- Esta classe de descrição de anotação é entregue ao gerenciamento do Spring
@Aspect ----- A classe descrita por esta anotação é uma classe que representa AOP (Orientado a Aspectos)
@Autowired
private Jedis jedis;
我们导入Redis的配置类
4. Estrutura de negócios
@Component
@Aspect
public class RedisAOP {
@Autowired
private Jedis jedis;
@Around("@annotation(redisAopFind)")
public Object around(ProceedingJoinPoint joinPointm, RedisAopFind redisAopFind){
Object result=null;
String Key=redisAopFind.key();
//动态获取方法的参数
String args= Arrays.toString(joinPointm.getArgs());
Key = Key + "::" + args;
if (jedis.exists(Key)){
String json=jedis.get(Key);
//动态获取方法的类型
MethodSignature methodSignature= (MethodSignature) joinPointm.getSignature();
Class returnType = methodSignature.getReturnType();
result = RedisUtl.toObject(json, returnType);
System.out.println("AOP查询redis缓存");
}else{
try {
result =joinPointm.proceed(); //执行下一个通知,执行目标方法
String json=RedisUtl.toJSON(result);
if (redisAopFind.seconds()>0){
jedis.setex(Key, redisAopFind.seconds(), json);
}else {
jedis.set(Key, json);
}
System.out.println("AOP查询数据库");
}catch (Throwable throwable) {
throwable.printStackTrace();
}
}
return result;
}
}
O primeiro passo é interceptar o negócio e encapsular a CHAVE
@Around("@annotation(redisAopFind)")
public Object around(ProceedingJoinPoint joinPoint, RedisAopFind redisAopFind){
Object result=null;
String Key=redisAopFind.key();
//动态获取方法的参数
String args= Arrays.toString(joinPointm.getArgs());
Key = Key + "::" + args;
Em primeiro lugar, eu importo nossa anotação personalizada @Around é a notificação surround, usamos a notificação surround para interceptar o método descrito por nossa anotação personalizada e obter o valor de retorno do método
- JoinPoint - o método do ponto de entrada, o objeto da informação do método alvo sendo executado, o ponto popular (interceptamos o gerenciador do método alvo)
- anotações personalizadas de redisAopFind que criamos
- redisAopFind.key () - Obtenha a chave na anotação personalizada, o valor chave que atribuímos quando a anotação descreve o método de destino
- joinPointm.getArgs () - Obtenha os parâmetros no método de destino, precisamos da concatenação de string, então use o método tostring
Key = Key + "::" + args;
- O valor da chave obtido é combinado com os parâmetros do método de destino para encapsular o valor da chave no redis
incitar:
Nossa KEY muda e não pode usar uma chave fixa. Portanto, se os parâmetros forem combinados, os parâmetros solicitados pelo cliente não serão os mesmos e nossos valores-chave também serão alterados dinamicamente. Isso é fácil de distinguir, e os parâmetros correspondentes também são usados ao armazenar.
Verificação da segunda etapa
1- O valor de KEY existe no Redis (obtenha o valor no redis)
if (jedis.exists(Key)){
String json=jedis.get(Key);
//动态获取方法的类型
MethodSignature methodSignature= (MethodSignature) joinPointm.getSignature();
Class returnType = methodSignature.getReturnType();
result = RedisUtl.toObject(json, returnType);
System.out.println("AOP查询redis缓存");
}
-
Determine se há atualmente nossa CHAVE encapsulada no cache do Redis
-
Se existir, obtenha o valor de KEY
String json=jedis.get(Key);
MethodSignature methodSignature= (MethodSignature) joinPointm.getSignature();
-
Obtenha dinamicamente o tipo do método alvo com base na assinatura
-
getReturnType Obtenha o tipo da assinatura do método de destino atual (ou seja, o tipo do método de destino)
-
O resultado impresso mostra o tipo de método alvo
Class returnType = methodSignature.getReturnType();
缓存中KEY的值转换成目标方法的类型,并返回
result = RedisUtl.toObject(json, returnType);
2- O valor de KEY não existe no redis (consultar o banco de dados e armazená-lo no cache)
else{
try {
result =joinPointm.proceed(); //执行下一个通知,执行目标方法
String json=RedisUtl.toJSON(result);
if (redisAopFind.seconds()>0){
jedis.setex(Key, redisAopFind.seconds(), json);
}else {
jedis.set(Key, json);
}
System.out.println("AOP查询数据库");
}catch (Throwable throwable) {
throwable.printStackTrace();
}
}
-
Se não houver dados de consulta no redis, execute diretamente o método de destino e coloque-o no banco de dados
-
joinPointm.proceed (); execute o método de destino
result =joinPointm.proceed();
String json=RedisUtl.toJSON(result);
-
No momento, não definimos o tempo limite. Se atingirmos o tempo limite no futuro, o tempo limite será maior que 0. Em seguida, defina o tempo limite que definimos ao armazenar
-
Armazene diretamente se não houver tempo limite
if (redisAopFind.seconds()>0){
jedis.setex(Key, redisAopFind.seconds(), json);
}else {
jedis.set(Key, json);
}
Expandir
Quando definimos anotações personalizadas, definimos o padrão sem tempo limite, portanto, se definirmos o tempo limite,
adicionaremos o tempo limite quando a anotação personalizada descrever o método
3. Conclusão de negócios
retornar resultado - retorna o resultado da consulta do cliente
A primeira consulta é o banco de dados, a
segunda consulta é o cache