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執行順序如下圖:
滿足文章開頭說的順序,其實如果記不住這個圖,還有個更好的記憶方式。
想象成同心圓。
先開始的後結束,後開始的先結束。