2020-03-16 Spring-Aop

簡(jiǎn)介

AOP:面向切面編程,是OOP的擴(kuò)展和延申祈纯,解決OOP中遇到的問題
可以進(jìn)行權(quán)限校驗(yàn)糠爬,日志記錄,性能監(jiān)控刽脖,事務(wù)校驗(yàn)
Spring底層的AOP實(shí)現(xiàn)原理:動(dòng)態(tài)代理
JDK動(dòng)態(tài)代理 :只能對(duì)實(shí)現(xiàn)了接口的類產(chǎn)生代理
Cglib動(dòng)態(tài)代理(類似于Javassist第三方代理技術(shù)):對(duì)沒有實(shí)現(xiàn)接口的類產(chǎn)生代理對(duì)象羞海,生成子
對(duì)象

兩種動(dòng)態(tài)代理

JDK動(dòng)態(tài)代理實(shí)例

1.建立一個(gè)接口:

public interface UserDao {
    public void insert();
    public void update();
}

2.接口實(shí)現(xiàn)類

public class UserDaoImpl implements UserDao {
    @Override
    public void insert() {
        System.out.println("insert方法");
    }
    @Override
    public void update() {
        System.out.println("update方法");
    }
}

3.編寫代理類JdkProxy

public class JdkProxy{
    //將被增強(qiáng)的對(duì)象傳遞到代理當(dāng)中
    private UserDao userDao;
    public JdkProxy(UserDao userDao) {
        this.userDao = userDao;
    }
    public UserDao creatProxy() {
        UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
        return userDaoProxy;
    }
}
  1. 實(shí)現(xiàn)InvocationHandler接口,并重寫其中方法曲管,用于權(quán)限管理
public class JdkProxy implements InvocationHandler{
        ······
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if("insert".equals(method.getName())) {
            System.out.println("權(quán)限增強(qiáng)");
            return method.invoke(userDao, args);
        }
        return method.invoke(userDao, args);
    }

5.測(cè)試類

    @Test
    public void demo1() {
        UserDao userDao=new UserDaoImpl();
        //創(chuàng)建代理
        UserDao proxy = new JdkProxy(userDao).creatProxy();
        proxy.insert();
        proxy.update();
    }

Cglib動(dòng)態(tài)代理

第三方開源代碼生成類庫(kù)却邓,動(dòng)態(tài)添加類的屬性和方法
1.編寫接口和測(cè)試類(同上)
2.編寫代理類CglibProxy

public class CglibProxy {
    private UserDaoImpl userDaoImpl;
    public CglibProxy(UserDaoImpl userDaoImpl) {
        this.userDaoImpl=userDaoImpl;
    }
    public UserDaoImpl createProxy() {
        //1.創(chuàng)建Cglib的代理對(duì)象
        Enhancer enhancer = new Enhancer();
        //2.設(shè)置父類
        enhancer.setSuperclass(userDaoImpl.getClass());
        //3.設(shè)置回調(diào)
        enhancer.setCallback(this);
        //4.創(chuàng)建代理
        UserDaoImpl proxy=(UserDaoImpl) enhancer.create();
        return  proxy;
    }

3.CglibProxy 繼承MethodInterceptor類,并重寫其中方法

public class CglibProxy implements MethodInterceptor{
    ······
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 判斷是否是insert方法
        if("insert".equals(method.getName())) {
            //增強(qiáng)
            System.out.println("權(quán)限校驗(yàn)");
            return methodProxy.invokeSuper(proxy, args);
        }
        return methodProxy.invokeSuper(proxy, args);
    }
}

4.測(cè)試類

    @Test
    public void demo1() {
        UserDaoImpl userDao=new UserDaoImpl();
        //創(chuàng)建代理
        UserDaoImpl proxy = new CglibProxy(userDao).createProxy();
        proxy.insert();
        proxy.update();
    }

Spring的AOP開發(fā)

簡(jiǎn)介

AOP思想最早是由AOP聯(lián)盟組織提出的院水,Spring是使用這種思想最好的框架
Spring的AOP有自己實(shí)現(xiàn)的方式(非常繁瑣)AspectJ是一個(gè)AOP框架腊徙,Spring引入了AspectJ作為自身開發(fā)

相關(guān)代碼編寫

1.新建切面類简十,并在切面類中MethodInterceptor類(環(huán)繞通知)

//環(huán)繞通知
public class MyAspectXML implements MethodInterceptor{
    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        System.out.println("0000000000");
        Object obj=arg0.proceed();
        System.out.println("0000000000");
        return obj;
    }
 }

2.在xml文件中配置

<!-- 配置目標(biāo)對(duì)象,被增強(qiáng)的對(duì)象-->
<bean id="productDao" class="com.zut.aopTest.ProductDaoImpl"></bean>
<!-- 將切面類交給Spring管理 -->
<bean id="myAspect" class="com.zut.aopTest.MyAspectXML"></bean>

