本文内容:spring中如何使用注解实现面向切面编程,以及如何使用自定义注解。


一个场景

比如用户登录,每个请求发起之前都会判断用户是否登录,如果每个请求都去判断一次,那就重复地做了很多事情,只要是有重复的地方,就有优化的空间。现在就把重复的地方抽取出来,暂且称之为 " 拦截器 ",然后每次请求之前就先经过" 拦截器 ",这个编程的思想就可以称之为面向切面编程。AOP(Aspect Oriented Program)

最典型的应用就是事务管理和权限验证,还有日志统计,下文中的案例就是接口执行时间的统计。

spring中使用AOP(基于注解)

不得不说注解是个很巧妙的设计,使用很少量的信息描述数据,这类数据称之为元数据,描述数据的数据。关于注解的理解,这里有个传送门:http://www.importnew.com/10294.html

下面的案例是在springBoot中进行的,直观地感受一下如何使用注解完成AOP。

@Service
public class UserService { public void getUser() {
//To do something
System.out.println("getUser() has been called");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

切面是这样定义的:


@Component
@Aspect
public class LoggerAspect {
/**
* getUser()执行之前执行
*/
@Before("execution(* com.springboot.demo.service.UserService.getUser(..))")
public void callBefore() {
System.out.println("before call method");
System.out.println("begin........................");
} /**
* getUser()执行之后执行
*/
@After("execution(* com.springboot.demo.service.UserService.getUser(..))")
public void callAfter() {
System.out.println("after call method");
System.out.println("end..............................");
}
}

来个单元测试验证一下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest { @Autowired
private UserService userService; @Test
public void getUserTest() {
userService.getUser();
}
}

具体案例

假如有以下的业务场景: UserService业务类中有个getUser()这个方法,现在想统计一下这个方法的执行时间,可能需要测试这个接口的性能。通常做法是方法开始时获取系统当前时间,然后方法结束时获取当前时间,最后 excuteTime=endTime-startTime。

如果现在不仅是这个方法需要统计,还有getUserByName()、getUserById()需要统计,上述的方法明显很笨了。

使用AOP怎么解决? 抽取公共部分为一个切面,方法执行前记录时间,然后执行目标方法,最后,目标方法执行完成之后再获取一次系统时间。

具体实现如下:在LoggerAspect中再写一个方法,记录getUser()方法的执行时间。


/**
* 记录执行时间
* @param point 切点
* @return
* @throws Throwable
*/
@Around("execution(* com.springboot.demo.service.UserService.getUser(..))")
public Object getMethodExecuteTime(ProceedingJoinPoint point) throws Throwable {
System.out.println("---------------getMethodExecuteTime------------------");
long startTime = System.currentTimeMillis();
//调用目标方法
Object result = point.proceed();
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
System.out.println("executeTime=" + executeTime + "------------------"); return result;
}

@Around将目标方法再次封装,控制了它的调用时机,以此来记录getUser()的执行时间。但是好像并没有达到记录UserService中的多个方法的执行时间的目的。

@Around("execution(* com.springboot.demo.service.UserService.getUser(..))")

其中指定了切点是getUser()这个方法,这里的表达式很丰富,可以设置为:

* com.springboot.demo.service.UserService.*(..)

表示UserService中的每一个方法都是切点,甚至可以是这样:

* com.springboot.demo.service..(..)

表示service包下的所有类的所有方法都是切点,但是这样很明显不够灵活,如果能自定义地控制就更好了。

自定义一个注解

如果用一个注解标注某个方法需要记录其执行时间,岂不是更加优雅。

/**
* @Description 标注某个方法需要记录执行时间
* @Author YaoQi
* @Date 2018/7/6 15:51
*/ @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented public @interface Logger {
String value() default "";
}

注解是用来描述数据的,上面的这个注解的意思是:这个注解将作用于方法,并且在运行时有效。但是这样只是标注了,如何读取这个标注的信息?

在LoggerAspect中加入这一个方法:


/**
* @param point
* @return
* @throws Throwable
*/
@Around("@annotation(com.springboot.demo.annotation.Logger)")
public Object getMethodExecuteTimeForLogger(ProceedingJoinPoint point) throws Throwable {
System.out.println("---------------getMethodExecuteTime------------------");
long startTime = System.currentTimeMillis();
Object result = point.proceed();
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
System.out.println("executeTime=" + executeTime + "------------------"); return result;
}

哪个方法需要记录执行时间就将@Logger放在对应的方法上:

    @Logger
public void getUser() {
System.out.println("getUser() has been called");
}

spring中基于注解使用AOP的更多相关文章

  1. Spring中基于xml的AOP

