Spring的AOP開發簡單示例

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章