java注解:AOP编程-使用注解引入缓存(redis)
一、java注解简介
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
二、自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Iredis { String prefix(); long timeout(); TimeUnit timeUnit(); }
三、4种标准元数据
1.@Target
@Target用于描述注解的使用范围,也就是说使用了@Target去定义一个注解,那么可以决定定义好的注解能用在什么地方可以用ElementType枚举类来指定范围
2.@Retention
@Retention用于描述注解的生命周期,也就是说这个注解在什么范围内有效,注解的生命周期和三个阶段有关:源代码阶段(SOURCE)、class文件中有效(CLASS)、运行时有效(RUNTIME),
3.@Documented
@Documented表示该注解是否可以生成到API文档中。
4.@Inherited
@Inherited是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个Annotation将被用于该class的子类。
四、自定义注解在Spring中的应用
在这之前需要普及一些Spring的注解
@Component:把普通pojo实例化到spring容器中
@Aspect:把当前类标识为一个切面供容器读取
@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行
@Around:环绕通知,围绕着方法执行
@AfterReturning:返回通知,在方法返回结果之后执行
@AfterThrowing:异常通知,在方法抛出异常之后执行
注解方式应用切面类
1.创建切面类
@Component @Aspect public class RedisAspect { /** * 环绕切面 * @annotation:用于匹配当前执行方法持有指定注解的方法 * @param point * @return * @throws Throwable */ @Around("@annotation(com.test.annotation.Iredis)") public Object around(ProceedingJoinPoint point) throws Throwable { System.out.println("hello"); //point.proceed();方法是用来执行注解标注方法的 Object data = point.proceed(point.getArgs()); return data; } }
环绕通知注意地方:
1. 环绕通知的参数类型必须是ProceedingJoinPoint类型的,他是JoinPoint的子接口,可以控制何时执行连接点
2. 在环绕通知中必须使用ProceedingJoinPoint的proceed()方法来手动执行被代理的方法
3. 环绕通知的方法需要返回proceed()方法执行后的结果,否则会出现空指针异常
2.创建连接点
在连接点上加入自定义注解就通过注解来应用切面类了
这里的方法是根据id查询用户的一个方法
@Iredis(prefix = "ss" , timeout = 1L , timeUnit = TimeUnit.SECONDS) @Override public Admin getAdmin(Integer id) { Admin admin = adminMapper.selectAdminById(id); return admin; }
3.创建测试类验证
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:spring-beans.xml" , "classpath:spring-mybatis.xml"}) public class AOPtest { @Autowired AdminService adminService; @Test public void test01() { System.out.println(adminService.getAdmin(1)); } }
返回结果
hello Admin{id=1, name='lzy', sex=1, age=20, desc='sdsdfs'}
五、通过注解引入redis缓存
直接代码
@Slf4j @Component @Aspect public class RedisAspect { @Resource StringRedisTemplate redisTemplate; /** * 环绕切面 * @annotation:用于匹配当前执行方法持有指定注解的方法 * @param point * @return * @throws Throwable */ @Around("@annotation(com.test.annotation.Iredis)") public Object around(ProceedingJoinPoint point) throws Throwable { Object data = null; try { log.info("前置通知"); //获取连接点参数 Object[] args = point.getArgs(); //获取连接点方法 MethodSignature signature = (MethodSignature) point.getSignature(); //获取方法上的注解 Iredis annotation = signature.getMethod().getAnnotation(Iredis.class); //如果没有获取到注解直接返回方法执行结果 if (annotation == null){ return point.proceed(args); } //获取注解prefix值(redis的前缀名) String prefix = annotation.prefix(); //将前缀名和参数进行累加,参数是具体的ID值 if (args!=null){ for (Object arg : args) { prefix+=arg.toString(); } } //先进行查找判断redis里是否有这条数据,如果有就直接返回redis里的数据 Object redisData = getRedisData(prefix , signature); if (null!=redisData){ return redisData; }else { //没有在缓存中查到数据,需要将数据存入缓存 Lock lock = new ReentrantLock(); lock.lock(); try { //进行第二次判断 if (null == redisData){ data = point.proceed(args); Gson gson = new Gson(); //将数据以json字符串形式存入redis,redis数据类型为String类型 redisTemplate.opsForValue().set(prefix , gson.toJson(data) , annotation.timeout() , annotation.timeUnit()); redisData=data; } return redisData; }catch (Exception e){ //e.printStackTrace(); }finally { lock.unlock(); } } }catch (Exception e){ log.info("异常通知"+e); }finally { log.info("后置通知"); } return null; } public Object getRedisData(String prefix , MethodSignature signature){ String s = redisTemplate.opsForValue().get(prefix); //判断是否查询出数据,redis返回的数据是JSON格式的字符串 if (null!=s){ //获取连接点返回值类型,并将json格式字符串转成对应的类型返回 Class returnType = signature.getReturnType(); Gson gson = new Gson(); return gson.fromJson(s, returnType); } return null; } }
如果使用ssm框架出现获取不到注解的情况需要在spring配置文件里面加入
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> <aop:aspectj-autoproxy proxy-target-class="true"/>
- 点赞
- 收藏
- 分享
- 文章举报
- 使用java5的注解和Sping/AspectJ的AOP 来实现Memcached的缓存
- 使用java5的注解和Sping/AspectJ的AOP 来实现Memcached的缓存
- 使用java5的注解和Sping/AspectJ的AOP 来实现Memcached的缓存
- 使用java5的注解和Sping/AspectJ的AOP 来实现Memcached的缓存
- Java乔晓松-基于注解的面向AOP(切面)编程
- 使用AOP与注解记录Java日志
- spring 配置 cache 缓存使用 Redis(基于注解)
- JAVA中使用redis+protoStuff实现数据库缓存机制
- 小白第七篇 Spring AOP编程 使用@AspectJ注解的方式
- 使用AOP与注解记录Java日志
- 【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列
- spring-redis缓存方案学习三:基于aop的自定义注解开发
- 缓存AOP编程的文摘(java例子),数据缓存切入编程的文章。【截取】
- 使用Redis和Java进行数据库缓存 - DZone数据库
- Spring AOP整合redis(注解方式) 实现缓存统一管理
- 基于 自己定义注解 和 aop 实现使用memcache 对数据库的缓存 演示样例
- 使用 AOP 和注解实现方法缓存
- 【JavaWeb-24】AOP介绍和术语、手动/半自动/自动实现AOP、基于XML和注解的AspectJ使用、JdbcTemplate的使用
- Java自定义注解实现Redis自动缓存的方法
- 【原】spring redis 缓存注解使用