1、AOP指在程序運行期間動態的將某段代碼切入到指定方法指定位置進行運行的編程方式。aop底層是動態代理。
1 package com.bie.config; 2 3 import org.aspectj.lang.annotation.Aspect; 4 import org.springframework.context.annotation.Bean; 5 import org.springframework.context.annotation.Configuration; 6 import org.springframework.context.annotation.EnableAspectJAutoProxy; 7 8 import com.bie.aop.LogAspect; 9 import com.bie.aop.MathCalculator; 10 11 /** 12 * 13 * 14 * @Title: SpringApplicationConfig.java 15 * @Package com.bie.config 16 * @Description: TODO 17 * @author biehl 18 * @date 2019年12月9日 19 * @version V1.0 20 * 21 * 22 * 1、AOP指在程序運行期間動態的將某段代碼切入到指定方法指定位置進行運行的編程方式。aop底層是動態代理。 23 * 24 * 第一步、導入aop模塊,spring-aspects。 25 * 第二步、定義業務邏輯類,MathCalculator。在業務邏輯運行的時候打印日誌(方法運行之前,方法運行結束,方法出現異常打印日誌。)。 26 * 第三步、定義一個日誌切面類LogAspect,切面類裏面的方法需要動態感知到類的方法MathCalculator.div運行到那一步了。然後開始執行。 27 * 通知方法介紹: 28 * 前置通知:logStart,在目標方法運行之前運行。註解@Before 29 * 後置通知:logEnd,在目標方法運行結束之後運行,無論方法正常結束還是異常結束。註解@After 30 * 返回通知:logReturn,在目標方法運行正常返回之後運行。註解@AfterRetruning 31 * 異常通知:logException,在目標方法運行異常返回之後運行。註解@AfterThrowing 32 * 環繞通知:動態代理。手動推進目標方法運行。 註解@Around 33 * 第四步、根據通知方法給切面類的目標方法標註何時何地運行。標註通知註解。 34 * 第五步、將切面類,和業務邏輯層(目標方法所在的類)都加如到容器中。使用@Bean註解或者@Component註解即可。 35 * 第六步、告訴Spring那個類是切面類。給切面類加一個@Aspect註解。 36 * 第七步、開啓基於註解版的aop模式切面功能。啓用該註解@EnableAspectJAutoProxy,啓動AspectJ自動代理。 37 * @EnableXXX開啓某項功能。 38 * 39 * AOP切面編程重要的三步走: 40 * 第一步、將業務邏輯組件和切面類都加入到容器中。告訴spring容器那個是切面類(@Aspect)。 41 * 第二步、在切面類上的每個通知方法上標註通知註解,告訴spring何時何地運行(注意切入點表達式的書寫)。 42 * 第三步、開啓基於註解版的aop模式切面功能。啓用該註解@EnableAspectJAutoProxy,啓動AspectJ自動代理。 43 */ 44 // @Configuration告訴Spring這是一個配置類,相當於bean.xml配置文件。 45 @Configuration 46 @EnableAspectJAutoProxy 47 public class SpringApplicationConfig15 { 48 49 /** 50 * 將目標類加入到容器中 51 * 52 * @return 53 */ 54 @Bean 55 public MathCalculator mathCalculator() { 56 return new MathCalculator(); 57 } 58 59 60 /** 61 * 將切面類加入到容器中 62 * 63 * @return 64 */ 65 @Bean 66 public LogAspect logAspect() { 67 return new LogAspect(); 68 } 69 70 }
開發業務邏輯層類,如下所示:
1 package com.bie.aop; 2 3 /** 4 * 5 * 6 * @Title: MathCalculator.java 7 * @Package com.bie.aop 8 * @Description: TODO 9 * @author biehl 10 * @date 2019年12月12日 11 * @version V1.0 12 * 13 */ 14 public class MathCalculator { 15 16 /** 17 * 18 * @param i 19 * @param j 20 * @return 21 */ 22 public int div(int i, int j) { 23 System.out.println(i + " / " + j + " = " + i / j); 24 return i / j; 25 } 26 27 }
開發切面類,如下所示:
1 package com.bie.aop; 2 3 import java.util.Arrays; 4 5 import org.aspectj.lang.JoinPoint; 6 import org.aspectj.lang.annotation.After; 7 import org.aspectj.lang.annotation.AfterReturning; 8 import org.aspectj.lang.annotation.AfterThrowing; 9 import org.aspectj.lang.annotation.Aspect; 10 import org.aspectj.lang.annotation.Before; 11 import org.aspectj.lang.annotation.Pointcut; 12 13 /** 14 * 15 * 16 * @Title: LogAspect.java 17 * @Package com.bie.aop 18 * @Description: TODO 19 * @author biehl 20 * @date 2019年12月12日 21 * @version V1.0 22 * 23 * 日誌切面類 24 */ 25 @Aspect // 告訴Spring容器,當前類是切面類 26 public class LogAspect { 27 28 /** 29 * 抽取公共的切入點表達式 30 * 31 * 方式一,如果是本類引用,直接使用即可,@Before("pointCut()") 32 * 方式二,其他的切面類引入,加上類路徑即可@Before("com.bie.aop.LogAspect.pointCut()") 33 */ 34 @Pointcut(value = "execution(* com.bie.aop.MathCalculator.*(..))") 35 public void pointCut() { 36 } 37 38 /** 39 * JoinPoint參數必須出現在參數的第一位 40 * 41 * 方法運行前執行該方法。@Before目標方法之前切入。 42 * 43 * 切入點表達式,public int com.bie.aop.MathCalculator.div(int int)。 指定在那個方法切入。 44 * 45 * Signature簽名是方法的簽名。 46 */ 47 @Before(value = "pointCut()") 48 public void logStart(JoinPoint joinPoint) { 49 // 獲取到方法參數列表 50 Object[] args = joinPoint.getArgs(); 51 // 獲取到方法名稱 52 String methodName = joinPoint.getSignature().getName(); 53 System.out.println(methodName + "()方法名稱, @Before除法方法執行了......參數列表是{" + Arrays.asList(args) + "}"); 54 } 55 56 /** 57 * JoinPoint參數必須出現在參數的第一位 58 * 59 * 方法運行後執行該方法 60 * 61 * @After(value = "public int com.bie.aop.MathCalculator.*(..)") 62 * 代表了MathCalculator該類的所有方法。所有方法的任意參數。 63 * 64 */ 65 @After(value = "pointCut()") 66 public void logEnd(JoinPoint joinPoint) { 67 // 獲取到方法參數列表 68 Object[] args = joinPoint.getArgs(); 69 // 獲取到方法名稱 70 String methodName = joinPoint.getSignature().getName(); 71 System.out.println(methodName + "()方法名稱, @After除法方法結束了......參數列表是{" + Arrays.asList(args) + "}"); 72 } 73 74 /** 75 * JoinPoint參數必須出現在參數的第一位 76 * 77 * returning指定誰來封裝返回值。 78 * 79 * @param result 80 * 參數封裝返回值 81 */ 82 @AfterReturning(value = "pointCut()", returning = "result") 83 public void logReturn(JoinPoint joinPoint, Object result) { 84 // 獲取到方法名稱 85 String methodName = joinPoint.getSignature().getName(); 86 System.out.println(methodName + "()方法名稱, @AfterReturning除法方法正常返回了......運行結果是{" + result + "}"); 87 } 88 89 /** 90 * JoinPoint參數必須出現在參數的第一位 91 * 92 * throwing指定誰來封裝返回值。 93 * 94 * @param exception 95 * 參數封裝返回值 96 */ 97 @AfterThrowing(value = "pointCut()", throwing = "exception") 98 public void logException(JoinPoint joinPoint, Exception exception) { 99 // 獲取到方法名稱 100 String methodName = joinPoint.getSignature().getName(); 101 System.out.println(methodName + "()方法名稱, @AfterThrowing除法方法異常了......異常信息是{" + exception + "}"); 102 } 103 104 }
測試主類,如下所示:
1 package com.bie.main; 2 3 import org.springframework.beans.BeansException; 4 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 5 6 import com.bie.aop.MathCalculator; 7 import com.bie.config.SpringApplicationConfig15; 8 9 /** 10 * 11 * 12 * @Title: SpringApplication.java 13 * @Package com.bie.main 14 * @Description: TODO 15 * @author biehl 16 * @date 2019年12月9日 17 * @version V1.0 18 * 19 */ 20 public class SpringApplication { 21 22 public static void main(String[] args) { 23 // 獲取到註解配置類 24 AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringApplicationConfig15.class); 25 26 try { 27 // 使用容器中獲取到目標對象,而不是自己創建對象。 28 MathCalculator mathCalculator = ac.getBean(MathCalculator.class); 29 mathCalculator.div(42, 2); 30 } catch (BeansException e) { 31 e.printStackTrace(); 32 } 33 34 // 調用關閉的時候,調用destory銷燬方法。 35 ac.close(); 36 } 37 38 }
作者:別先生
博客園:https://www.cnblogs.com/biehongli/
如果您想及時得到個人撰寫文章以及著作的消息推送,可以掃描上方二維碼,關注個人公衆號哦。