切面编程开发
1 引入对应的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2 定义切面
定义一个java类
@Aspect 切面注解
@Component 定义为一个组件,不然spring找不到
@Pointcut 定义一个切点,只要是这个切点的所有方法都会执行这个切面方法,定义了切点就得定义一个切点方法
如
/** 定义一个切点 */
@Pointcut("execution(public * com.sc.*.controller..*Controller.*(..))") 只要是在这个路径下的方法都会调用者切面
* 代表任一路径 ..代表有0或多个路径 *Controller 代表任何以Controller结尾的类 *(..))代表任意方法
public void pointcut(){
}
//pointcut() 自定义的一个切点方法,和pointcut一起使用,这个方法不会执行,只提供给其他方法绑定
@Before 前置通知
@After后置通知
@AfterReturning 运行通知
@AfterThrowing 异常通知
@Around 环绕通知,必须带上返回值,不然返回的值是空
package com.sc.service.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class TestAnnotation {
@Pointcut("execution(public * com.sc.*.controller..*Controller.*(..))")
public void pointcut(){
}
//前置通知 ..表示0-多个文件
@Before("pointcut()")
public void begin() {
System.out.println("前置通知");
}
// // 后置通知
@After("pointcut()")
public void commit() {
System.out.println("后置通知");
}
//
// // 运行通知
@AfterReturning("pointcut()")
public void returning() {
System.out.println("运行通知");
}
//
// // 异常通知
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("异常通知");
}
//
// 环绕通知 必须带上返回值,不然原来的返回会给替换
@Around("execution(* com.sc.*.controller..*Controller.*(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知开始");
Object object = proceedingJoinPoint.proceed();
System.out.println("环绕通知结束");
return object;
}
}
自定义注解实现切面
1 定义一个自定义注解可以带参数也可以不带参数
package com.sc.service.annotation;
import java.lang.annotation.*;
/**
* @author lenovo
*/
@Retention(RetentionPolicy.RUNTIME) 记录在生命周期
@Target({ElementType.TYPE,ElementType.METHOD}) 记录注解可以用于什么类型 type是任意类型 METHOD是方法类型
@Documented 没搞懂这个什么用
public @interface logAnnotation {
}
2 定义一个切面
package com.sc.service.config;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Before;
@Aspect
@Component
public class TestAnnotation {
@Pointcut("@annotation(com.sc.service.annotation.logAnnotation)") 这里定义的方式和上面不同注意
public void pointcut(){
}
//前置通知 ..表示0-多个文件
@Before("pointcut()")
public void begin() {
System.out.println("前置通知");
}
// // 后置通知
@After("pointcut()")
public void commit() {
System.out.println("后置通知");
}
//
// // 运行通知
@AfterReturning("pointcut()")
public void returning() {
System.out.println("运行通知");
}
//
// // 异常通知
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("异常通知");
}
//
// 环绕通知 必须带上返回值,不然原来的返回会给替换
@Around("execution(* com.sc.*.controller..*Controller.*(..))")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知开始");
Object object = proceedingJoinPoint.proceed();
System.out.println("环绕通知结束");
return object;
}
}
3 使用注解
在方法上加入注解,就可以自动实现aop
package com.sc.business.controller.business;
import com.sc.service.annotation.logAnnotation;
import com.sc.service.dto.ChapterDto;
import com.sc.service.dto.PageDto;
import com.sc.service.dto.ResponseDto;
import com.sc.service.service.ChapterService;
import com.sc.service.util.ValidatorUtil;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RequestMapping("/chapter")
@RestController
public class BusinessController {
@Resource
private ChapterService chapterService;
@RequestMapping("/test") 这个方法没加,这个则不会调用aop
public String test(){
return "抱抱,想你了,宝宝mua";
}
@RequestMapping("/getList")
@logAnnotation 这里加上了注解,这个方法会调用aop
public ResponseDto getChapterList(@RequestBody PageDto pageDto){
ResponseDto responseDto = new ResponseDto();
chapterService.getChapterList(pageDto);
responseDto.setContent(pageDto);
return responseDto;
}
}