springBoot-aop
springBoot-aop
简介
AOP(Aspect OrientedProgramming):面向切面编程,面向切面编程(也叫面向方面编程),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
使用场景
利用AOP可以对我们边缘业务进行隔离,降低无关业务逻辑耦合性。提高程序的可重用性,同时提高了开发的效率。一般用于日志记录
,性能统计
,安全控制
,权限管理
,事务处理
,异常处理
,资源池管理
。使用场景
技术要点
- 通知(Advice):包含了需要用于多个应用对象的横切行为,完全听不懂,没关系,通俗一点说就是定义了“什么时候”和“做什么”。
- 连接点(Join Point):是程序执行过程中能够应用通知的所有点。
- 切点(Pointcut):是定义了在“什么地方”进行切入,哪些连接点会得到通知。显然,切点一定是连接点。
- 切面(Aspect):是通知和切点的结合。通知和切点共同定义了切面的全部内容——是什么,何时,何地完成功能。
- 引入(Introduction):允许我们向现有的类中添加新方法或者属性。
- 织入(Weaving):是把切面应用到目标对象并创建新的代理对象的过程,分为编译期织入、类加载期织入和运行期织入。
在springBoot中运用
- 导入依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
- 编写测试的TestController
@RestController
public class TestController {
@GetMapping("/test01")
public String test01(@RequestParam(value = "str")String str){
return str + "我是test01";
}
@GetMapping("/test02")
public String test02(){
int a = 10/0;
return "出异常了";
}
@Wlog(value = "test")
@PostMapping("/test03")
public String test03(){
return "test03";
}
}
- 定义切面
@Aspect //使用@Aspect注解表示这是一个切面类
@Component
public class LogAspect {
/**
* @Pointcut 定义切点
* 由于Spring切面粒度最小是达到方法级别,而execution表达式可以用于明确指定方法返回类型,类名,方法名和参数名等与方法相关的部件,并且实际中,
* 大部分需要使用AOP的业务场景也只需要达到方法级别即可,因而execution表达式的使用是最为广泛的。如下是execution表达式的语法
*/
@Pointcut("execution(public * com.cxf.controller.*.*(..))")
public void webLog(){}
//前置通知
@Before(value = "webLog()")
public void doBefore(JoinPoint joinPoint){
System.out.println("在方法执行前通知");
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
System.out.println("url:"+request.getRequestURL().toString());
System.out.println("requestMethod:"+request.getMethod());
System.out.println("content-Type:"+request.getContentType());
System.out.println("remoteHost:"+request.getRemoteHost());
System.out.println("args:"+ Arrays.toString(joinPoint.getArgs()));
}
//后置通知,相当于是finally的增强,不管是异常还是正常退出都会执行
@After(value = "webLog()")
public void doAfter(JoinPoint joinPoint){
System.out.println("在方法执行后");
}
//环绕通知,环绕增强,相当于MethodInterceptor
@Around("webLog()")
public Object arround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("方法环绕start.....");
try {
Object o = pjp.proceed();
System.out.println("方法环绕proceed,结果是 :" + o);
return o;
} catch (Throwable e) {
throw e;
}
}
//方法的返回值
@AfterReturning(returning = "ret",pointcut = "webLog()")
public void returnArgs(Object ret){
System.out.println("return:"+ret.toString());
}
//有异常时触发
@AfterThrowing(value = "webLog()")
public void afterThrow(JoinPoint joinPoint){
System.out.println("触发了异常");
}
}
- 测试结果
自定义注解
在日常开发中,有一些相同的功能,但是又不想编写重复的代码,此时自定义一个注解,并且赋予他功能,只需在需要使用到的地方加上这个注解就方便很多。
如何自定义注解
- 定义注解 -- 相当于定义标记
- 配置注解 -- 把标记打在需要用到的程序代码中
- 解析注解 -- 在编译期或运行时检测到标记,并运行特殊操作
基本语法
- 所有定义的注解都会自动继承java.lang.annotation,Annotation接口
- 关键字: @interface
定义注解类型元素
- 访问修饰符必须为public,不写默认为public
- 类型为基本数据类型、String、Class、枚举类型、注解类型、以及上述类型的一维数组
- 元素名称一般为名词,如果注解中只有一个元素,请命名为value(方便后续操作)
- ()内不放任何参数,只是特殊语法
- default为默认值
- 若没有默认值,则后续使用时必须赋值
元注解
- @Target 限制注解的使用范围 TYPE--类、FIELD--属性、METHOD--方法、PARAMETER--方法形式参数、LOCAL_VARIABLE--局部变量、ANNOTATION--注解类型、PACKAGE--包
- @Retention 用来修饰自定义注解的生命力 SOURCE--注解将被编译器忽略掉、CLASS--注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,
这是一个默认的行为、RUNTIME--注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到 - @Documented 是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中
- @Inherited 是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解。只对那些@Target被定义为ElementType.TYPE的自定义注解起作用。
示例
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Documented
public @interface Wlog {
String value() default "";
}
定义该注解切面
@Aspect
@Component
public class MyWlogAspect {
@Pointcut(value = "@annotation(com.cxf.annotation.Wlog)")
public void myMethod() {}
@Around(value = "@annotation(wlog)")
public Object aroundAdvice(ProceedingJoinPoint pjp, Wlog wlog){
System.out.println("获取注解属性的值:"+wlog.value());
try{
return pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
return null;
}
}
}
测试结果
本文来自博客园,作者:cxf0616,转载请注明原文链接:https://www.cnblogs.com/cxfbk/p/17203349.html
风起于青萍之末,浪成于微澜之间
每一份成功都源于每日的坚持