Spring之Aop練習

勿在浮沙築高臺LS發表於2016-12-25

注意一下,在講解之前,說明一點:使用Spring AOP,要成功執行起程式碼,只用Spring提供給開發者的jar包是不夠的,請額外上網下載兩個jar包:

1、aopalliance.jar

2、aspectjweaver.jar

開始講解用Spring AOP的XML實現方式,先定義一個介面:

package cn.itcast.oa.service;

public interface HelloWorld {
    void printHelloWorld();

    void doPrint();
}

兩個實現類:

package cn.itcast.oa.service.impl;

import cn.itcast.oa.service.HelloWorld;

public class HelloWorldImpl1 implements HelloWorld {
    public void printHelloWorld() {
        System.out.println("Enter HelloWorldImpl1.printHelloWorld()");
    }

    public void doPrint() {
        System.out.println("Enter HelloWorldImpl1.doPrint()");
        return;
    }
}
package cn.itcast.oa.service.impl;

import cn.itcast.oa.service.HelloWorld;

public class HelloWorldImpl2 implements HelloWorld {
    public void printHelloWorld() {
        System.out.println("Enter HelloWorldImpl2.printHelloWorld()");
    }

    public void doPrint() {
        System.out.println("Enter HelloWorldImpl2.doPrint()");
        return;
    }
}

橫切關注點,這裡面是列印時間:

package cn.itcast.oa.service.impl;

public class TimeHandler {
    public void printTime() {
        System.out.println("CurrentTime = " + System.currentTimeMillis());
    }
}

測試程式碼:

package cn.itcast.oa.test;

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

import cn.itcast.oa.service.HelloWorld;

public class TestAop {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");

        HelloWorld hw1 = (HelloWorld) ctx.getBean("helloWorldImpl1");
        HelloWorld hw2 = (HelloWorld) ctx.getBean("helloWorldImpl2");
        hw1.printHelloWorld();
        System.out.println();
        hw1.doPrint();

        System.out.println();
        hw2.printHelloWorld();
        System.out.println();
        hw2.doPrint();
    }
}

新建aop.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:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

    <bean id="helloWorldImpl1" class="cn.itcast.oa.service.impl.HelloWorldImpl1" />
    <bean id="helloWorldImpl2" class="cn.itcast.oa.service.impl.HelloWorldImpl2" />
    <bean id="timeHandler" class="cn.itcast.oa.service.impl.TimeHandler" />

    <aop:config>
        <aop:aspect id="time" ref="timeHandler">
            <aop:pointcut id="addAllMethod"
                expression="execution(* cn.itcast.oa.service.HelloWorld.*(..))" />
            <aop:before method="printTime" pointcut-ref="addAllMethod" />
            <aop:after method="printTime" pointcut-ref="addAllMethod" />
        </aop:aspect>
    </aop:config>
</beans>

實驗結果:

CurrentTime = 1482635730488
Enter HelloWorldImpl1.printHelloWorld()
CurrentTime = 1482635730489

CurrentTime = 1482635730491
Enter HelloWorldImpl1.doPrint()
CurrentTime = 1482635730491

CurrentTime = 1482635730491
Enter HelloWorldImpl2.printHelloWorld()
CurrentTime = 1482635730491

CurrentTime = 1482635730491
Enter HelloWorldImpl2.doPrint()
CurrentTime = 1482635730491

基於Spring的AOP使用其他細節

1、增加一個橫切關注點,列印日誌,Java類為:

package cn.itcast.oa.service.impl;

public class LogHandler {
    public void LogBefore() {
        System.out.println("Log before method");
    }

    public void LogAfter() {
        System.out.println("Log after method");
    }
}

aop.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:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

    <bean id="helloWorldImpl1" class="cn.itcast.oa.service.impl.HelloWorldImpl1" />
    <bean id="helloWorldImpl2" class="cn.itcast.oa.service.impl.HelloWorldImpl2" />
    <bean id="timeHandler" class="cn.itcast.oa.service.impl.TimeHandler" />
    <bean id="logHandler" class="cn.itcast.oa.service.impl.LogHandler" />
    <aop:config>
        <aop:aspect id="time" ref="timeHandler">
            <aop:pointcut id="addAllMethod"
                expression="execution(* cn.itcast.oa.service.HelloWorld.*(..))" />
            <aop:before method="printTime" pointcut-ref="addAllMethod" />
            <aop:after method="printTime" pointcut-ref="addAllMethod" />
        </aop:aspect>
        <aop:aspect id="log" ref="logHandler" order="2">
            <aop:pointcut id="printLog"
                expression="execution(* cn.itcast.oa.service.HelloWorld.*(..))" />
            <aop:before method="LogBefore" pointcut-ref="printLog" />
            <aop:after method="LogAfter" pointcut-ref="printLog" />
        </aop:aspect>
    </aop:config>
</beans>

測試程式碼不變,測試結果如下:

Log before method
CurrentTime = 1482637050240
Enter HelloWorldImpl1.printHelloWorld()
CurrentTime = 1482637050241
Log after method

Log before method
CurrentTime = 1482637050244
Enter HelloWorldImpl1.doPrint()
CurrentTime = 1482637050244
Log after method

Log before method
CurrentTime = 1482637050244
Enter HelloWorldImpl2.printHelloWorld()
CurrentTime = 1482637050245
Log after method

Log before method
CurrentTime = 1482637050246
Enter HelloWorldImpl2.doPrint()
CurrentTime = 1482637050246
Log after method

要想讓logHandler在timeHandler前使用有兩個辦法:

(1)aspect裡面有一個order屬性,order屬性的數字就是橫切關注點的順序

(2)把logHandler定義在timeHandler前面,Spring預設以aspect的定義順序作為織入順序
2、我只想織入介面中的某些方法

修改一下pointcut的expression就好了:

<?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:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

    <bean id="helloWorldImpl1" class="cn.itcast.oa.service.impl.HelloWorldImpl1" />
    <bean id="helloWorldImpl2" class="cn.itcast.oa.service.impl.HelloWorldImpl2" />
    <bean id="timeHandler" class="cn.itcast.oa.service.impl.TimeHandler" />
    <bean id="logHandler" class="cn.itcast.oa.service.impl.LogHandler" />
    <aop:config>
        <aop:aspect id="time" ref="timeHandler">
            <aop:pointcut id="addAllMethod"
                expression="execution(* cn.itcast.oa.service.HelloWorld.*(..))" />
            <aop:before method="printTime" pointcut-ref="addAllMethod" />
            <aop:after method="printTime" pointcut-ref="addAllMethod" />
        </aop:aspect>
        <aop:aspect id="log" ref="logHandler" order="2">
            <aop:pointcut id="printLog"
                expression="execution(* cn.itcast.oa.service.HelloWorld.do*(..))" />
            <aop:before method="LogBefore" pointcut-ref="printLog" />
            <aop:after method="LogAfter" pointcut-ref="printLog" />
        </aop:aspect>
    </aop:config>
</beans>

表示timeHandler只會織入HelloWorld介面print開頭的方法,logHandler只會織入HelloWorld介面do開頭的方法

3、強制使用CGLIB生成代理

前面說過Spring使用動態代理或是CGLIB生成代理是有規則的,高版本的Spring會自動選擇是使用動態代理還是CGLIB生成代理內容,當然我們也可以強制使用CGLIB生成代理,那就是裡面有一個”proxy-target-class”屬性,這個屬性值如果被設定為true,那麼基於類的代理將起作用,如果proxy-target-class被設定為false或者這個屬性被省略,那麼基於介面的代理將起作用

相關文章