    1.Aop 全程是Aspect Oriented Programming 即面向切面编程,通过预编译方式和运行期动态代理实现程序功能的同一维护的一种技术.Aop是oop的延续,是软件开发中的 一个热点 ...

  2. Spring AspectJ基于注解的AOP实现

    对于AOP这种编程思想,很多框架都进行了实现.Spring就是其中之一,可以完成面向切面编程.然而,AspectJ也实现了AOP的功能,且实现方式更为简捷,使用更加方便,而且还支持注解式开发.所以,S ...

  3. spring中基于注解使用ehcache

    继续上篇,这篇介绍服务层缓存,基于注解的方式使用ehcache 注解的标签主要有4个:@Cacheable.@CacheEvict.@CachePut.@Caching,他们的用法是: @Cachea ...

  4. Spring中基于注解的IOC(二):案例与总结

    2.Spring的IOC案例 创建maven项目 导入依赖 pom.xml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ...

  5. Spring中基于注解的IOC(一):基础介绍

    1. Spring中的常用注解 注解配置和xml配置要实现的功能都是一样的,都要降低程序的耦合,只是配置的形式不一样 xml中配置示例: 注解分类: 1.用于创建对象的注解 它们的作用就和在xml中编 ...

  6. Spring中基于注解方式管理bean

    操作步骤 第一步:导入相关jar包 spring IoC的基本包 Spring支持注解的Jar包 第二步:创建Spring配置文件,ApplicationContext.xml 引入约束和开启注解扫描 ...

  7. Spring 中基于 AOP 的 @AspectJ

    Spring 中基于 AOP 的 @AspectJ @AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格. 通过在你的基于架构的 XML ...

  8. Spring 中基于 AOP 的 XML架构

    Spring 中基于 AOP 的 XML架构 为了使用 aop 命名空间标签,你需要导入 spring-aop j架构,如下所述: <?xml version="1.0" e ...

  9. Spring_Spring与AOP_AspectJ基于注解的AOP实现

    一.AspectJ.Spring与AOP的关系 AspectJ是一个面向切面的框架,它扩展了Java语言.AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Cl ...

随机推荐

  1. [ SSH框架 ] Spring框架学习之三(AOP开发和注解的使用)

    一.Spring 使用 AspectJ 进行 AOP 的开发:注解的方式 1.1 引入相关的jar包 1.2 引入spring的配置文件 <?xml version="1.0" ...

  2. eclipse 创建maven 项目 动态web工程完整示例 maven 整合springmvc整合mybatis

    接上一篇: eclipse 创建maven 项目 动态web工程完整示例 eclipse maven工程自动添加依赖设置 maven工程可以在线搜索依赖的jar包,还是非常方便的 但是有的时候可能还需 ...

  3. Linux find常用用法示例

    在此处只给出find的基本用法示例,都是平时我个人非常常用的搜索功能.如果有不理解的部分,则看后面的find运行机制详解对于理论的说明,也建议在看完这些基本示例后阅读一遍理论说明,它是本人翻译自fin ...

  4. 《CLR via C#》读书笔记(一)——CLR的执行模式

    前言 万事开头难,很早之前就想写博客记录些东西,迟迟未行动,甚是遗憾.原因诸多,大体上无非都是懒.没意志力等等.这次从自己的读书笔记开始,兴许能够有所改变. 一.CLR概念 CLR(Common La ...

  5. (摘)sql-索引的作用(超详细)

    (一)深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonc ...

  6. Docker安装nginx

    直切正题: 一.安装nginx docker pull nginx 二.启动nginx容器 docker run --name mynginx -d -p : nginx 命令说明: -p 80:80 ...

  7. 测试一波SpringBoot的HTTP吞吐量

    本来,其实就我个人而言现在很少去弄性能这一块的阵地了,主要在做设计与架构,不过前几天刚刚关注公众号的罗哥给我抛了关于性能方面的问题. 一个问题立马引起了我的兴趣,太久没弄性能方面的事情了,所以在隔天有 ...

  8. Js与jQuery的相互转换

    $()与jQuery() jQuery中$函数,根据传入参数的不同,进行不同的调用,实现不同的功能.返回的是jQuery对象 jQuery这个js库,除了$之外,还提供了另外一个函数:jQuery j ...

  9. Html和Css学习笔记-html进阶-html5属性

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 此篇博客是我的复习笔记,html和css学的时间太久了,忘得差不多了,最近要使用一下,所以重新打开html的书略读,后记录了标签 ...

  10. 0.react学习笔记-环境搭建与脚手架

    0.环境搭建 笔者使用的是deepin/mac两种系统,因为两个电脑经常切换用.环境搭建没什么区别. 0.1 node安装 按照node官网叙述安装 # Using Debian, as root c ...