day14-15-Spring AOP總結(jié)(千峰逆戰(zhàn))

一、第五種方式
1邀桑、AOP的相關(guān)概念
橫切關(guān)注點(diǎn):對(duì)哪些方法進(jìn)行攔截,攔截后怎么處理科乎,這些關(guān)注點(diǎn)稱(chēng)之為橫切關(guān)注點(diǎn)
Aspect(切面):通常是一個(gè)類(lèi)壁畸,里面可以定義切入點(diǎn)和通知
JointPoint(連接點(diǎn)):程序執(zhí)行過(guò)程中明確的點(diǎn),一般是方法的調(diào)用茅茂。被攔截到的點(diǎn)捏萍,因?yàn)镾pring只支持方法類(lèi)型的連接點(diǎn),所以在Spring中連接點(diǎn)指的就是被攔截到的方法空闲,實(shí)際上連接點(diǎn)還可以是字段或者構(gòu)造器
Advice(通知):AOP在特定的切入點(diǎn)上執(zhí)行的增強(qiáng)處理令杈,有before(前置),after(后置),afterReturning(最終),afterThrowing(異常),around(環(huán)繞)
Pointcut(切入點(diǎn)):就是帶有通知的連接點(diǎn),在程序中主要體現(xiàn)為書(shū)寫(xiě)切入點(diǎn)表達(dá)式
weave(織入):將切面應(yīng)用到目標(biāo)對(duì)象并導(dǎo)致代理對(duì)象創(chuàng)建的過(guò)程
introduction(引入):在不修改代碼的前提下碴倾,引入可以在運(yùn)行期為類(lèi)動(dòng)態(tài)地添加一些方法或字段
AOP代理(AOP Proxy):AOP框架創(chuàng)建的對(duì)象逗噩,代理就是目標(biāo)對(duì)象的加強(qiáng)。Spring中的AOP代理可以使JDK動(dòng)態(tài)代理跌榔,也可以是CGLIB代理异雁,前者基于接口,后者基于子類(lèi)
目標(biāo)對(duì)象(Target Object): 包含連接點(diǎn)的對(duì)象僧须。也被稱(chēng)作被通知或被代理對(duì)象纲刀。POJO
2、第五種方式
Student.class

package com.qianfeng.aop05;

public class Student implements Person {
@Override
public boolean eat() {
System.out.println("I can eat");
return true;
}
@Override
public String drink() {
System.out.println(1/0);
System.out.println("I can drink");
return null;
}
}

beans5.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="st" class="com.qianfeng.aop05.Student" />
<bean id="my" class="com.qianfeng.aop05.MyAspect" />
<aop:config proxy-target-class="true">
<aop:aspect ref="my">
<aop:pointcut id="pt" expression="(execution(boolean com.qianfeng.aop05..(..))) or (execution(java.lang.String com.qianfeng.aop05..(..)))"/>
<aop:around method="myAround" pointcut-ref="pt"/>
<aop:before method="myBefore" pointcut-ref="pt"/>
<aop:after method="myAfter" pointcut-ref="pt"/>

        <aop:after-returning method="myReturn" pointcut-ref="pt" returning="object"/>
        <aop:after-throwing method="myThrow" pointcut-ref="pt" throwing="e"/>
    </aop:aspect>
</aop:config>

</beans>
aop:point-cut標(biāo)簽指定了切點(diǎn)担平,返回值示绊、包、類(lèi)暂论、方法與參數(shù)面褐,只匹配符合條件的方法,也就是對(duì)這些方法進(jìn)行代理空另,條件可以進(jìn)行與或非操作盆耽,分別使用and或&&、or或||、!進(jìn)行多條件匹配摄杂。
aop:before標(biāo)簽是前置通知坝咐,在切點(diǎn)方法執(zhí)行前通知
aop:around標(biāo)簽是環(huán)繞通知,在方法執(zhí)行前后都通知
aop:after標(biāo)簽是后置通知析恢,在方法執(zhí)行后通知
aop:after-returning標(biāo)簽是后置返回通知墨坚,方法執(zhí)行后的返回值進(jìn)行通知,returning參數(shù)所對(duì)應(yīng)的值是方法返回的參數(shù)用于放在method方法中的形參映挂。
aop:after-throwing是異常拋出通知泽篮,只有方法的執(zhí)行過(guò)程中出現(xiàn)了異常并且自己沒(méi)有處理的話(huà)才會(huì)執(zhí)行通知,throwing是捕獲到的異常用于放在對(duì)應(yīng)method方法中的形參
執(zhí)行順序:before >around before > 業(yè)務(wù)方法 > (after-throwing)(after returning > around after)>after柑船。不過(guò)順序也不固定:使用注解的話(huà)是環(huán)繞通知proceed方法之前部分先執(zhí)行帽撑,使用xml配置的話(huà)取決于aop:before和aop:around的配置順序
MyAspect.java

