Spring+3.x企業(yè)應(yīng)用開發(fā)實(shí)戰(zhàn)筆記一使用增強(qiáng)(Advice)

1、創(chuàng)建增強(qiáng)類型

spring的增強(qiáng)類型為5個(gè)
1、前置,后置,環(huán)繞,異常,引介,這些增強(qiáng)接口都有一些方法,
在接口方法中定義橫切邏輯,就可以將它們織入到目標(biāo)類方法的相應(yīng)連接點(diǎn)的位置。
我們這里只看前置和環(huán)繞。
我們先來溫故一下,spring如何使用jdk動(dòng)態(tài)代理實(shí)現(xiàn)aop
1、把業(yè)務(wù)邏輯里的橫切邏輯拿出來只留下業(yè)務(wù)邏輯
2、創(chuàng)建橫切邏輯類,實(shí)現(xiàn)InvocationHandler接口,并給構(gòu)造方法傳入一個(gè)目標(biāo)類對(duì)象Object target
3、實(shí)現(xiàn)接口里的方法invoke(Object proxy,Method method,Object[] args),
在invoke方法中調(diào)用編寫橫切邏輯,然后調(diào)用method.invoke(target,args)采用反射機(jī)制調(diào)用業(yè)務(wù)類方法,即目標(biāo)類對(duì)象方法。
4、測(cè)試類,聲明一個(gè)業(yè)務(wù)類接口target,并業(yè)務(wù)類實(shí)現(xiàn)類實(shí)例化它;聲明一個(gè)增強(qiáng)類(織入器)handler并實(shí)例化(織入器就是整合和業(yè)務(wù)邏輯和橫切邏輯);
在聲明一個(gè)業(yè)務(wù)類接口proxy,并調(diào)用Proxy的靜態(tài)方法newProxyInstance實(shí)例化一個(gè)整合后的代理對(duì)象。該方法有三個(gè)參數(shù),第一個(gè)是目標(biāo)類的類加載器,第二個(gè)
是創(chuàng)建代理實(shí)例所實(shí)現(xiàn)的接口,第三個(gè)是織入器。
這里沒有用到spring配置文件,完全硬編碼。
硬編碼就是把代碼寫死,如果要改功能就只能修改代碼,軟編碼就是不需要修改代碼,只需要修改配置就可以修改功能。

spring底層就是采用動(dòng)態(tài)代理實(shí)現(xiàn)aop的
怎么使用增強(qiáng)類型實(shí)現(xiàn)aop

spring使用前置增強(qiáng):

  1. 創(chuàng)建一個(gè)前置增強(qiáng)類并且實(shí)現(xiàn)MethodBeforeAdvice接口,實(shí)現(xiàn)一個(gè)方法before(Method method,Object[] args,Object target) throws Throwable
    method為目標(biāo)類方法,args為目標(biāo)類方法的入?yún)ⅲ瑃arget為目標(biāo)類實(shí)例。然后直接在before()方法里寫橫切邏輯代碼,不再需要調(diào)用method.invoke,因?yàn)檫@里已經(jīng)是前置通知了。
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

/*
 * 前置增強(qiáng)類
 */
public class LogBeforeAdvice implements MethodBeforeAdvice {

    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        
        System.out.println("我是前置日志.......");
    }

}
  1. 采用硬編碼的方式測(cè)試前置通知,聲明一個(gè)業(yè)務(wù)邏輯接口target,業(yè)務(wù)邏輯實(shí)現(xiàn)類實(shí)例化它;聲明一個(gè)前置增強(qiáng)類advice并實(shí)例化它;聲明一個(gè)
    spring提供的代理工廠ProxyFactory,pf并實(shí)例化它;然后設(shè)置代理目標(biāo)pf.setTarget(target),為代理目標(biāo)添加增強(qiáng)pf.addAdvice(advice);然后聲明一個(gè)業(yè)務(wù)服務(wù)接口,并用pf.getProxy()實(shí)例化它。解析PrxoyFactory以后再說。
         /*
        采用硬編碼方式測(cè)試前置通知
        */
        ForumService target = new ForumServiceImpl();
        LogBeforeAdvice advice = new LogBeforeAdvice();
        ProxyFactory pf = new ProxyFactory();
        pf.setTarget(target);
        pf.addAdvice(advice);
        ForumService proxy = (ForumService) pf.getProxy();
        proxy.removeForum(1);
  1. 采用spring配置方式
    1、聲明增強(qiáng)類bean,advice
    2、聲明業(yè)務(wù)邏輯實(shí)現(xiàn)類bean,target
    3、聲明ProxyFactoryBean,pf
    并且傳參,proxyInterfaces指定代理接口一般只有業(yè)務(wù)邏輯接口,如果是多個(gè)接口,使用<list>元素;interceptorNames指定使用的增強(qiáng)bean,target;target-ref指定對(duì)哪個(gè)bean進(jìn)行代理即對(duì)哪個(gè)業(yè)務(wù)實(shí)現(xiàn)類bean進(jìn)行代理,這里是target。
