爱游戏全站app官网入口-爱游戏官网

spring中基于注解使用aop -爱游戏全站app官网入口

2023-08-21,,

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


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

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

不得不说注解是个很巧妙的设计,使用很少量的信息描述数据,这类数据称之为元数据,描述数据的数据。关于注解的理解,这里有个传送门: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的相关教程结束。

网站地图