javascript
Spring AOP 简介以及简单用法
Spring AOP 簡(jiǎn)介以及簡(jiǎn)單用法
如果你去面試java開(kāi)發(fā), 那么Spring的AOP和DI幾乎是必問(wèn)的問(wèn)題。
那么AOP是什么呢?
一. AOP
所謂Aop就是 Aspect-OrientedProgramming, 中文就是面向切面編程。
我們之前聽(tīng)說(shuō)面向過(guò)程編程, 以及面向?qū)ο缶幊?#xff0c; 而這個(gè)面向切面編程我們可以視為是面向?qū)ο缶幊痰?個(gè)補(bǔ)充(增強(qiáng));
在一般的方法(函數(shù))中, 為了方便,可能只寫(xiě)了業(yè)務(wù)代碼
1. 業(yè)務(wù)代碼
而我們我們可以將其補(bǔ)充成4個(gè)部分。
1.1 橫切關(guān)注點(diǎn) (Crosscutting Concerns)
大家看上面的方法, 就像用刀子把1個(gè)方法橫向切成4塊, 我們把上面除業(yè)務(wù)代碼外任意一個(gè)部分就叫做橫切關(guān)注點(diǎn).
1.2 切面 (Aspect)
我們可以把橫切關(guān)注點(diǎn)進(jìn)行分組, 其中任意一組就叫做切面
例如上面的例子中, 我們可以分成
1.3 通知 (Advice)
所謂通知就是切面要完成的工作。
例如對(duì)于日志通知來(lái)講, 里面執(zhí)行日志的方法我們就可以稱為1個(gè)通知。
1.4 目標(biāo) (Target)
所謂目標(biāo)就是被通知的對(duì)象, 也就是指上面例子中的原方法本身啦。
1.5 代理 (Proxy)
當(dāng)目標(biāo)被通知后產(chǎn)生的對(duì)象就叫做代理, 因?yàn)锳OP的原理就是利用代理來(lái)實(shí)現(xiàn)的, 如果想了解動(dòng)態(tài)代理的可以參考這里
1.6 連接點(diǎn) (Joinpoint)
所謂Joinpoint就是程序執(zhí)行到的某個(gè)位置,
上面例子中, 業(yè)務(wù)代碼方法的執(zhí)行之前, 執(zhí)行之后, 拋出異常后 都可以視為某個(gè)連接點(diǎn)。
1.7 切點(diǎn) (PointCut)
每個(gè)方法都存在多個(gè)連接點(diǎn), 而Spring AOP利用切點(diǎn)來(lái)定位到具體那些連接點(diǎn)。
Joinpoint 和 PointCut 的關(guān)系可以作如下比喻,假如Joinpoint的數(shù)據(jù)里的記錄, 那么PointCut就相當(dāng)于查詢條件
1.8 小結(jié)
而Spring的AOP 能在不修改具體某個(gè)方法的前提下, 利用動(dòng)態(tài)代理技術(shù)將通知注入到這個(gè)方法的各個(gè)連接點(diǎn)中, 令到這個(gè)方法得到了必要的補(bǔ)充。
對(duì)于上面的例子種, 我們?cè)瓉?lái)的方法只有業(yè)務(wù)代碼, 但是我們可以利用Spring AOP加入 驗(yàn)證參數(shù), 日志等功能!
二. 具體例子
2.1 還沒(méi)使用AOP的例子
我們首先利用spring創(chuàng)建兩個(gè)計(jì)算類。
1個(gè)加法類, 1個(gè)減法類。
bean config xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"><!-- auto scan --><context:component-scan base-package="com.home.aop"></context:component-scan> </beans>注意引入aop命名空間
計(jì)算接口 Calculator
package com.home.aop;public interface Calculator {public double getResult(double a, double b); }加法類 AddCalculator
package com.home.aop;import org.springframework.stereotype.Component;@Component public class AddCalculator implements Calculator {@Overridepublic double getResult(double a, double b) {return a + b;} }減法類 SubCalculator
package com.home.aop;import org.springframework.stereotype.Component;@Component public class SubCalculator implements Calculator {@Overridepublic double getResult(double a, double b) {return a - b;} }Client 代碼
package com.home.aop;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class AopMain {public static void f(){g();}public static void g(){ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-aop.xml");Calculator addCal = (Calculator) ctx.getBean("addCalculator");Calculator subCal = (Calculator) ctx.getBean("subCalculator");System.out.println(addCal.getResult(3, 1));System.out.println(subCal.getResult(3, 1));} }執(zhí)行結(jié)果
Jul 05, 2016 10:10:00 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5d79a4c9: startup date [Tue Jul 05 22:10:00 CST 2016]; root of context hierarchy Jul 05, 2016 10:10:00 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [bean-aop.xml] 4.0 2.02.2 小結(jié)
上面例子中, 加法類和減法類中只包含了業(yè)務(wù)代碼, 我們可以將視為兩個(gè)Target(目標(biāo)), 下面我們就利用AOP技術(shù)為這兩個(gè)Target加入通知。
2.3 AOP 前置通知
這個(gè)任務(wù)的需求很簡(jiǎn)單。
首先maven里要引入這些lib
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${org.springframework.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${org.springframework.version}</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.8.8</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.8</version></dependency>然后在bean-config xml里加入下面這個(gè)句話, enable spring aop 功能
<!-- enable @Aspect --><aop:aspectj-autoproxy></aop:aspectj-autoproxy>然后新建1個(gè)類LoggingAspect
package com.home.aop;import java.util.Arrays; import java.util.List;import org.springframework.stereotype.Component; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;@Aspect @Component public class LoggingAspect {//@Before("execution(public double com.home.aop.AddCalculator.getResult(double,double))")@Before("execution(public * com.home.aop.*.*(..))")public void beforeExecute(JoinPoint joinPoint){String classname = joinPoint.getTarget().getClass().getSimpleName();String methodName = joinPoint.getSignature().getName();List<Object> args = Arrays.asList(joinPoint.getArgs());System.out.println("before Execute! --class name: " + classname + ", method name: " + methodName + " " + args );}}方法beforeExecute的意思就是我們要為目標(biāo)執(zhí)行之前 而注入的方法。
上面@Before 注解表示這是1個(gè)前置通知。 括號(hào)里面的就是PointCut(切點(diǎn)), 上面說(shuō)過(guò)了, 相當(dāng)于數(shù)據(jù)庫(kù)里的查詢條件
然后Spring AOP 會(huì)根據(jù)PointCut 查找出所有符合條件的目標(biāo)。
內(nèi)容就很簡(jiǎn)單了, 無(wú)非就是輸出被執(zhí)行的類名方法名和參數(shù)…
執(zhí)行結(jié)果:
Jul 06, 2016 12:30:03 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6924181b: startup date [Wed Jul 06 00:30:03 CST 2016]; root of context hierarchy Jul 06, 2016 12:30:03 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [bean-aop.xml] before Execute! --class name: AddCalculator, method name: getResult [3.0, 1.0] 4.0 before Execute! --class name: SubCalculator, method name: getResult [3.0, 1.0] 2.0三 總結(jié)
項(xiàng)目中, 如果不用AOP 我們往往要為每個(gè)方法添加日志代碼, 十分難于維護(hù), 可讀性也大大下降, 而AOP的出現(xiàn), 就能解決這些問(wèn)題。
總結(jié)
以上是生活随笔為你收集整理的Spring AOP 简介以及简单用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Spring 利用FactoryBean
- 下一篇: SpringMVC Controller