<?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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    <bean id="advice" class="com.ljs.springaop.advice.LogBeforeAdvice"/>
    <bean id="target" class="com.ljs.springaop.advice.ForumServiceImpl"/>
    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="target"/>
        <property name="interceptorNames">
            <value>advice</value>
        </property>
        <property name="proxyInterfaces" value="com.ljs.springaop.advice.ForumService"/>
    </bean>
 </beans>
/*
        采用軟編碼方式測(cè)試前置通知
        */
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "com/ljs/springaop/advice/spring.xml");
        ForumService proxy2 = (ForumService) context.getBean("proxy");
        proxy2.removeForum(1);

spring使用環(huán)繞增強(qiáng):

  1. 創(chuàng)建一個(gè)環(huán)繞增強(qiáng)類并且實(shí)現(xiàn)MethodInterceptor,這個(gè)有點(diǎn)像spring使用jdk動(dòng)態(tài)代理實(shí)現(xiàn)aop,環(huán)繞綜合實(shí)現(xiàn)了前置和后置兩者的功能。然后實(shí)現(xiàn)該方法,invoke(MethodInvocation invocation) throws Throwable,注意這個(gè)接口是org.aopalliance.intercept.MethodInterceptor,別搞錯(cuò)了。
  2. 再該方法中需要先獲取該目標(biāo)方法的參數(shù),用Object[] args=invocation.getArguments()然后再傳值String clientName = (String)args[0]
  3. 在編寫橫切邏輯
  4. 通過反射機(jī)制調(diào)用目標(biāo)方法Object obj = invocation.proceed();
  5. 編寫橫切邏輯
  6. return obj;
  7. 采用spring配置方式,增強(qiáng)bean,業(yè)務(wù)邏輯實(shí)現(xiàn)類bean,spring代理工廠bean,然后跟前置一樣傳參。
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;


public class LogInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object[] args = invocation.getArguments();//目標(biāo)方法入?yún)?        int number = (int) args[0];
        System.out.println("我是環(huán)繞log1,你想刪除的是"+number);//在目標(biāo)方法前執(zhí)行調(diào)用
        Object obj = invocation.proceed();//通過反射機(jī)制調(diào)用目標(biāo)方法
        System.out.println("我是環(huán)繞log2");//在目標(biāo)方法后執(zhí)行調(diào)用
        return obj;
    }

}
<?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"
    xmlns:tx="http://www.springframework.org/schema/tx"
    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
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    <bean id="advice" class="com.ljs.springaop.advice.interceptor.LogInterceptor"/>
    <bean id="target" class="com.ljs.springaop.advice.interceptor.ForumServiceImpl"/>
    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="target"/>
        <property name="interceptorNames">
            <value>advice</value>
        </property>
        <property name="proxyInterfaces" value="com.ljs.springaop.advice.interceptor.ForumService"/>
    </bean>
 </beans>
public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext(
                "com/ljs/springaop/advice/interceptor/spring.xml");
        ForumService proxy = (ForumService) context.getBean("proxy");
        proxy.removeForum(1);

    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,275評(píng)論 6 342
  • 什么是Spring Spring是一個(gè)開源的Java EE開發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,773評(píng)論 1 133
  • 這部分主要是開源Java EE框架方面的內(nèi)容,包括Hibernate、MyBatis、Spring、Spring ...
    雜貨鋪老板閱讀 1,566評(píng)論 0 2
  • 文| 戈多 大雨浸泡城市的瞬間 將陸海變遷重演 行走動(dòng)物在被動(dòng)中 慌亂進(jìn)化 抵抗淘汰風(fēng)險(xiǎn) 越奮力越掙扎越想變強(qiáng)大...
    戈多歸來閱讀 491評(píng)論 4 3

友情鏈接更多精彩內(nèi)容