1. 程式人生 > >Spring 四種切面技術(攔截)、獲取Spring容器的兩種辦法

Spring 四種切面技術(攔截)、獲取Spring容器的兩種辦法

Spring AOP程式設計

切面(Aspect):簡單的理解就是把那些與核心業務無關的程式碼提取出來,進行封裝成一個或幾個模組用來處理那些附加的功能程式碼。(如日誌,事務,安全驗證)我們把這個模組的作用理解為一個切面,其實切面就是我們寫一個類,這個類中的程式碼原來是在業務模組中完成的,現在單獨成一個或幾個類。在業務模組需要的時候才織入。

連線點(Joinpoint):在程式執行過程中某個特定的點,比如某方法呼叫的時候或者處理異常的時候。 在Spring AOP中,一個連線點總是代表一個方法的執行。通過宣告一個JoinPoint型別的引數可以使通知(Advice)的主體部分獲得連線點資訊。

切入點(Pointcut):本質上是一個捕獲連線點的結構。在AOP中,可以定義一個pointcut,來捕獲相關方法的呼叫

織入(Weaving):把切面(aspect)連線到其它的應用程式型別或者物件上,並建立一個被通知(advised)的物件。這些可以在編譯時,類載入時和執行時完成。Spring和其它純Java AOP框架一樣,在執行時完成織入。

通知(Advice):在切面的某個特定的連線點(Joinpoint)上執行的動作。通知有各種型別,其中包括“around”、“before”和“after”等通知。通知的型別將在後面部分進行討論。許多AOP框架,包括Spring,都是以攔截器做通知模型,並維護一個以連線點為中心的攔截器鏈。

通知的型別:

前置通知(Before advice):在某連線點(join point)之前執行的通知,但這個通知不能阻止連線點前的執行(除非它丟擲一個異常)。

返回後通知(After returning advice):在某連線點(join point)正常完成後執行的通知:例如,一個方法沒有丟擲任何異常,正常返回。

丟擲異常後通知(After throwing advice):在方法丟擲異常退出時執行的通知。

後置通知(After(finally)advice):當某連線點退出的時候執行的通知(不論是正常返回還是異常退出)。

環繞通知(Around Advice):包圍一個連線點(join point)的通知,如方法呼叫。這是最強大的一種通知型別。 環繞通知可以在方法呼叫前後完成自定義的行為。它也會選擇是否繼續執行連線點或直接返回它們自己的返回值或丟擲異常來結束執行。

1.RegexpMethodPointcutAdvisor切面技術
純Java的方式實現切面(攔截)技術
下面演示程式碼:

public class AopDemo {
    @Test//純Java的方式實現切面(攔截)技術
    public void demo1(){
        Person p=new Person();
        ProxyFactory factory=new ProxyFactory(); //該類的功能沒有ProxyFactoryBean強
        factory.setTarget(p);//1 給代理工廠一個原型物件
        //切面 = 切點 + 通知
        //切點
        JdkRegexpMethodPointcut pointcut=new JdkRegexpMethodPointcut();
        pointcut.setPattern("cn.hncu.spring4x.domain.Person.run");
        //      pointcut.setPattern(".*run.*");ProxyFactory對setPattern無效
        Advice advice=new MethodInterceptor() {

            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("前面攔截");
                Object obj=invocation.proceed();
                System.out.println("後面攔截");
                return obj;
            }
        };
        //切面 = 切點 + 通知
        Advisor advisor=new DefaultPointcutAdvisor(pointcut, advice);

        factory.addAdvice(advice);

        Person p2=(Person) factory.getProxy();
//      p2.run();
//      p2.run(5);
        p2.say();
    }
    @Test//純Java的方式實現切面(攔截)技術
    public void demo2(){
        ProxyFactoryBean factoryBean=new ProxyFactoryBean();
        factoryBean.setTarget(new Person());
        //切面 = 切點 + 通知
        //切點
        JdkRegexpMethodPointcut pointcut=new JdkRegexpMethodPointcut();
        pointcut.setPattern(".*run.*");

        //通知  前切面---不需要放行,原方法也能執行
        Advice beforeAdvice=new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target)
                    throws Throwable {
                System.out.println("beforeAdvice攔截");//正則表示式有效
            }
        };
        Advice afterReturning=new AfterReturningAdvice() {
            @Override
            public void afterReturning(Object returnValue, Method method,
                    Object[] args, Object target) throws Throwable {
                System.out.println("afterReturning");
            }
        };

        Advice aroundAdvice=new MethodInterceptor() {

            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("前面攔截");
                Object obj=invocation.proceed();
                System.out.println("後面攔截");
                return obj;
            }
        };
        Advisor advisor1=new DefaultPointcutAdvisor(pointcut, beforeAdvice);
        Advisor advisor2=new DefaultPointcutAdvisor(pointcut, afterReturning);
        Advisor advisor3=new DefaultPointcutAdvisor(pointcut, aroundAdvice);
        factoryBean.addAdvisors(advisor1,advisor2,advisor3);
        //2 給代理工廠一個切面 ---注意,新增的順序的攔截動作執行的順序是有關係的!!!
        //先加的切面,如果攔前面,就攔在最前面,如果攔後面,就攔在最後面.
        Person p = (Person) factoryBean.getObject(); //3 從代理工廠中獲取一個代理後的物件
        //p.run();
        //p.run(0);
        p.say();
    }

}