package com.qianfeng.aop05;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import java.util.Arrays;

public class MyAspect{
public void myBefore(JoinPoint jp){
System.out.println("args:"+ Arrays.toString(jp.getArgs()));
System.out.println("toString:"+jp.toString());
System.out.println("getTarget:"+jp.getTarget());
System.out.println("---------before----------");
}
public void myAfter(){
System.out.println("---------after----------");
}
public Object myAround(ProceedingJoinPoint pjp){
System.out.println("this is around-before");
try {
Object obj = pjp.proceed();
System.out.println("this is around-after"+obj);
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}

public void myReturn(JoinPoint jp,Object object){
    System.out.println("this is after returning "+object);
}

public void myThrow(JoinPoint jp,Throwable e){
    System.out.println("this is after throwing "+e.getMessage());
}

}

JoinPoint是連接點(diǎn)凹耙,會(huì)包含連接點(diǎn)的基本消息旱幼,通知所在的類(lèi)、通知的方法名坐桩、通知方法的入?yún)⒓夏嫖 etArgs()方法獲取方法的參數(shù)數(shù)組及塘,getTarget()獲取目標(biāo)對(duì)象信息
ProceedingJoinPoint是JoinPoint的子接口,該對(duì)象只用在A(yíng)round的切面方法中。
二锐极、第六種方式
第五種方式使用xml文件配置較多步驟笙僚,比較麻煩,第六種方式使用注解更為簡(jiǎn)便

beans6.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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qianfeng.aop06"/>
<aop:aspectj-autoproxy/>
</beans>
相較于第五種方式灵再,第六種方式主要的不同就是可以實(shí)現(xiàn)自動(dòng)代理肋层,xml文件的配置有以下不同:

引入了三個(gè)命名空間,和context有關(guān)
添加了context:component-scan標(biāo)簽翎迁,用于掃描組件槽驶,base-package指定了需要進(jìn)行組件掃描的包
aop:aspectj-autoproxy標(biāo)簽指定了實(shí)現(xiàn)自動(dòng)代理
MyAspect.java

package com.qianfeng.aop06;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
@Component
@Aspect
public class MyAspect{
@Pointcut(value = "execution(boolean com.qianfeng.aop06..(..))")
public void setAll(){}
@Before(value = "execution(java.lang.String com.qianfeng.aop06..(..))")
public void myBefore(JoinPoint jp){
System.out.println("args:"+ Arrays.toString(jp.getArgs()));
System.out.println("toString:"+jp.toString());
System.out.println("getTarget:"+jp.getTarget());
System.out.println("---------before----------");
}
@After("setAll()")
public void myAfter(){
System.out.println("---------after----------");
}
@Around("setAll()")
public Object myAround(ProceedingJoinPoint pjp){
System.out.println("this is around-before");
try {
Object obj = pjp.proceed();
System.out.println("this is around-after"+obj);
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
@AfterReturning(value = "setAll()",returning = "object")
public void myReturn(JoinPoint jp,Object object){
System.out.println("this is after returning "+object);
}
@AfterThrowing(value = "setAll()",throwing = "e")
public void myThrow(JoinPoint jp,Throwable e){
System.out.println("this is after throwing "+e.getMessage());
}
}

@Component注解標(biāo)注當(dāng)前類(lèi)是一個(gè)組件,在掃描時(shí)會(huì)被掃描進(jìn)來(lái)
@Aspect標(biāo)注當(dāng)前類(lèi)是一個(gè)切面類(lèi)
@PointCut標(biāo)注切點(diǎn)鸳兽,為了避免相同的匹配規(guī)則被定義多處掂铐,專(zhuān)門(mén)定義該方法設(shè)置執(zhí)行的匹配規(guī)則,各個(gè)方法自行調(diào)用即可
@Before標(biāo)注前置通知
@After標(biāo)注后置通知
@Around標(biāo)注環(huán)繞通知
@AfterReturning標(biāo)注后置返回通知
@AfterThorwing標(biāo)注拋出異常通知
注解的執(zhí)行順序稍有不同:(after throwing)around before>before > 業(yè)務(wù)方法 > around-after > after >after returning
三揍异、第七種方式
第七種方式使用BeanPostProcessor方式實(shí)現(xiàn)全陨。該接口我們也叫后置處理器,作用是在Bean對(duì)象在實(shí)例化和依賴(lài)注入完畢后衷掷,在顯示調(diào)用初始化方法的前后添加我們自己的邏輯辱姨。注意是Bean實(shí)例化完畢后及依賴(lài)注入完成后觸發(fā)的。

Spring中Bean的運(yùn)行順序:

Spring IoC容器實(shí)例化Bean(注意實(shí)例化與初始化的區(qū)別戚嗅,實(shí)例化是在內(nèi)存中開(kāi)辟空間雨涛,初始化是對(duì)變量賦值)
調(diào)用BeanPostProcesson的postProcessBeforeInitialization方法
調(diào)用Bean實(shí)例的初始化方法
調(diào)用BeanPostProcesson的postProcessAfterInitialization方法
beans7.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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qianfeng.aop07"/>
<bean class="com.qianfeng.aop07.MyBeanPostProcessor"/>
</beans>
context:component-scan用于指定組件掃描枢舶,base-package指定需要掃描的包,只有打上@component注解的類(lèi)才會(huì)被掃描
bean class="com.qianfeng.aop07.MyBeanPostProcessor"指定BeanPostProcessor的Factory hook替久,讓每個(gè)bean對(duì)象初始化是自動(dòng)回調(diào)該對(duì)象中的回調(diào)方法
MyBeanPostProcessor.java

package com.qianfeng.aop07;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("this is before "+bean);
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("this is after");
    return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            MyAspect ma = new MyAspect();

            ma.before();

            Object obj = method.invoke(bean, args);

            ma.after();

            return obj;
        }
    });

}

}

