AOP使用
AOP是什么?
AOP(Aspect Oriented Programming) ,意义:面向切面编程,实现横切逻辑的控制。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
AOP的变成思想就是把很多类对象中的横切问题点,从业务逻辑中分离出来,从而达到解耦的目的,增加代码重用性,提高开发效率。
产生的问题
很多类对象和Logger仍然存在依赖关系
甚至每个类中的所有方法都要调用Logger
如果修改了方法,需要修改N遍,不能一次修改完成改变
AOP应用场景
日志记录、权限验证、事务处理、效率检查、异常处理、数据持久化…
Spring AOP 中主要概念理解
切面(Aspect):在Spring AOP中,切面可以使用通用类或者在普通类中以@Aspect 注解(@AspectJ风格)来实现。相当于一个切面的载体
切入点(Pointcut):定义出一个或一组方法,当执行这些方法时可产生通知,Spring缺省使用AspectJ切入点语法。
连接点(Joinpoint):在Spring AOP中一个连接点代表一个方法的执行,程序执行的某个特定的位置,如某个方法调用前后等。
通知(Advice):在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括"around"、"before”和"after"等通知。增强到什么地方?什么内容?
通知类型
前置通知(@Before):在某连接点(join point)之前执行的通知,无论方法是否异常都会执行
返回后通知(@AfterReturning):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
抛出异常后通知(@AfterThrowing):只有方法抛出异常退出时执行的通知
后通知(@After):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)
环绕通知(@Around):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型,环绕通知可以在方法调用前后完成自定义的行为,它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。ProceedingJoinPoint参数 可以控制目标方法的执行
Spring Aop 的底层实现其实就是通过JDK动态代理或CGlib代理在运行时期在对象初始化阶段织入代码的
AOP实现步骤
1.定义一个切面类Aspect
即在声明的类,增加@Component @Aspect 两个注解,Springboot中要引入spring-boot-stater-aop依赖
package com.ganggu.aopdemo;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AopTest {
}
2.定义切点Pointcut
定义切点,并定义切点在哪些地方进行执行,采用@Pointcut注解完成,如@Pointcut(“execution public * com.xxx.xxx.*. *(…)”)
规则:修饰符(可以不写,但不能*)+返回类型+哪些包下的类+哪些方法+方法参数“ * ”代表不限。“ …”两个点代表参数不限
package com.ganggu.aopdemo;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AopTest {
Logger logger = LoggerFactory.getLogger(AopTest.class);
/**
* 切点
* 指定在哪些类下哪些方法进行增强
*/
@Pointcut("execution(* com.ganggu.aopdemo.controller.*.*(..))")
public void aopCut(){
}
}
3.定义Advice通知
利用通知的5种类型注解@Before 、 @After、@AfterReturning 、 @Afterthrowing 、 @Around来完成某些切点的增强动作,如@Around(“myPointcut()”),myPointcut()未定义第二步骤定义的切点
package com.ganggu.aopdemo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AopTest {
Logger logger = LoggerFactory.getLogger(AopTest.class);
/**
* 切点
* 表示所有controller下所有类所有方法不论参数个数都会被增强
* 被调用时根据定义的连接点进行处理(调用方法之前、之后、环绕、抛出异常等等通知类型)
*/
@Pointcut("execution(* com.ganggu.aopdemo.controller.*.*(..))")
public void aopCut(){
}
/**
* 连接点
* 环绕型通知可以再调用方法前后自定义行为
* @return
*/
@Around("aopCut()")
public Object aspect(ProceedingJoinPoint point) throws Throwable {
String ClassName = point.getTarget().getClass().toString();
String Method = point.getSignature().getName();
Object[] arr = point.getArgs();
ObjectMapper mapper = new ObjectMapper();
logger.info("方法调用前" + ClassName + "方法" + Method + "参数" + mapper.writeValueAsString(arr));
//调用方法
Object proceed = point.proceed();
logger.info("方法调用后返回值" + proceed);
return proceed;
}
/**
* 连接点 smartinput
* 调用方法之后执行
* @return
*/
@After("@annotation(com.ganggu.aopdemo.aop.AnnAop)")
public void aspect1(JoinPoint point) throws Throwable {
String ClassName = point.getTarget().getClass().toString();
String Method = point.getSignature().getName();
Object[] arr = point.getArgs();
ObjectMapper mapper = new ObjectMapper();
logger.info("方法调用后");
}
/**
* 连接点
* 调用方法之后抛出异常执行
* @return
*/
@AfterThrowing(throwing = "ex",pointcut = "@annotation(com.ganggu.aopdemo.aop.AnnAop)")
public void aspect2(JoinPoint point,Throwable ex) throws Throwable {
String Method = point.getSignature().getName();
logger.info("方法调用异常目标方法为"+Method+"异常为:"+ex);
}
}
AOP自定义注解方式
1.自定义Aop注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
比如
package com.ganggu.aopdemo.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnAop {
}
代码演示
/**
* 连接点 smartinput
* @return
*/
@After("@annotation(com.ganggu.aopdemo.aop.AnnAop)")
public void aspect1(JoinPoint point) throws Throwable {
String ClassName = point.getTarget().getClass().toString();
String Method = point.getSignature().getName();
Object[] arr = point.getArgs();
ObjectMapper mapper = new ObjectMapper();
logger.info("方法调用后");
}
Controller层
@AnnAop
@RequestMapping("/hello1")
public String Hello1(@RequestParam("name") String name,@RequestParam("age") int age){
System.out.println("licaifeng");
return "姓名"+name+"年龄"+age;
}
这样调用Controller中方法的时候就会被增强