首頁 > 軟體

淺談@Aspect@Order各個通知的執行順序

2022-02-14 13:00:05

@Aspect@Order各個通知的執行順序

兩個切面類:【記錄紀錄檔】和【判斷引數】,分別對應順序 @Order(0) 和@Order(1) 。

本文只是將重點說下 執行順序 這麼回事哈哈哈

程式碼

【業務類】

/**
 * 登入控制器
 */
@Controller
public class LoginController {
    //向外面丟擲異常
    public void loginWithThrow(String username, String password) throws Exception {
        if (username == null || password == null) {
            throw new Exception("登入資訊不可為空啊");
        }
        System.out.println("LoginController#login...");
    }
    //丟擲異常自己捕獲的情況
    public void loginWithTryCatch(String username, String password) {
       try{
           if (username == null || password == null) {
               throw new Exception("登入資訊不可為空啊");
           }
           System.out.println("LoginController#login...");
       }catch (Exception e){
           e.printStackTrace();
       }
    }
}

【切面類】

/**
 * 輸出紀錄檔註解
 */
@Order(0)
@Aspect
@Component
public class LogAspect {
    //抽出共通的execution用的
    //com.yuki.demo.aop.aspect 包或者子包下所有類的方法
    @Pointcut("execution(* com.yuki.demo.aop.aspect..*.*(..))")
    public void pointcut(){
    }
    //前置通知
//    @Before("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
    @Before("pointcut()")
    public void before() {
        System.out.println("LogAspect#before...");
    }
    //環繞通知
    //ProceedingJoinPoint 只有環繞通知有
    @Around("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("LogAspectA#around開始...");
        //代理方法的執行,如果沒有joinPoint.proceed() ,則前置通知@Before 不會執行,其它的通知正常
        joinPoint.proceed();
        //執行方法之後,如果joinPoint.proceed() 丟擲了異常,則該句不會執行,丟擲異常後直接跳出了aroud方法了
        System.out.println("LogAspectA#around結束...");
    }
    //後置通知(只要連線點被執行,不管是否丟擲異常)
    @After("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
    public void after() {
        System.out.println("LogAspect#after...");
    }
    //異常通知(只有在joinPoint.proceed()方法執行向外面丟擲了異常,才會執行該通知)
    @AfterThrowing("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
    public void afterThrowing() {
        System.out.println("LogAspect#afterThrowing...");
    }
    //正常的返回通知通知(正常結束了才會執行該通知)
    @AfterReturning("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
    public void afterReturning() {
        System.out.println("LogAspect#afterReturning...");
    }
}

【切面類】

/**
 * 判斷請求引數的sign是否正確的 切面類
 */
@Order(1)
@Aspect
@Component
public class SignAspect {
    @Around("execution(public void com.yuki.demo.aop.aspect.LoginController.*(String,String))")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("SignAspect#around開始...");
        joinPoint.proceed();
        System.out.println("SignAspect#around結束...");
    }
}

【啟動設定】

省略。。。非重點

【測試類】

@SpringBootTest
class AopApplicationTests {
    @Autowired
    private LoginController loginController;
    @Test
    void contextLoads() {
        loginController.loginWithTryCatch("yuki", "1234");
    }
}

【控制檯輸出】

LogAspectA#around開始...
LogAspect#before...
SignAspect#around開始...
LoginController#login...
SignAspect#around結束...
LogAspectA#around結束...
LogAspect#after...
LogAspect#afterReturning...

小結

spring AspectJ order(順序)

@Aspect
@Order(2)
public class HelloWorldAspectAnnotation {
	/**
	 * JoinPoint介面
	 * @param joinPoint
	 */
	/*public interface JoinPoint {
	    String toString();         //連線點所在位置的相關資訊
	    String toShortString();     //連線點所在位置的簡短相關資訊
	    String toLongString();     //連線點所在位置的全部相關資訊
	    Object getThis();         //返回AOP代理物件
	    Object getTarget();       //返回目標物件
	    Object[] getArgs();       //返回被通知方法參數列
	    Signature getSignature();  //返回當前連線點簽名
	    SourceLocation getSourceLocation();//返回連線點方法所在類檔案中的位置
	    String getKind();        //連線點型別
	    StaticPart getStaticPart(); //返回連線點靜態部分
	}*/	
	
    //定義前置通知,注意這裡是sayHello2
	//使用@Before進行前置通知宣告,其中value用於定義切入點表示式或參照命名切入點
	@Before(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param")
	public void beforeAdvice(JoinPoint joinPoint,String param) {
		System.out.println(1);
		System.out.println("=======================");
		System.out.println("===param:" + param);
		System.out.println("=======================");
		System.out.println(joinPoint.getArgs().length);
		System.out.println("=======================");
		System.out.println(joinPoint.toString());
		System.out.println("=======================");
		System.out.println(joinPoint.getTarget());
		System.out.println("=======================");
		System.out.println(joinPoint.getThis());
		System.out.println("=======================");
		System.out.println("===========before advice");
	}
	/*value:指定切入點表示式或命名切入點;
    pointcut:同樣是指定切入點表示式或命名切入點,如果指定了將覆蓋value屬性指定的,pointcut具有高優先順序;*/
	@AfterReturning(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param",pointcut="execution(* com.boventech..*.sayHello2(..))&& args(param)")
	public void afterFinallyAdvice(JoinPoint joinPoint,String param) {
		System.out.println("param:"+param);
		System.out.println("===========");
		System.out.println("===========after finally advice");
	}
}
@Aspect
@Order(1)
public class HelloWorldAspectAnnotation2 {
	/**
	 * JoinPoint介面
	 * @param joinPoint
	 */
	/*public interface JoinPoint {
	    String toString();         //連線點所在位置的相關資訊
	    String toShortString();     //連線點所在位置的簡短相關資訊
	    String toLongString();     //連線點所在位置的全部相關資訊
	    Object getThis();         //返回AOP代理物件
	    Object getTarget();       //返回目標物件
	    Object[] getArgs();       //返回被通知方法參數列
	    Signature getSignature();  //返回當前連線點簽名
	    SourceLocation getSourceLocation();//返回連線點方法所在類檔案中的位置
	    String getKind();        //連線點型別
	    StaticPart getStaticPart(); //返回連線點靜態部分
	}*/	
	
    //定義前置通知,注意這裡是sayHello2
	//使用@Before進行前置通知宣告,其中value用於定義切入點表示式或參照命名切入點
	@Before(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param")
	public void beforeAdvice(JoinPoint joinPoint,String param) {
		System.out.println(2);
		System.out.println("=======================");		
	}
	
	/*value:指定切入點表示式或命名切入點;
    pointcut:同樣是指定切入點表示式或命名切入點,如果指定了將覆蓋value屬性指定的,pointcut具有高優先順序;*/
	@AfterReturning(value="execution(* com.boventech..*.sayHello2(..))&& args(param)",argNames="param",pointcut="execution(* com.boventech..*.sayHello2(..))&& args(param)")
	public void afterFinallyAdvice(JoinPoint joinPoint,String param) {
		System.out.println("order:" + 2);
	}
}
public class AopAnnotationTest {	
	@Test
    public void testHelloworld() {
        ApplicationContext ctx =  new ClassPathXmlApplicationContext("/helloWorld2.xml");
        IHelloWorld2Service helloworldService =ctx.getBean("helloWorld2Service", IHelloWorld2Service.class);
        String param = "12";
        helloworldService.sayHello2(param);
    } 
}
<aop:aspectj-autoproxy/>
	<bean id="helloWorld2Service" class="com.boventech.learning.serviceImpl.HelloWorld2ServiceImpl"/>
	
    <bean id="aspect"
             class="com.boventech.learning.aspect.HelloWorldAspectAnnotation"/>
             
    <bean id="aspect2"
             class="com.boventech.learning.aspect.HelloWorldAspectAnnotation2"/>

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com