1. 程式人生 > >簡述DI與AOP

簡述DI與AOP

point java 保持 ans orien face fig 圖片 www.

Spring的兩個核心特性:

  • 依賴註入(dependency injection,DI)
  • 面向切面編程(aspect oriented programming,AOP)

依賴註入(dependency injection,DI)

  • 沒有使用依賴註入時:以前每個POJO(Plain Ordinary Java Object,簡單的Java對象)在創建的時候會主動的去獲取依賴。從代碼上的體現是一個類中有實例化另一個類的對象(耦合度高)。為此我們需要讓類從外部被註入依賴,而不是主動獲取。
  • 三種依賴註入方式:setter方法註入,構造器註入,接口註入(就是在接口中聲明一個方法,參數是依賴的對象)。
  • 依賴註入作用:將各個相互協作的模塊代碼保持松散耦合。
  • 下面我們通過幾個簡單的類來了解一下依賴註入:

先聲明兩個接口People與Fruit。

public interface People {// people接口
    void eat();
}

public interface Fruit {// 水果接口
    void speak();
}

接下來是分別實現他們的類Watermelon與Student。

public class Watermelon implements Fruit{// 西瓜類
    @Override
    public void speak() {
        System.out.println(
"我是西瓜,我要被吃掉了!"); } } public class Student implements People {// 學生類 private Fruit fruit; public Student(Fruit fruit) {// 構造器註入依賴的對象 this.fruit = fruit; } @Override public void eat() { fruit.speak(); } }

到這裏我們可以看出Student類依賴Watermelon類。當調用Student的eat方法時需要調用Watermelon的speak方法。

我們接下來用XML對這兩個應用組件進行裝配(wiring)。

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">

    <!--水果聲明為Spring的bean-->
    <bean id="fruit" class="com.qsh.springaction.Watermelon"/>
    <!--人聲明為Spring的bean-->
    <bean id="people" class="com.qsh.springaction.Student">
        <constructor-arg ref="fruit"/>
    </bean>
</beans>

最後我們進行測試。用spring上下文全權負責對象的創建和組裝。

public class TestEat {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("eat.xml");
        People people = context.getBean(People.class);
        people.eat();
        context.close();
    }
}

測試結果。

技術分享圖片

面向切面編程(aspect oriented programming,AOP)

  • 是什麽:促使軟件系統實現關註點分離的一項技術。系統由許多不同組件構成,每個組件負責一塊特定功能。除了實現自身核心功能外,這些組件還承擔著額外職責,如日誌,事務管理和安全這樣的系統服務,這樣的系統服務被稱為橫切關註點。因為他們會橫跨多個組件。
  • 作用:使系統服務模塊化,並以聲明的方式將它們應用到他們需要影響的組件中。
  • 個人理解:每個組件除了實現自身的功能,還需要實現其他的如事物管理等功能(稱為橫切關註點)。我們將這功能單獨抽取出來成一個模塊,每個組件在工作的過程中,這個模塊神不知鬼不覺的為每個組件實現額外功能。
  • 個人理解的切面圖:應用組件:實現各自功能的代碼。橫切關註點:每個組件的額外業務,相同的代碼。切面:將這些額外業務抽取出來成一個類。切點:應用組件的方法。

技術分享圖片

  • 通過幾段代碼講解AOP:

我們還是有上面的Student 和 Watermelon類。需要新增加一個Action類,就是一會的切面。

public class Action {// 行為類

    public void beforeEat() {
        System.out.println("吃前拿刀,嚓嚓嚓");
    }

    public void afterEat() {
        System.out.println("吃後洗手,嘩嘩嘩");
    }
}

需要在XML中加入Spring AOP命名空間,將Action方法聲明為Spring的bean,然後切面引用這個bean。切點為student的eat方法,在切點前後加入前置通知和後置通知。

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!--水果聲明為Spring的bean-->
    <bean id="fruit" class="com.qsh.springaction.Watermelon"/>
    <!--人聲明為Spring的bean-->
    <bean id="people" class="com.qsh.springaction.Student">
        <constructor-arg ref="fruit"/>
    </bean>
    <!--行為聲明為Spring的bean-->
    <bean id="action" class="com.qsh.springaction.Action"/>

    <!--用spring aop的命名空間把Action聲明為一個切面-->
    <aop:config>
        <!--引用Action的bean-->
        <aop:aspect ref="action">
            <!--聲明Student的eat方法為一個切點-->
            <aop:pointcut id="eating" expression="execution(* *.eat(..))"/>
            <!--前置通知,在調用eat方法前調用Action的beforeEat方法-->
            <aop:before pointcut-ref="eating" method="beforeEat"/>
            <!--後置通知,在調用eat方法後調用Action的afterEat方法-->
            <aop:after pointcut-ref="eating" method="afterEat"/>
        </aop:aspect>
    </aop:config>
</beans>

運行結果為:

技術分享圖片

簡述DI與AOP