1. 什麼是aop
AOP為Aspect Oriented Programming的縮寫,是面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續,是軟體開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生范型。
AOP的出現彌補了OOP的這點不足,AOP 是一個概念,一個規范,本身並沒有設定具體語言的實現,AOP是基於動態代理模式。AOP是方法級別的,要測試的方法不能為static修飾,因為介面中不能存在靜態方法,編譯就會報錯。
AOP可以分離業務代碼和關注點代碼(重復代碼),在執行業務代碼時,動態的注入關注點代碼。切面就是關注點代碼形成的類。Spring AOP中的動態代理主要有兩種方式,JDK動態代理和CGLIB動態代理。JDK動態代理通過反射來接收被代理的類,並且要求被代理的類必須實現一個介面。
(1)javaaop實例擴展閱讀
AOP實現的關鍵在於AOP框架自動創建的AOP代理,AOP代理主要分為靜態代理和動態代理,靜態代理的代表為AspectJ。而動態代理則以Spring AOP為代表,靜態代理是編譯期實現,動態代理是運行期實現,可想而知前者擁有更好的性能。
靜態代理是編譯階段生成AOP代理類,也就是說生成的位元組碼就織入了增強後的AOP對象;動態代理則不會修改位元組碼,而是在內存中臨時生成一個AOP對象,這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法。
2. spring配置aop的方式有哪些
在Spring中實現AOP根據版本不同,可以有大致四種配置方式。現簡單列一下。在介紹Spring的AOP配置方式前,先要注意Spring中Advisor的概念。在Spring中Advisor是Advice和Pointcut的結合,但它還不是AOP概念上的Aspect。因為在Spring中Advisor還是Spring用來生成Aspect對象的一個原型,根據配置的不同,Spring可以只對某個類生成Aspect,也可以對所有的類生成Aspect。
1. 基於xml配置文件的代理配置方式
這種方式在2.0以後很少用了,原因是配置項過多,過於繁瑣。但對於理解Spring AOP還是很有幫助的
1.1 定義通知
<bean id="advice" class="yourAdviceImpl" />
1.2 定義切點
要定義一個切點,可以選擇使用正則表達式方式聲明的切點或者AspectJ方式聲明的切點。對正則表達式切點,使用Perl5RegexpMethodPointcut或JdkRegexpMethodPointcut(Java
1.4以上版本,不需要Jakarta ORO的支持了);對AspectJ切點,使用AspectJExpressPointcut
<bean id="pointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value="yourRegularExpression" />
</bean>
<bean id="pointcut" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="expression" value="yourAspectJExpression" />
</bean>
1.3 定義通知者
DefaultPointcutAdvisor是Spring提供的默認通知者,它需要提供通知和切點的引用。
Spring也提供了RegexpMethodPointcutAdvisor和來對應兩種聲明切點的方式,不用再單獨定義切點。
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="advice" />
<property name="pointcut" ref="pointcut" />
</bean>
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="advice" />
<property name="pattern" value="yourRegularExpression" />
</bean>
<bean id="advisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="advice" ref="advice" />
<property name="expression" value="yourAspectjExpression" />
</bean>
1.4 定義ProxyFactoryBean
<bean id="yourBean" class="org.springframework.aop.framework.ProxyFactoryBean>
<property name="target" ref="yourTargetBean" />
<property name="interceptorNames" value="advisor" />
<property name="proxyInterfaces" value="interfaceClass" />
</bean>
interceptorNames和proxyInterfaces都是數組屬性,所以可以聲明要使用的一個list,也可以讓Spring自動把單個值轉化為數組
上面明確定義了要對那個targetBean應用代理生成切面實例。如果不想限制targetBean,可以讓Spring為所有匹配切點聲明的bean生成切面實例,這樣就不用一個個定義ProxyFactoryBean了,只需要定義
<bean class="org.springframework.aop.framework.autoproxy." />
這是一個BeanPostProcessor,所以Spring會自動識別並在bean的聲明周期使用
2 利用2.0以後使用aop標簽
<aop:config>
<aop:aspect ref="">
<aop:pointcut id="performance" expression="execution(* *.perform(..))" />
<aop:before method="" pointcut-ref="performance" />
<aop:before method="" pointcut="execution(* *.perform(..))" />
<aop:after-returning method="" pointcut="execution(* *.perform(..))" />
<aop:after-throwing method="" pointcut="execution(* *.perform(..))" />
</aop:aspect>
</aop:config>
3 利用Annotation
3.1 利用@Aspect將一個POJO類聲明為一個切面。
3.2 定義切點
@Pointcut("execution(* *.perform(..))")
public void performance(){}
通過@Pointcut定義的切點的名字就是它所註解的方法的名字,因此例子中的切點名字是
performance()。這里聲明的performance()方法實際聖只是一個標記,為@Pointcut提供附加的點,並不要求有實際意義。
3.3 定義通知
對要執行切面的方法,通過@Before("performance()"),@AfterReturning
("performance()")來定義通知。注意這里提供的切點名稱,是performance(),而不是performance
如果對上面的兩點不是很理解,也可以省略@Pointcut,而將AspectJ表達式直接定義在@Before等通知中,將上面的兩步合為一步,如@Before("execution(* *.perform(..))")
3.4 通知Spring創建代理
<aop:aspectj-autoproxy>
這實際上相當於聲明了一個,從而根據@Pointcut聲明的切點來自動代理匹配的bean實例
4 在Spring中結合進AspectJ
對於超出Spring AOP支持范圍的,可以採用這種方式。只需要在Spring中配置AspectJ的Class實例時讓Spring能夠獲得AspectJ類的實例就可以了,比如
<bean class="a_aspectj_class" factory-method="aspectOf">
<preperty .... />
</bean>
3. java中的靜態方法能否進行切面編程
aop的事務代理機制最重要的放心是確定切入點,面,通知.具體看代碼,下面是在spring中配置的我自己寫的一個異常處理的aop作用類 ,該配置切入面在於在controller包下的所有類的所有註解為aspect的切面類,通知類型為表示在目標方法之前切入,切入點為controller包下的所有類所有方法.至於樓主所說的靜態方法對於事務機制應該沒什麼區別吧,只要用within方法一樣可以的
<!-- 定義共同處理組件 -->
<bean id="loggerBean"
class="org.te.cloudnote.aspect.LoggerBean">
</bean>
<!-- 將loggerBean組件切入到Controller方法上 -->
<aop:config>
<!-- 要切入哪個共同處理組件,ref指定共同組件id值 -->
<aop:aspect ref="loggerBean">
<!-- aop:before表示在目標方法之前切入,
method指定方法名;pointcut指定目標組件 -->
<aop:before method="logController"
pointcut="within(org.te.cloudnote.controller..*)"/>
</aop:aspect>
4. java編程,spring里ioc和aop用什麼原理實現的
控制反轉(IOC)
(理解好Ioc的關鍵是要明確「誰控制誰,控制什麼,為何是反轉(有反轉就應該有正轉了),哪些方面反轉了」)
1、Ioc—Inversion of Control:即「控制反轉」,不是什麼技術,而是一種設計思想。在Java開發中,Ioc意味著將你設計好的對象交給容器控制,而不是傳統的在你的對象內部直接控制。
2、誰控制誰,控制什麼:傳統Java SE程序設計,我們直接在對象內部通過new進行創建對象,是程序主動去創建依賴對象;而IoC是有專門一個容器來創建這些對象即由Ioc容器來控制對象的創建。
誰控制誰?當然是IoC 容器控制了對象。
控制什麼?那就是主要控制了外部資源獲取(不只是對象包括比如文件等)。
3、為何是反轉,哪些方面反轉了: 有反轉就有正轉,傳統應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴對象。
為何是反轉?因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉。
哪些方面反轉了?依賴對象的獲取被反轉了。
還是不明白沒事,下面搞個簡單案例來說就懂啦 !!!
例子:當我們在任何一個有實際開發意義的程序項目中,我們會使用很多類來描述他們特有的功能,並且通過類與類之間的相互協作來完成特定的業務邏輯。這個時候,每個類都需要負責管理與自己有交互的類的引用和依賴,代碼將會變的異常難以維護和極高的高耦合。而IOC的出現正是用來解決這個問題,我們通過IOC將這些依賴對象的創建、協調工作交給spring容器去處理,每個對象值需要關注其自身的業務邏輯關系就可以了。在這樣的角度上來看,獲得依賴的對象的方式,進行了反轉,變成了由spring容器控制對象如何獲取外部資源(包括其他對象和文件資料等)。
總的來說:IOC就是通過在Xml配置文件里依賴注入來解決代碼問題。
IOC的注入類型有幾種?主要可以劃分為三種:構造函數注入、屬性注入和介面注入。Spring支持構造函數注入和屬性注入
面向切面(AOP)
(面向切面編程,AOP其實只是OOP的補充而已,AOP基本上是通過代理機制實現的。)
我們管切入到指定類指定方法的代碼片段稱為切面,而切入到哪些類、哪些方法則叫切入點。有了AOP,我們就可以把幾個類共有的代碼,抽取到一個切片中,等到需要時再切入對象中去,從而改變其原有的行為。
我們都知道 Java 是 OOP-面向對象編程的,它有自己的優勢,也有自己的不足。比如說:在我們開發中,都會有一條業務主線(即客戶的需求)。而我們要做的就是實現這個主線上的需求。我們在實現這些功能的時候,經常要干一些額外的不可避免的事情,比如事務的管理,日誌的記錄等,就很繁雜且代碼量增多,所以 Spring 提供了另一種角度來思考程序結構,也就是把這一些事情剝離出來,然後適時適地的把它們加入到我們的代碼中,比如說 聲明式事務管理的時候,我們在 service 層檢測到save*、update*這些方法要被調用的時候,我們先進行開啟事務什麼的,這就是AOP,面向編程的思想。
AOP的術語:
1、通知(Advice):就是你想要的功能,也就是上面說的 安全,事物,日誌等。你給先定義好把,然後在想用的地方用一下
2、連接點(JoinPoint):這個更好解釋了,就是spring允許你使用通知的地方,那可真就多了,基本每個方法的前,後(兩者都有也行),或拋出異常時都可以是連接點,spring只支持方法連接點.其他如aspectJ還可以讓你在構造器或屬性注入時都行,不過那不是咱關注的,只要記住,和方法有關的前前後後(拋出異常),都是連接點。
3、切入點(Pointcut):上面說的連接點的基礎上,來定義切入點,你的一個類里,有15個方法,那就有幾十個連接點了對把,但是你並不想在所有方法附近都使用通知(使用叫織入,以後再說),你只想讓其中的幾個,在調用這幾個方法之前,之後或者拋出異常時干點什麼,那麼就用切點來定義這幾個方法,讓切點來篩選連接點,選中那幾個你想要的方法。
4、切面(Aspect):切面是通知和切入點的結合。現在發現了吧,沒連接點什麼事情,連接點就是為了讓你好理解切點,搞出來的,明白這個概念就行了。通知說明了干什麼和什麼時候干(什麼時候通過方法名中的before,after,around等就能知道),而切入點說明了在哪干(指定到底是哪個方法),這就是一個完整的切面定義。
5、引入(introction):允許我們向現有的類添加新方法屬性。這不就是把切面(也就是新方法屬性:通知定義的)用到目標類中嗎
6、目標(target):引入中所提到的目標類,也就是要被通知的對象,也就是真正的業務邏輯,他可以在毫不知情的情況下,被咱們織入切面。而自己專注於業務本身的邏輯。
7、代理(proxy):怎麼實現整套aop機制的,都是通過代理,這個一會給細說。
8、織入(weaving):把切面應用到目標對象來創建新的代理對象的過程。有3種方式,spring採用的是運行時,為什麼是運行時,後面解釋。