3.在xml文件中配置通知

<!-- 創(chuàng)建代理對(duì)象  默認(rèn)JDK動(dòng)態(tài)代理  如果沒有proxyInterfaces 則默認(rèn)cglib-->
    <bean class="org.springframework.aop.framework.ProxyFactoryBean" name="proxyBean">
        <property name="targetName" value="productDao"></property>
        <!-- 攔截器名字 -->
        <property name="interceptorNames" value="myAspect">
            <!-- 如果通知在多個(gè)類中 -->
            <!-- <array>
                <value></value>
            </array> -->
        </property>
            <property name="proxyInterfaces" value="com.zut.aopTest.ProductDao"></property>
    </bean>

4.編寫測(cè)試類

public void demo1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ProductDao productDao=context.getBean("proxyBean",ProductDao.class);
        productDao.save();
}

前置通知接口:MethodBrforeAdvice
后置通知接口:AfterReturningAdvice 注意: 有異常時(shí)后置通知不執(zhí)行
異常通知接口:ThrowsAdvice
最終通知接口:AfterAdvice

在此方式下撬腾,xml文件可以采用自動(dòng)織入編寫

1.xml文件

<!-- 配置目標(biāo)對(duì)象螟蝙,被增強(qiáng)的對(duì)象 -->
    <bean id="productDao" class="com.zut.aopTest.ProductDaoImpl"></bean>
    <!-- 將切面類交給Spring管理 -->
    <bean id="myAspect" class="com.zut.aopTest.MyAspectXML"></bean>
<aop:config>
        <aop:pointcut expression="execution(* com.zut.springAOP.UserImpl.*(..))" id="pointcut"/>
        <aop:advisor advice-ref="myAspect" pointcut-ref="pointcut"/>
    </aop:config>
 //id 與 pointcut-ref 相等

2.測(cè)試類

public void demo1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        ProductDao productDao=context.getBean("productDao",ProductDao.class);
        productDao.save();
}

采用AspectJ的XML的方式

相關(guān)配置文件

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.5.3</version>
</dependency>

xml文件

clipboard.png

相關(guān)代碼編寫

1.編寫接口和測(cè)試類
2.編寫切面類

public class MyAspectXML {
    public void checkPri() {
        System.out.println("權(quán)限校驗(yàn)。民傻。胰默。。漓踢。初坠。。彭雾。碟刺。");
    }
}

3.在xml文件里進(jìn)行配置

<!-- 配置目標(biāo)對(duì)象,被增強(qiáng)的對(duì)象 -->
    <bean id="productDao" class="com.aopTest.ProductDaoImpl"></bean>
    <!-- 將切面類交給Spring管理 -->
    <bean id="myAspect" class="com.aopTest.MyAspectXML"></bean>
    <!-- 通過(guò)AOP的配置實(shí)現(xiàn)對(duì)目標(biāo)產(chǎn)生代理 -->
    <aop:config>
        <!-- 表達(dá)式配置那些類哪些方法需要進(jìn)行增強(qiáng)   ()里面只寫參數(shù)類型  可以寫成 save(int ,String) and args(a,b)  -->
        <aop:pointcut expression="execution(* com.aopTest.ProductDaoImpl.save(..))" id="pointcut1"/>
        <!-- 配置切面  myAspect指向切面 與上文要對(duì)應(yīng)上  checkPri 切面類里的方法名-->
        <aop:aspect ref="myAspect">
                      <!--匹配參數(shù)  這里的名字要一致-->
            <aop:before method="checkPri" pointcut-ref="pointcut1" arg-names="a"/></aop:aspect>   
    </aop:config>
</beans>

4.測(cè)試類

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:Spring-config.xml")
public class SpringDemo1 {
    @Resource(name="productDao")
    private ProductDao productDao;
    @Test
    public void demo1() {
        productDao.save();
        productDao.update();
        productDao.find();
        productDao.delete();
    }
}

通知類型

前置通知

在目標(biāo)方法執(zhí)行之前執(zhí)行此操作
1.xml文件

<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<aop:before method="checkPri" pointcut-ref="pointcut1"/>
</aop:aspect>

2.獲得切入點(diǎn)信息(幾種通知均可實(shí)現(xiàn))
在切入類中

public void checkPri(JoinPoint joinPoint) {
        System.out.println("權(quán)限校驗(yàn)薯酝。半沽。。吴菠。者填。。做葵。占哟。。"+joinPoint);
}

后置通知

在目標(biāo)方法之后執(zhí)行的操作
1.在xml文件中

<aop:pointcut expression="execution(* com.aopTest.ProductDaoImpl.delete(..))" id="pointcut2"/>

<!-- 后置通知 -->
<aop:after-returning method="write" pointcut-ref="pointcut2" returning="result"/>
//returning表示獲取返回值

2.獲得方法返回值
在切入類中

