SpringAOP支持方法级别的增强。
大致有
@Before:方法执行前执行
@After:方法执行后还没有返回时执行
@Around:环绕通知,在Before之前,在After之前。
@AfterReturning:方法返回结果之后执行
@AfterThrowing:返回异常时执行
@ @DeclareParents:给类增加接口
假设 增强service包下的所有方法 :
目录结构 :
切面类:
package com.fuyouj.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @Desc
* @Author FuYouJ
* @date 2020/5/30 22:27
*/
@Aspect
@Component
public class ServiceAspect {
//定义需要切割的地方,下面的表达式的意思是 所有限制类型的 service 包下的所有类的所有方法(任意个数参数)
@Pointcut(value = "execution(* com.fuyouj.service..*.*(..))")
public void embed(){}
//方法执行前执行
@Before("embed()")
public void before(JoinPoint joinPoint){
System.out.println("开始调用"+joinPoint);
}
//执行完成还没有返回时执行
@After("embed()")
public void after(JoinPoint joinPoint){
System.out.println("调用完成"+joinPoint);
}
/**
* 通过环绕通知达到检测运行时的目的
* @param joinPoint
* @return
*/
@Around("embed()")
public Object around(JoinPoint joinPoint){
long start = System.currentTimeMillis();
//返回值
Object returnValue = null;
System.out.println("开始计时"+joinPoint);
ProceedingJoinPoint point = (ProceedingJoinPoint) joinPoint;
System.out.println("环绕完毕");
try {
returnValue = point.proceed();
} catch (Throwable throwable) {
System.out.println("执行失败,结束计时"+joinPoint);
throwable.printStackTrace();
}
finally {
long end = System.currentTimeMillis();
System.out.println("耗时"+(end - start));
}
return returnValue;
}
//方法返回结果之后执行
@AfterReturning(pointcut = "embed()",returning = "returnValue")
public void afterReturning(JoinPoint joinPoint,Object returnValue){
System.out.println("无论为空还是有值都会返回" + joinPoint + "返回值" + returnValue);
}
//返回异常时执行
@AfterThrowing(pointcut = "embed()",throwing = "exception")
public void afterThrowing(JoinPoint joinPoint,Exception exception){
System.out.println(joinPoint+"抛出了异常"+exception.getMessage());
}
/**
* 给类增加实现接口和接口的默认实现类
*/
@DeclareParents(value = "com.fuyouj.controller..*",defaultImpl = com.fuyouj.aspect.ParentImpl.class)
public Parent parent;
}
控制器里面调用service的方法
@Controller
public class HelloController {
@Autowired
private HelloService helloService;
public void handleRequest(){
helloService.sayHello();
helloService.justWantToThrowException();
}
}
@Controller
public class HiController {
@Autowired
private HiService hiService;
public void handleRequest(){
hiService.sayHi();
System.out.println(hiService.justWantToSayHi());
}
}
两个service
@Service
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hello everyOne");
}
@Override
public void justWantToThrowException() {
throw new RuntimeException("抛出一个hello Exception");
}
}
@Service
public class HiServiceImpl implements HiService {
@Override
public void sayHi() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Hi everyOne");
}
@Override
public String justWantToSayHi() {
return "justWantToSayHi";
}
}
定义增强控制器的接口
public interface Parent {
void parentMethod();
}
接口实现类
public class ParentImpl implements Parent {
@Override
public void parentMethod() {
System.out.println("额外增加的方法执行了");
}
}
不转换接口执行
@Configuration
@ComponentScan("com.fuyouj")
//识别AOP
@EnableAspectJAutoProxy
public class Entrance {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);
HelloController helloController = (HelloController) applicationContext.getBean("helloController");
// ((Parent)helloController).parentMethod();
helloController.handleRequest();
HiController hiController = (HiController) applicationContext.getBean("hiController");
hiController.handleRequest();
}
}
执行结果:
开始计时execution(void com.fuyouj.service.HelloService.sayHello())
环绕完毕
开始调用execution(void com.fuyouj.service.HelloService.sayHello())
Hello everyOne
耗时2001
调用完成execution(void com.fuyouj.service.HelloService.sayHello())
无论为空还是有值都会返回execution(void com.fuyouj.service.HelloService.sayHello())返回值null
开始计时execution(void com.fuyouj.service.HelloService.justWantToThrowException())
环绕完毕
开始调用execution(void com.fuyouj.service.HelloService.justWantToThrowException())
执行失败,结束计时execution(void com.fuyouj.service.HelloService.justWantToThrowException())
耗时1
调用完成execution(void com.fuyouj.service.HelloService.justWantToThrowException())
无论为空还是有值都会返回execution(void com.fuyouj.service.HelloService.justWantToThrowException())返回值null
开始计时execution(void com.fuyouj.service.HiService.sayHi())
环绕完毕
开始调用execution(void com.fuyouj.service.HiService.sayHi())
java.lang.RuntimeException: 抛出一个hello Exception
at com.fuyouj.service.impl.HelloServiceImpl.justWantToThrowException(HelloServiceImpl.java:25)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
at com.fuyouj.aspect.ServiceAspect.around(ServiceAspect.java:44)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:47)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:55)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:62)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy27.justWantToThrowException(Unknown Source)
at com.fuyouj.controller.HelloController.handleRequest(HelloController.java:18)
at com.fuyouj.controller.HelloController$$FastClassBySpringCGLIB$$71d20363.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor.doProceed(DelegatePerTargetObjectIntroductionInterceptor.java:119)
at org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor.invoke(DelegatePerTargetObjectIntroductionInterceptor.java:107)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
at com.fuyouj.controller.HelloController$$EnhancerBySpringCGLIB$$13848a28.handleRequest(<generated>)
at com.fuyouj.Entrance.main(Entrance.java:47)
Hi everyOne
耗时3001
调用完成execution(void com.fuyouj.service.HiService.sayHi())
无论为空还是有值都会返回execution(void com.fuyouj.service.HiService.sayHi())返回值null
开始计时execution(String com.fuyouj.service.HiService.justWantToSayHi())
环绕完毕
开始调用execution(String com.fuyouj.service.HiService.justWantToSayHi())
耗时0
调用完成execution(String com.fuyouj.service.HiService.justWantToSayHi())
无论为空还是有值都会返回execution(String com.fuyouj.service.HiService.justWantToSayHi())返回值justWantToSayHi
justWantToSayHi
Process finished with exit code 0
只测试给类增加接口
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Entrance.class);
HelloController helloController = (HelloController) applicationContext.getBean("helloController");
((Parent)helloController).parentMethod();
}
运行
Spring的对一个地方多个AOP执行顺序如下图:
满足文章开头说的顺序,其实如果记不住这个图,还有个更好的记忆方式。
想象成同心圆。
先开始的后结束,后开始的先结束。