下面演示5種方式配置檔案AOP

通知:AroundAdvice.java


import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("前面攔攔....");
        Object resObj = invocation.proceed();//放行
        System.out.println("後面攔攔.....");
        return resObj;
    }

}

測試程式碼:



import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AopXmlDemo {
    @Test//採用配置檔案的方式使用切面攔截
    public void demo1(){
        ApplicationContext act=new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/1.xml");
        Cat cat=act.getBean("catProxide",Cat.class);//要從catProxide返回
        cat.run();
        cat.say();
        cat.run(6);
    }
    @Test//把切點和通知配置成 切面的內部bean
    public void demo2(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/2.xml");
        Cat cat = ctx.getBean("catProxide",Cat.class);
        cat.run();
        cat.say();
        cat.run(7);
    }
    @Test//直接在切面bean中配置“切點的正則表示式”,省去“切點bean”的配置
    public void demo3(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/3.xml");
        Cat cat = ctx.getBean("catProxide",Cat.class);
        cat.run();
        cat.say();
        cat.run(7);
    }
    @Test//自動代理
    public void demo4(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/4.xml");
        Cat cat = ctx.getBean(Cat.class);
        cat.run();
        cat.say();
        cat.run(7);
    }
    @Test//自己寫的自動代理
    public void demo5(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("cn/hncu/spring4x/aop/5.xml");
        Cat cat = ctx.getBean("cat",Cat.class);
//      cat.run();
//      cat.say();
//      cat.run(7);
    }

}

v1.xml:

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>
    <!-- 切點 -->
    <bean class="org.springframework.aop.support.JdkRegexpMethodPointcut" id="pointcut">
        <property name="pattern" value=".*run.*"></property>
    </bean>
    <!-- 通知 ,要自己寫-->
    <bean class="cn.hncu.spring4x.aop.AroundAdvice" id="advice"></bean>

    <!-- 切面=切點+通知 -->
    <bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="advisor">
        <property name="advice" ref="advice"></property>
        <property name="pointcut" ref="pointcut"></property>
    </bean>

    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="catProxide">
        <property name="target" ref="cat"></property>
        <property name="interceptorNames">
            <list>
                <value>advisor</value>
            </list>
        </property>
    </bean>
</beans>

v2.xml

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>

    <!-- 切面=切點+通知 (把切點和通知寫成內部bean)-->
    <bean class="org.springframework.aop.support.DefaultPointcutAdvisor" id="advisor">
        <property name="advice">
            <bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
        </property>
        <property name="pointcut">
            <bean class="org.springframework.aop.support.JdkRegexpMethodPointcut">
             <property name="patterns">
                <list>
                    <value>.*run.*</value>
                    <value>.*say.*</value>
                </list>
             </property>

            </bean>
        </property>
    </bean>

    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="catProxide">
        <property name="target" ref="cat"></property>
        <property name="interceptorNames">
            <list>
                <value>advisor</value>
            </list>
        </property>
    </bean>
</beans>

v3.xml

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>

    <!--//直接在切面bean中配置“切點的正則表示式”,省去“切點bean”的配置 用到這個類 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
        <property name="advice">
            <bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
        </property>
        <property name="patterns">
            <list>
                <value>.*run.*</value>
            </list>
        </property>
    </bean>

    <bean class="org.springframework.aop.framework.ProxyFactoryBean" id="catProxide">
        <property name="target" ref="cat"></property>
        <property name="interceptorNames">
            <list>
                <value>advisor</value>
            </list>
        </property>
    </bean>
</beans>

v4.xml

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>

    <!--//直接在切面bean中配置“切點的正則表示式”,省去“切點bean”的配置 用到這個類 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
        <property name="advice">
            <bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
        </property>
        <property name="patterns">
            <list>
                <value>.*run.*</value>
            </list>
        </property>
    </bean>
    <!-- 自動代理 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>

v5.xml

<!--?xml version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean class="cn.hncu.spring4x.aop.Cat" id="cat"></bean>

    <!--//直接在切面bean中配置“切點的正則表示式”,省去“切點bean”的配置 用到這個類 org.springframework.aop.support.RegexpMethodPointcutAdvisor -->
    <bean class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" id="advisor">
        <property name="advice">
            <bean class="cn.hncu.spring4x.aop.AroundAdvice"></bean>
        </property>
        <property name="patterns">
            <list>
                <value>.*run.*</value>
            </list>
        </property>
    </bean>
    <!-- 自動代理 -->

    <bean class="cn.hncu.spring4x.aop.MyAutoProxy"></bean>
</beans>