/**
 * 后置通知
 */
    public void write(Object result) {
        System.out.println("日志通知酿矢。榨乎。。瘫筐。蜜暑。。策肝。肛捍。。之众。"+result);
    }
 //這里的reult必須與前面配置里的returning一致

環(huán)繞通知

在目標(biāo)方法執(zhí)行之前和之后進(jìn)行操作
1.xml文件

<aop:pointcut expression="execution(* com.aopTest.ProductDaoImpl.update(..))" id="pointcut3"/>

<!-- 環(huán)繞通知 -->
<aop:around method="around" pointcut-ref="pointcut3"/>

2.在切入類

/**
 * 環(huán)繞通知
 * 性能監(jiān)控
 * @throws Throwable 
 */
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("環(huán)繞通知前拙毫。。棺禾。");
    Object obj=joinPoint.proceed();
    System.out.println("環(huán)繞通知后缀蹄。。。");
    return obj;
}

異常拋出通知

在程序出現(xiàn)異常時(shí)袍患,進(jìn)行的操作
1.xml文件中

<aop:pointcut expression="execution(* com.aopTest.ProductDaoImpl.find(..))" id="pointcut4"/>

<!-- 異常通知 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4" throwing="ex"/>
//throwing:得到異常類型

2.切入類

/**
 * 異常拋出
 */
public void afterThrowing(Throwable ex) {
    System.out.println("異常拋出坦康。。诡延。"+ex);
}
 //ex必須與上文配置中的throwing一致

最終通知

無(wú)論代碼是否有異常滞欠,總是會(huì)執(zhí)行,相當(dāng)于finally代碼塊
1.xml文件里

<!-- 最終通知 -->
<aop:after method="after" pointcut-ref="pointcut4"/>

2.切面類

/**
* 最終通知
*/
public void after() {
    System.out.println("最終通知肆良。筛璧。。...");
}

spring的切入點(diǎn)表達(dá)式寫法

基于execution的函數(shù)完成的
語(yǔ)法:
[訪問修飾符] 方法返回值 包名.類名.方法名(參數(shù))
public void com.zut.aopTest.ProductDao.save(..)
星號(hào)(*)代表任意惹恃,參數(shù)不能寫 * 夭谤,可以寫 ..
*****Dao.save(..)
*com.zut.aopTest.ProductDao+save(..)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市巫糙,隨后出現(xiàn)的幾起案子朗儒,更是在濱河造成了極大的恐慌,老刑警劉巖参淹,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件醉锄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡浙值,警方通過(guò)查閱死者的電腦和手機(jī)恳不,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)开呐,“玉大人烟勋,你說(shuō)我怎么就攤上這事】鸶叮” “怎么了卵惦?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)家妆。 經(jīng)常有香客問我鸵荠,道長(zhǎng),這世上最難降的妖魔是什么伤极? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮姨伤,結(jié)果婚禮上哨坪,老公的妹妹穿的比我還像新娘。我一直安慰自己乍楚,他們只是感情好当编,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著徒溪,像睡著了一般忿偷。 火紅的嫁衣襯著肌膚如雪金顿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天鲤桥,我揣著相機(jī)與錄音揍拆,去河邊找鬼。 笑死茶凳,一個(gè)胖子當(dāng)著我的面吹牛嫂拴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贮喧,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼筒狠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了箱沦?” 一聲冷哼從身側(cè)響起辩恼,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谓形,沒想到半個(gè)月后运挫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡套耕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年谁帕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冯袍。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡匈挖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出康愤,到底是詐尸還是另有隱情儡循,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布征冷,位于F島的核電站择膝,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏检激。R本人自食惡果不足惜肴捉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望叔收。 院中可真熱鬧齿穗,春花似錦、人聲如沸饺律。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至脖卖,卻和暖如春乒省,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背畦木。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工袖扛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馋劈。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓攻锰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親妓雾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娶吞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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

  • 本章內(nèi)容: 面向切面編程的基本原理 通過(guò)POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,147評(píng)論 0 9
  • **** AOP 面向切面編程 底層原理 代理!P狄觥妒蛇! 今天AOP課程1、 Spring 傳統(tǒng) AOP2楷拳、 Spri...
    luweicheng24閱讀 1,367評(píng)論 0 1
  • 一绣夺、AOP 簡(jiǎn)介 AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方...
    leeqico閱讀 796評(píng)論 0 1
  • 1.概述 Aop(Aspect Oriented Programming),即面向切面編程欢揖,這是面向?qū)ο笏枷氲囊环N...
    Tian_Peng閱讀 3,539評(píng)論 0 2
  • 很多次想要寫點(diǎn)東西她混,每次卻都不了了之烈钞,其一是因?yàn)樘珣校涠闶窃S久未接觸坤按,提筆生疏毯欣。今天偶然看到了一個(gè)同學(xué)發(fā)的...
    小茗姑娘閱讀 246評(píng)論 3 1