javascript
Spring学习之AOP(面向切面编程)
動態代理
??? 代理模式是常用的java設計模式,他的特征是代理類與委托類有同樣的接口,代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事后處理消息等。代理類與委托類之間通常會存在關聯關系,一個代理類的對象與一個委托類的對象關聯,代理類的對象本身并不真正實現服務,而是通過調用委托類的對象的相關方法,來提供特定的服務
????動態代理好比如影星和經紀人,實際演戲的是影星,經紀人為影星處理好拍戲前后的事情.實際演戲的是影星.電影公司找影星拍戲前需要先找到經紀人,但最終拍戲還是得找影星執行這個動作.?
?public?interface?Dinner?{//吃晚飯的方法public?void?haveDinner(); } //委托類 public?class?MyDinner?implements?Dinner{@Overridepublic?void?haveDinner()?{System.out.println("媽媽做的晚飯真好吃....");} } import?java.lang.reflect.InvocationHandler; import?java.lang.reflect.Method; import?java.lang.reflect.Proxy; //代理類 public?class?MyDinnerProxy?implements?InvocationHandler?{private?Object?originalObject;?//被代理的原始對象//綁定被代理對象,返回一個代理對象public?Object?getProxy(Object?obj){this.originalObject?=?obj;//返回一個代理對象return?Proxy.newProxyInstance(obj.getClass().getClassLoader(),?obj.getClass().getInterfaces(),?this);}?@Overridepublic?Object?invoke(Object?proxy,?Method?method,?Object[]?args)throws?Throwable?{Object?result?=?null;System.out.println("吃飯之前洗手保持個人衛生...");result?=?method.invoke(this.originalObject,?args);System.out.println("吃飯之后洗碗保持廚房衛生....");return?result;}? } //測試類 public?class?MyDinnerProxyDemo?{public?static?void?main(String[]?args)?{Dinner?din?=?new?MyDinner();//不是使用代理對象的效果//din.haveDinner();MyDinnerProxy?proxy?=?new?MyDinnerProxy();//返回了一個代理對象din?=?(Dinner)proxy.getProxy(din);//執行代理對象的方法din.haveDinner();} }AOP簡介?
AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論, 是對傳統 OOP(Object-Oriented Programming, 面向對象編程) 的補充.
AOP 的主要編程對象是切面(aspect), 而切面模塊化橫切關注點.
在應用 AOP 編程時, 仍然需要定義公共功能, 但可以明確的定義這個功能在哪里, 以什么方式應用, 并且不必修改受影響的類. 這樣一來橫切關注點就被模塊化到特殊的對象(切面)里.
AOP 的好處:
–每個事物邏輯位于一個位置, 代碼不分散, 便于維護和升級
–業務模塊更簡潔, 只包含核心業務代碼.
?
?
切面(Aspect):? 橫切關注點(跨越應用程序多個模塊的功能)被模塊化的特殊對象
通知(Advice):? 切面必須要完成的工作
目標(Target): 被通知的對象
代理(Proxy): 向目標對象應用通知之后創建的對象
連接點(Joinpoint):程序執行的某個特定位置:如類某個方法調用前、調用后、方法拋出異常后等。連接點由兩個信息確定:方法表示的程序執行點;相對點表示的方位。例如 ArithmethicCalculator#add() 方法執行前的連接點,執行點為 ArithmethicCalculator#add(); 方位為該方法執行前的位置
切點(pointcut):每個類都擁有多個連接點:例如 ArithmethicCalculator的所有方法實際上都是連接點,即連接點是程序類中客觀存在的事務。AOP 通過切點定位到特定的連接點。類比:連接點相當于數據庫中的記錄,切點相當于查詢條件。切點和連接點不是一對一的關系,一個切點匹配多個連接點,切點通過 org.springframework.aop.Pointcut接口進行描述,它使用類和方法作為連接點的查詢條件。???
切面就是一個帶有 @Aspect 注解的 Java 類.
切面需要在IOC容器中,@Component
通知是標注有某種注解的簡單的 Java 方法.
AspectJ支持 5 種類型的通知注解:
–@Before: 前置通知, 在方法執行之前執行
–@After: 后置通知, 在方法執行之后執行
–@AfterRunning: 返回通知, 在方法返回結果之后執行
–@AfterThrowing: 異常通知, 在方法拋出異常之后
–@Around: 環繞通知, 圍繞著方法執行
?可以用@Order(1)指定不同切面的優先級(也就是執行順序),數字越小優先級越高
?在 AspectJ切面中, 可以通過 @Pointcut注解將一個切入點聲明成簡單的方法. 切入點的方法體通常是空的, 因為將切入點定義與應用程序邏輯混在一起是不合理的
import?org.aspectj.lang.annotation.After; import?org.aspectj.lang.annotation.Aspect; import?org.aspectj.lang.annotation.Before; import?org.springframework.stereotype.Component; /***?AOP?的?helloWorld*?1.?加入?jar?包*?com.springsource.net.sf.cglib-2.2.0.jar*?com.springsource.org.aopalliance-1.0.0.jar*?com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar*?spring-aspects-4.0.0.RELEASE.jar*?*?2.?在?Spring?的配置文件中加入?aop?的命名空間。?*?*?3.?基于注解的方式來使用?AOP*?3.1?在配置文件中配置自動掃描的包:?<context:component-scan?base-package="com.atguigu.spring.aop"></context:component-scan>*?3.2?加入使?AspjectJ?注解起作用的配置:?<aop:aspectj-autoproxy></aop:aspectj-autoproxy>?使@Before和@After起作用*?為匹配的類自動生成動態代理對象.?*?*?4.?編寫切面類:?*?4.1?一個一般的?Java?類*?4.2?在其中添加要額外實現的功能.?**?5.?配置切面*?5.1?切面必須是?IOC?中的?bean:?添加?@Component?注解*?5.2?聲明是一個切面:?添加?@Aspect*?5.3?配置切面優先級@Order(1)*?5.3.1?給方法配置通知注解. 前置通知:?@Before("execution(public?int?com.atguigu.spring.aop.ArithmeticCalculator.*(int,?int))")*?6.?在通知中訪問連接細節:?可以在通知方法中添加?JoinPoint?類型的參數,?從中可以訪問到目標方法的簽名和方法的參數.?*?*/ //通過添加?@Aspect?注解聲明一個?bean?是一個切面! @Order(2) @Aspect @Component public?class?LoggingAspect?{ /***?定義一個方法,?用于聲明切入點表達式.?一般地,?該方法中再不需要添入其他的代碼.?*?使用?@Pointcut?來聲明切入點表達式.?*?后面的其他通知直接使用方法名來引用當前的切入點表達式.?*/@Pointcut("execution(public?int?com.atguigu.spring.aop.ArithmeticCalculator.*(..))")public?void?declareJointPointExpression(){}//聲明是一個前置通知,在目標方法之前執行@Before("declareJointPointExpression()")public?void?beforeMethod(JoinPoint?joinPoint){String?methodName?=?joinPoint.getSignature().getName();Object?[]?args?=?joinPoint.getArgs();System.out.println("The?method?"?+?methodName?+?"?begins?with?"?+?Arrays.asList(args));} //聲明是一個后置通知,在目標方法執行后(發生異常后)執行,還不能訪問目標方法的執行結果@After("execution(*?com.atguigu.spring.aop.*.*(..))")public?void?afterMethod(JoinPoint?joinPoint){String?methodName?=?joinPoint.getSignature().getName();System.out.println("The?method?"?+?methodName?+?"?ends");}/***?在方法法正常結束受執行的代碼*?返回通知是可以訪問到方法的返回值的!*/@AfterReturning(value="declareJointPointExpression()",returning="result")public?void?afterReturning(JoinPoint?joinPoint,?Object?result){String?methodName?=?joinPoint.getSignature().getName();System.out.println("The?method?"?+?methodName?+?"?ends?with?"?+?result);}/***?在目標方法出現異常時會執行的代碼.*?可以訪問到異常對象;?且可以指定在出現特定異常時在執行通知代碼*/@AfterThrowing(value="declareJointPointExpression()",throwing="e")public?void?afterThrowing(JoinPoint?joinPoint,?Exception?e){String?methodName?=?joinPoint.getSignature().getName();System.out.println("The?method?"?+?methodName?+?"?occurs?excetion:"?+?e);}/***?環繞通知需要攜帶?ProceedingJoinPoint?類型的參數.?*?環繞通知類似于動態代理的全過程:?ProceedingJoinPoint?類型的參數可以決定是否執行目標方法.*?且環繞通知必須有返回值,?返回值即為目標方法的返回值*//*@Around("execution(public?int?com.atguigu.spring.aop.ArithmeticCalculator.*(..))")public?Object?aroundMethod(ProceedingJoinPoint?pjd){Object?result?=?null;String?methodName?=?pjd.getSignature().getName();try?{//前置通知System.out.println("The?method?"?+?methodName?+?"?begins?with?"?+?Arrays.asList(pjd.getArgs()));//執行目標方法result?=?pjd.proceed();//返回通知System.out.println("The?method?"?+?methodName?+?"?ends?with?"?+?result);}?catch?(Throwable?e)?{//異常通知System.out.println("The?method?"?+?methodName?+?"?occurs?exception:"?+?e);throw?new?RuntimeException(e);}//后置通知System.out.println("The?method?"?+?methodName?+?"?ends");return?result;} } //另一個切面 package?com.atguigu.spring.aop; import?java.util.Arrays; import?org.aspectj.lang.JoinPoint; import?org.aspectj.lang.annotation.Aspect; import?org.aspectj.lang.annotation.Before; import?org.springframework.core.annotation.Order; import?org.springframework.stereotype.Component; @Order(1) @Aspect @Component public?class?VlidationAspect?{ //重用另一個包的一個類里的切入點表達式@Before("com.atguigu.spring.aop.LoggingAspect.declareJointPointExpression()")public?void?validateArgs(JoinPoint?joinPoint){System.out.println("-->validate:"?+?Arrays.asList(joinPoint.getArgs()));}}?
轉載于:https://blog.51cto.com/s5650326/1717136
總結
以上是生活随笔為你收集整理的Spring学习之AOP(面向切面编程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android开发之Intent.Act
- 下一篇: WebView与JavaScript交互