springboot中如何面向切面编程?
一.什么是面向切面编程
面向切面编程(AOP):利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
简单点理解就是:不通过修改源代码方式,在主干功能里面添加新功能
AOP的底层使用的是动态代理方式;
二.AOP中的几个术语
1. 连接点
连接点指的是哪些方法可以被增强,这些方法称为连接点
2. 切入点
实际被真正增强的方法,称为切入点
3. 通知(增强)
实际增强的逻辑部分(扩展的功能)称为通知或增强
通知有多种类型
4. 切面
把通知应用到切入点的过程
5.切入点表达式
- 切入点表达式作用:
知道对哪个类里面的方法进行增强
- 语法结构
execution([权限修饰符] [返回类型] [类全路径] [方法名称][参数列表])
举例
-
对com.atguigu.dao.BookDao类里面的add进行增强
execution(* com.atguigu.dao.BookDao.add(…)) -
对com.atguigu.dao.BookDao类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…)) -
对com.atguigu.dao包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…))
权限修饰符可省略,
返回类型用通配符*代替
(…) 代表可变参数
三.如何使用
1.首先肯定是要引入相关依赖啦!!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.然后创建一个增强类
@Aspect
@Component
public class HttpAspect {
}
要加上@Aspect注解和@Component注解
3.之后就是写扩展的方法了
这里介绍几个常见的通知
- @Before 前置通知
在访问到目标方法(add)方法之前,先执行此方法;
在此方法中可以获取request对象,获取请求的URL,请求方法,ip,类方法,请求参数
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
//这里定义looger,为了后面使用日志进行记录
@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//获取request
HttpServletRequest request = attributes.getRequest();
//url
logger.info("url={}", request.getRequestURL());
//method
logger.info("method={}", request.getMethod());
//ip
logger.info("ip={}", request.getRemoteAddr());
//类方法
logger.info("class_method={}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
//参数
logger.info("args={}", joinPoint.getArgs());
}
注意:
如果要获取请求方法和参数,需要传入JoinPoint作为形参
- @After 后置通知(又称最终通知)
在访问目标方法结束之后,再执行此方法;
@After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void after() {
System.out.println("after.........");
}
- @AfterReturning 返回通知(后置通知)
在目标方法返回对象之后,此方法接收返回值;
@AfterReturning(returning = "object", pointcut = "log()")
public void doAfterReturning(Object object) {
logger.info("response={}", object.toString());
}
- @AfterThrowing 异常通知
在发生异常后执行
@AfterThrowing(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing.........");
}
- @PointCut 相同切入点的抽取
我们可以把相同的切入点抽取出来,减少重复代码的开发
//抽取切入点
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")
public void pointdemo() {
}
//前置通知
@Before(value = "pointdemo()")
public void before() {
System.out.println("before.........");
}