這個(gè)類(lèi)實(shí)現(xiàn)了BeanPostProcessor接口凉泄,重寫(xiě)了postProcessBeforeInitialization()與postProcessAfterInitialization()方法,這兩個(gè)方法的第一個(gè)參數(shù)是目標(biāo)對(duì)象的bean蚯根,返回值都是Object類(lèi)型后众,因?yàn)榘裝ean從IoC容器中取出來(lái)還需要放回去,如果返回null的話(huà)會(huì)報(bào)異常
postProcessBeforeInitialization()是在初始化方法之前執(zhí)行颅拦,postProcessAfterInitialization()是在初始化方法之后執(zhí)行
配置了包掃描之后蒂誉,該類(lèi)會(huì)初始化兩個(gè)對(duì)象EventListenerMethodProcessor和DefaultEventListenerFactory,再外加我們自己的組件對(duì)象 距帅, 所以會(huì)發(fā)現(xiàn)有三個(gè)before打印右锨。
return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() ...)這條語(yǔ)句的作用就是將代理后的對(duì)象放進(jìn)IoC容器中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碌秸,一起剝皮案震驚了整個(gè)濱河市陡蝇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哮肚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件广匙,死亡現(xiàn)場(chǎng)離奇詭異允趟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)鸦致,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)潮剪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人分唾,你說(shuō)我怎么就攤上這事抗碰。” “怎么了绽乔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵弧蝇,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我折砸,道長(zhǎng)看疗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任睦授,我火速辦了婚禮两芳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘去枷。我一直安慰自己怖辆,他們只是感情好是复,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著竖螃,像睡著了一般淑廊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上斑鼻,一...
    開(kāi)封第一講書(shū)人閱讀 50,050評(píng)論 1 291
  • 那天蒋纬,我揣著相機(jī)與錄音,去河邊找鬼坚弱。 笑死蜀备,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荒叶。 我是一名探鬼主播碾阁,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼些楣!你這毒婦竟也來(lái)了脂凶?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤愁茁,失蹤者是張志新(化名)和其女友劉穎蚕钦,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鹅很,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘶居,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了促煮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邮屁。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖菠齿,靈堂內(nèi)的尸體忽然破棺而出佑吝,到底是詐尸還是另有隱情,我是刑警寧澤绳匀,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布芋忿,位于F島的核電站,受9級(jí)特大地震影響疾棵,放射性物質(zhì)發(fā)生泄漏盗飒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一陋桂、第九天 我趴在偏房一處隱蔽的房頂上張望逆趣。 院中可真熱鬧,春花似錦嗜历、人聲如沸宣渗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)痕囱。三九已至田轧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鞍恢,已是汗流浹背傻粘。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帮掉,地道東北人弦悉。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蟆炊,于是被迫代替她去往敵國(guó)和親稽莉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容