1. 程式人生 > >Spring使用註解的方式實現AOP的開發——Spring AOP(七)

Spring使用註解的方式實現AOP的開發——Spring AOP(七)

上一章我們已經學過使用XML的方式實現AOP:
https://blog.csdn.net/qq_34598667/article/details/83502426
本章我們學習一下使用註解的方式實現AOP


Spring使用註解的方式實現AOP的開發


本章所需知識點

1、開啟aop註解的自動代理

< aop:aspectj-autoproxy/>

2、 AspectJ的AOP的註解:

  • @Aspect:定義切面類的註解
  • 通知型別:
    @Before:前置通知
    @AfterReturing:後置通知
    @Around:環繞通知
    @After:最終通知
    @AfterThrowing:異常丟擲通知.
  • @Pointcut:定義切入點的註解

3、切入點語法表示式(與xml方式一樣)

語法:execution(表示式)
表示式語法:[方法訪問修飾符] 方法返回值包名.類名.方法名(方法的引數)

例1:
execution (* com.oak.service.impl.UserServiceImpl.*(…)) :匹配UserServiceImpl類中宣告的所有方法。
第一個 * :代表任意修飾符及任意返回值型別
第二個 * :代表任意方法,
… :匹配任意數量任意型別的引數,若目標類與該切面在同一個包中,可以省略包名。

例2:execution public double cn.itcast.service.impl.PersonServiceImpl.*(…):匹配PersonServiceImpl類中返回值型別為double型別的所有公有方法。


實現案例

本章案例基於上一章使用xml的方式實現AOP的專案上繼續完成:

1)編寫目標類

建立介面InfoService
public interface InfoService {
	void save(); 
	void update(); 
	void delete(); 
	void find(); 
}
建立實現類InfoServiceImpl
public class InfoServiceImpl implements InfoService{

	@Override
	public void save() {
		System.out.println
("I am the method for save "); } @Override public void update() { System.out.println("I am the method for update "); } @Override public void delete() { System.out.println("I am the method for delete "); } @Override public void find() { System.out.println("I am the method for find "); } }

2)配置目標類

<!--配置目標類 -->
<bean id="infoService" class="com.oak.service.InfoServiceImpl"></bean>

3)開啟aop自動代理

<!--配置目標類 -->
<bean id="infoService" class="com.oak.service.InfoServiceImpl"></bean>
<!-- 開啟aop的自動代理 -->
<aop:aspectj-autoproxy/> 

4)編寫切面類MyAspectAnno

宣告切入點和通知方法


@Aspect
public class MyAspectAnno {
	
	//宣告一個切入點,anyMethod為切入點名稱,指定切入點,哪些方法需要通知
	@Pointcut("execution (* com.oak.service.InfoService.*(..))")
	private void anyMethod(){}
	
	//宣告該方法是一個前置通知:在目標方法開始之前執行 
	@Before("anyMethod()")
	public void doBeforeCheck() {
        System.out.println("前置通知");
    }
}

5)配置切面類

<!--配置切面類--> 
<bean id="myAspectAnno" class="com.oak.aop.MyAspectAnno"></bean> 

6)測試

在測試類中編寫測試方法

@Test
public void aopAnnoTest(){
	ApplicationContext cxt = 
				 new ClassPathXmlApplicationContext
				 ("applicationContext.xml");
	InfoService infoService=cxt.getBean("infoService",InfoService.class);
	infoService.save();
}

測試結果是:

前置通知
I am the method for save 

7)其他通知

修改切面類,使用註解加上其他通知

@Aspect
public class MyAspectAnno {
	
	//宣告一個切入點,anyMethod為切入點名稱,指定切入點,哪些方法需要通知
	@Pointcut("execution (* com.oak.service.InfoService.*(..))")
	private void anyMethod(){}
	
	//宣告該方法是一個前置通知:在目標方法開始之前執行 
	@Before("anyMethod()")
	public void doBeforeCheck() {
        System.out.println("前置通知");
    }
	@AfterReturning("anyMethod()")
    public void doAfterReturning() {
        System.out.println("後置通知");
    }

    @After("anyMethod()")
    public void doAfter() {
        System.out.println("最終通知");
    }

    @AfterThrowing("anyMethod()")
    public void doAfterThrowing() {
        System.out.println("異常通知");
    }

    @Around("anyMethod()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        /**
         * 環繞通知內部一定要確保執行該方法,如果不執行該方法,業務bean中被攔截的方法就不會被執行。
         * 當執行該方法,如果後面還有切面的話,它的執行順序應該是這樣的:先執行後面的切面,如果後面沒有切面了,
         * 再執行最終的目標物件的業務方法。若不執行該方法,則後面的切面,業務bean的方法都不會被執行。
         */
        // if () { // 判斷使用者是否有許可權,
        System.out.println("進入方法");
        Object result = pjp.proceed();
        System.out.println("退出方法");
        // }
        return result;
    }
}

注意:環繞通知內部一定要確保執行proceed()該方法,如果不執行該方法,業務bean中被攔截的方法就不會被執行。當執行該方法,如果後面還有切面的話,它的執行順序應該是這樣的:先執行後面的切面,如果後面沒有切面了,再執行最終的目標物件的業務方法。若不執行該方法,則後面的切面,業務bean的方法都不會被執行。

執行測試:

進入方法
前置通知
I am the method for save 
退出方法
最終通知
後置通知