1.引入pom依赖
主要是spring-boot-starter-aop
依赖—>里面有需要的切面注解等配置
< ! -- 引入springboot父工程依赖-- >
< ! -- 引入依赖作用:
可以省去version标签来获得一些合理的默认配置
-- >
< parent>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- parent< / artifactId>
< version> 2.3 .2 . RELEASE< / version>
< / parent>
< dependencies>
< ! -- 引入提供Web 开发场景依赖-- >
< dependency>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- web< / artifactId>
< / dependency>
< ! -- 引入面向切面依赖-- >
< dependency>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- aop< / artifactId>
< / dependency>
< / dependencies>
2.切入点表达式
——组成
关键字(访问修饰符 返回值 包名.类名.方法名(参数)异常名) 示例:execution(public String com.it.Controller.findById(int))
组成部分 解释 关键字
描述表达式的匹配模式(参看关键字列表) 访问修饰符
方法的访问控制权限修饰符 类名
方法所在的类(此处可以配置接口名称) 异常
方法定义中指定抛出的异常
——逻辑运算符
运算符 解释 &&
连接两个切入点表达式,表示两个切入点表达式同时成立的匹配 ||
连接两个切入点表达式,表示两个切入点表达式成立任意一个的匹配 !
连接单个切入点表达式,表示该切入点表达式不成立的匹配
——通配符
*示例:execution(public * com.it.*.UserService.find*(*))
*解释:匹配com.it包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法
通配符 解释 *
单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现
实例: execution(public User com..UserService.findById(..))
解释: 匹配com包下的任意包中的UserService类或接口中所有名称为findById并且返回是User实体的方法
通配符 解释 ..
多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写
示例: execution(* *..*Service+.*(..))
解释:匹配Service其子类方法
——范例
execution(* *(…)) execution(* … (…)) execution(* … .*(…)) execution(public * … .*(…)) execution(public int … .*(…)) execution(public void … .*(…)) execution(public void com…. (…)) execution(public void com…service.. (…)) execution(public void com.it.service.. (…)) execution(public void com.it.service.User*.*(…)) execution(public void com.it.service.Service. (…)) execution(public void com.it.service.UserService.*(…)) execution(public User com.it.service.UserService.find*(…)) execution(public User com.it.service.UserService.*Id(…)) execution(public User com.it.service.UserService.findById(…)) execution(public User com.it.service.UserService.findById(int)) execution(public User com.it.service.UserService.findById(int,int)) execution(public User com.it.service.UserService.findById(int,*)) execution(public User com.it.service.UserService.findById(*,int)) execution(public User com.it.service.UserService.findById()) execution(List com.it.service.*Service+.findAll(…))
3. 启动类配置
只需要注意下 其它的类都要在启动类同包或及下层目录即可 让@SpringBootApplication中@ComponentScan扫描到; 如果类不在同级目录或下层目录 可以用@Import(Xxx.class)引入;
import org. springframework. boot. SpringApplication ;
import org. springframework. boot. autoconfigure. SpringBootApplication ;
@SpringBootApplication
public class AOPTestApplication {
public static void main ( String [ ] args) {
SpringApplication . run ( AOPTestApplication . class , args) ;
}
}
4.通知类型
4.1 @Before : 标注当前方法作为前置通知
前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行 应 用:数据校验
4.1.1 创建自定义注解(用于使用注解作为切入点)
创建出名为BeforeDS
注解 作为后面的 before AOP切入点;
import java. lang. annotation. Retention ;
import java. lang. annotation. RetentionPolicy ;
@Retention ( RetentionPolicy . RUNTIME)
public @interface BeforeDS {
public String value ( ) default "Before_Value" ;
}
4.1.2 设置切面类以及Before切面方法
@Before("@annotation(com.it.mhh.anno.BeforeDS)") @Before:标注当前方法作为前置通知 @annotation:指定用注解进行切面 com.it.mhh.anno.BeforeDS:注解的全路径名
JoinPoint: 主要是获取切入点方法相应数据 getSignature()): 是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名 joinPoint.getArgs() :这里返回的是切入点方法的参数列表这里返回的是切入点方法的参数列表 (MethodSignature) joinPoint.getSignature().getMethod().getAnnotation(BeforeDS.class) :获取切入点方法上的@BeforeDS注解 …
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. anno. BeforeDS ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. aspectj. lang. annotation. * ;
import org. aspectj. lang. reflect. MethodSignature ;
import org. springframework. core. annotation. Order ;
import org. springframework. stereotype. Component ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
import java. util. List ;
@Component
@Aspect
@Order ( 0 )
public class SwitchDSAspect {
@Before ( "@annotation(com.it.mhh.anno.BeforeDS)" )
public void before ( JoinPoint joinPoint) throws Throwable {
Signature pointSignature = joinPoint. getSignature ( ) ;
System . err. println ( "切入点方法的修饰符+ 包名+组件名(类名) +方法名-->:" + pointSignature) ;
Object [ ] args = joinPoint. getArgs ( ) ;
System . err. println ( "切入点方法的参数列表-->:" + Arrays . toString ( args) ) ;
MethodSignature signature = ( MethodSignature ) joinPoint. getSignature ( ) ;
Method method = signature. getMethod ( ) ;
BeforeDS beforeDS = method. getAnnotation ( BeforeDS . class ) ;
String value = beforeDS. value ( ) ;
System . err. println ( "切面类中before方法--自定义注解BeforeDS中的值为-->:" + value) ;
}
}
4.1.3 @Before : 标注当前方法作为前置通知测试
4.1.3.1 Controller层
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. web. bind. annotation. PathVariable ;
import org. springframework. web. bind. annotation. PostMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "AOPtest" )
public class AOPTestController {
@Value ( "#{AOPTestServiceImpl}" )
private AOPTestService aopTestService;
@RequestMapping ( "before" )
public String beforeTest ( ) {
System . out. println ( "before测试-controller" ) ;
return aopTestService. beforeTest ( ) ;
}
}
4.1.3.2 service层
public interface AOPTestService {
String beforeTest ( ) ;
}
4.1.3.3 serviceimpl层
import com. it. mhh. anno. BeforeDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. stereotype. Service ;
@Service
public class AOPTestServiceImpl implements AOPTestService {
@BeforeDS
@Override
public String beforeTest ( ) {
System . out. println ( "before测试-serviceimpl层" ) ;
return "before测试end" ;
}
}
@Before标注当前方法作为前置通知测试结果:
首先可以看出先走了controller层并打印了日志,我在serviceimp层的方法上加入了自定义注解, 此注解作为切入点那么就会走设置的切入点方法,执行完切入点方法后执行后面代码; 此方法没有入参 所以参数列表为空; BeforeDS注解没有设置值,所以是默认值
4.2 @After : 标注当前方法作为后置通知
后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知 应 用:现场清理
4.2.1 创建自定义注解(用于使用注解作为切入点)
创建出名为AfterDS
注解 作为后面的 after AOP切入点;
import java. lang. annotation. Retention ;
import java. lang. annotation. RetentionPolicy ;
@Retention ( RetentionPolicy . RUNTIME)
public @interface AfterDS {
public String value ( ) default "After_Value" ;
}
4.2.2 设置切面类以及After切面方法
@After("@annotation(afterDS)") @After:标注当前方法作为后置通知 @annotation:指定用注解进行切面 afterDS:切面方法上的入参注解名
JoinPoint: 主要是获取切入点方法相应数据 getSignature()): 是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名 joinPoint.getArgs() :这里返回的是切入点方法的参数列表这里返回的是切入点方法的参数列表 …
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. anno. BeforeDS ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. aspectj. lang. annotation. * ;
import org. aspectj. lang. reflect. MethodSignature ;
import org. springframework. core. annotation. Order ;
import org. springframework. stereotype. Component ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
import java. util. List ;
@Component
@Aspect
@Order ( 0 )
public class SwitchDSAspect {
@After ( "@annotation(afterDS)" )
public void after ( JoinPoint joinPoint, AfterDS afterDS) {
Signature pointSignature = joinPoint. getSignature ( ) ;
System . err. println ( "切入点方法的修饰符+ 包名+组件名(类名) +方法名-->:" + pointSignature) ;
Object [ ] args = joinPoint. getArgs ( ) ;
System . err. println ( "切入点方法的参数列表-->:" + Arrays . toString ( args) ) ;
String value = afterDS. value ( ) ;
System . err. println ( "切面类中after方法--自定义注解中的值为->" + value) ;
}
}
4.2.3 @After : 标注当前方法作为后置通知测试
4.2.3.1 Controller层
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. web. bind. annotation. PathVariable ;
import org. springframework. web. bind. annotation. PostMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "AOPtest" )
public class AOPTestController {
@Value ( "#{AOPTestServiceImpl}" )
private AOPTestService aopTestService;
@AfterDS ( "afterController" )
@PostMapping ( "after/{name}" )
public String afterTest ( @PathVariable ( "name" ) String name) {
System . out. println ( "after测试-controller" ) ;
return aopTestService. afterTest ( name) ;
}
}
4.2.3.2 service层
public interface AOPTestService {
String afterTest ( String name) ;
}
4.2.3.3 serviceimpl层
import com. it. mhh. anno. BeforeDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. stereotype. Service ;
@Service
public class AOPTestServiceImpl implements AOPTestService {
@Override
public String afterTest ( String name) {
System . out. println ( "after测试-serviceimpl层" ) ;
return "afterTest测试end--入参姓名-->:" + name;
}
}
@After : 标注当前方法作为后置通知 测试结果:
首先可以看出在controller层的方法上加入了自定义注解@AfterDS(afterController),然后代码走了controller层并打印了日志,也走完了serviceimp层的方法以及打印了日志, 之后执行了切入点方法的代码; 此方法有一个入参 所以参数列表中有一个值; @AlterDS()设置了value值 所以打印的就是设置的值
4.3 @Around: 标注当前方法作为环绕通知
环绕通知:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行 应 用:十分强大,可以做任何事情
4.3.1 设置切面类以及@Around切面方法
@Around(“pointCut()”)------>@Pointcut(value = “execution(public String com.it.mhh.service.impl.AOPTestServiceImpl.pointCutTest())”) @Around:标注当前方法作为环绕通知 pointCut():自定义的方法,此方法上有一个注解 @Pointcut() @Pointcut():此注解的value值为切入点表达式
JoinPoint: 主要是获取切入点方法相应数据 getSignature()): 是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名 joinPoint.getArgs() :这里返回的是切入点方法的参数列表这里返回的是切入点方法的参数列表 ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotations():获取切入点方法上的所有注解 …
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. anno. BeforeDS ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. aspectj. lang. annotation. * ;
import org. aspectj. lang. reflect. MethodSignature ;
import org. springframework. core. annotation. Order ;
import org. springframework. stereotype. Component ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
import java. util. List ;
@Component
@Aspect
@Order ( 0 )
public class SwitchDSAspect {
@Pointcut ( value = "execution(public String com.it.mhh.service.impl.AOPTestServiceImpl.pointCutTest())" )
public void pointCut ( ) {
}
@Around ( "pointCut()" )
public Object around ( ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint. getSignature ( ) ;
String targetClass = signature. getDeclaringTypeName ( ) ;
String targetMethod = signature. getName ( ) ;
long beginTime = System . currentTimeMillis ( ) ;
System . err. println ( "环绕通知在此方法之前执行的代码" ) ;
Object ret = joinPoint. proceed ( joinPoint. getArgs ( ) ) ;
System . err. println ( "环绕通知在此方法之后执行的代码" ) ;
long endTime = System . currentTimeMillis ( ) ;
System . err. println ( targetClass + " 中 " + targetMethod + " 运行时长 " + ( endTime - beginTime) + "ms" ) ;
Method method = ( ( MethodSignature ) joinPoint. getSignature ( ) ) . getMethod ( ) ;
Annotation [ ] annotations = method. getAnnotations ( ) ;
System . err. println ( "此方法上的所以注解:" + Arrays . toString ( annotations) ) ;
System . err. println ( "真实反参--》" + ret) ;
return ret+ "--》:通过环绕通知修改的参数" ;
}
}
4.3.2 @Around : 标注当前方法作为环绕通知测试
4.3.2.1 Controller层
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. web. bind. annotation. PathVariable ;
import org. springframework. web. bind. annotation. PostMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "AOPtest" )
public class AOPTestController {
@Value ( "#{AOPTestServiceImpl}" )
private AOPTestService aopTestService;
@PostMapping ( "pointCut" )
public String pointCutTest ( ) {
System . out. println ( "pointCutTest测试-controller" ) ;
return aopTestService. pointCutTest ( ) ;
}
}
4.3.2.2 service层
public interface AOPTestService {
String pointCutTest ( ) ;
}
4.3.2.3 serviceimpl层
import com. it. mhh. anno. BeforeDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. stereotype. Service ;
@Service
public class AOPTestServiceImpl implements AOPTestService {
@Override
@Order
public String pointCutTest ( ) {
System . out. println ( "pointCutTest测试-serviceimpl层" ) ;
return "pointCutTest测试end" ;
}
}
@Around : 标注当前方法作为环绕通知 测试结果:
@Around环绕通知可以修改返回参数
切入点为AOPTestServiceImpl类pointCutTest()方法 所以首先走了controller并打印日志 然后到了pointCutTest()方法 在此方法之前走了环绕通知方法的joinPoint.proceed(joinPoint.getArgs())代码之前的编码,然后接着走AOPTestServiceImpl类pointCutTest()方法里的代码,走完后会回到环绕通知的代码并执行完后返回结束; method.getAnnotations():这里 好像发现获取方法上的注解 获取不到@Override
4.4 @AfterReturning: 标注当前方法作为返回后通知
返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行 应 用:返回值相关数据处理
4.4.1 设置切面类以及@AfterReturning切面方法
@AfterReturning(value = “execution(public String com.it.mhh.service.impl.AOPTestServiceImpl.afterReturningTest(int ,int ))”, returning = “result”) @AfterReturning:标注当前方法作为返回后通知 execution:切入点表达式—匹配执行指定方法 returning:设定使用通知方法参数接收返回值的变量名
JoinPoint: 主要是获取切入点方法相应数据 getSignature()): 是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名 joinPoint.getArgs() :这里返回的是切入点方法的参数列表这里返回的是切入点方法的参数列表 ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotations():获取切入点方法上的所有注解 …
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. anno. BeforeDS ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. aspectj. lang. annotation. * ;
import org. aspectj. lang. reflect. MethodSignature ;
import org. springframework. core. annotation. Order ;
import org. springframework. stereotype. Component ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
import java. util. List ;
@Component
@Aspect
@Order ( 0 )
public class SwitchDSAspect {
@AfterReturning ( value = "execution(public String com.it.mhh.service.impl.AOPTestServiceImpl.afterReturningTest(int ,int ))" , returning = "result" )
public void afterReturning ( JoinPoint joinPoint, Object result) {
Signature pointSignature = joinPoint. getSignature ( ) ;
System . err. println ( "切入点方法的修饰符+ 包名+组件名(类名) +方法名-->:" + pointSignature) ;
Object [ ] args = joinPoint. getArgs ( ) ;
System . err. println ( "切入点方法的参数列表-->:" + Arrays . toString ( args) ) ;
System . err. println ( "切入点返回参-->:" + result) ;
}
}
4.4.2 @AfterReturning: 标注当前方法作为返回后通知测试
4.4.2.1 Controller层
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. web. bind. annotation. PathVariable ;
import org. springframework. web. bind. annotation. PostMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "AOPtest" )
public class AOPTestController {
@Value ( "#{AOPTestServiceImpl}" )
private AOPTestService aopTestService;
@PostMapping ( "afterReturning/{i1}/{i2}" )
public String afterReturningTest ( @PathVariable ( "i1" ) int i1, @PathVariable ( "i2" ) int i2) {
System . out. println ( "afterReturningTest测试-controller" ) ;
return aopTestService. afterReturningTest ( i1, i2) ;
}
}
4.4.2.2 service层
public interface AOPTestService {
String afterReturningTest ( int i1, int i2) ;
}
4.4.2.3 serviceimpl层
import com. it. mhh. anno. BeforeDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. stereotype. Service ;
@Service
public class AOPTestServiceImpl implements AOPTestService {
@Override
public String afterReturningTest ( int i1, int i2) {
System . out. println ( "afterReturningTest测试-serviceimpl层" ) ;
return "afterReturningTest测试end--->int总和:" + ( i1 + i2) ;
}
}
@AfterReturning : 标注当前方法作为返回后通知 测试结果:
原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行 切入点为AOPTestServiceImpl类afterReturningTest(int ,int )方法
4.5 @AfterThrowing: 标注当前方法作为抛出异常后通知
抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行 应 用:对原始方法中出现的异常信息进行处理
4.5.1 设置切面类以及@AfterThrowing切面方法
@AfterThrowing(value = “execution(public String com.it.mhh.service.impl.AOPTestServiceImpl.afterThrowingTest(String))”, throwing = “e”) @AfterThrowing:标注当前方法作为抛出异常后通知 execution:切入点表达式—匹配执行指定方法 throwing:设定使用通知方法参数接收原始方法中抛出的异常对象名
JoinPoint: 主要是获取切入点方法相应数据 getSignature()): 是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名 joinPoint.getArgs() :这里返回的是切入点方法的参数列表这里返回的是切入点方法的参数列表 ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotations():获取切入点方法上的所有注解 …
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. anno. BeforeDS ;
import org. aspectj. lang. JoinPoint ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. Signature ;
import org. aspectj. lang. annotation. * ;
import org. aspectj. lang. reflect. MethodSignature ;
import org. springframework. core. annotation. Order ;
import org. springframework. stereotype. Component ;
import java. lang. reflect. Method ;
import java. util. Arrays ;
import java. util. List ;
@Component
@Aspect
@Order ( 0 )
public class SwitchDSAspect {
@AfterThrowing ( value = "execution(public String com.it.mhh.service.impl.AOPTestServiceImpl.afterThrowingTest(String))" , throwing = "e" )
public void afterThrowing ( JoinPoint joinPoint, Exception e) {
Signature pointSignature = joinPoint. getSignature ( ) ;
System . err. println ( "切入点方法的修饰符+ 包名+组件名(类名) +方法名-->:" + pointSignature) ;
Object [ ] args = joinPoint. getArgs ( ) ;
System . err. println ( "切入点方法的参数列表-->:" + Arrays . toString ( args) ) ;
System . err. println ( "切入点异常-->:" + e) ;
}
}
4.5.2 @AfterThrowing: 标注当前方法作为异常后通知测试
4.5.2.1 Controller层
import com. it. mhh. anno. AfterDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. web. bind. annotation. PathVariable ;
import org. springframework. web. bind. annotation. PostMapping ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
@RestController
@RequestMapping ( "AOPtest" )
public class AOPTestController {
@Value ( "#{AOPTestServiceImpl}" )
private AOPTestService aopTestService;
@PostMapping ( "afterThrowing/{string}" )
public String afterThrowingTest ( @PathVariable ( "string" ) String string) {
System . out. println ( "afterThrowingTest测试-controller" ) ;
return aopTestService. afterThrowingTest ( string) ;
}
}
4.5.2.2 service层
public interface AOPTestService {
String afterThrowingTest ( String string) ;
}
4.5.2.3 serviceimpl层
import com. it. mhh. anno. BeforeDS ;
import com. it. mhh. service. AOPTestService ;
import org. springframework. stereotype. Service ;
@Service
public class AOPTestServiceImpl implements AOPTestService {
@Override
public String afterThrowingTest ( String string) {
System . out. println ( "afterThrowingTest测试-serviceimpl层" ) ;
int i = 1 / 0 ;
return "afterThrowingTest测试end--->String值:" + string;
}
}
@AfterThrowing: 标注当前方法作为异常后通知 测试结果:
抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行 切入点为AOPTestServiceImpl类afterThrowingTest(String)方法