Spring-1.依賴注入(BI)和面向切面編程(AOP)

1 依賴注入

通過依賴注入(Dependency Injection, DI),對象的依賴關(guān)系將由系統(tǒng)中負責協(xié)調(diào)各對象的第三方組件在創(chuàng)建對象的時候進行設定。

1.1 實現(xiàn)

對于如下類

package com.junzerg.spring_knight;

public class BraveKnight implements Knight {

    private Quest quest;

    public BraveKnight(Quest quest) {
        this.quest = quest;
    }

    public void embarkOnQuest() {
        quest.embark();
    }
}
  1. BraveKnight沒有自己創(chuàng)建探險任務,而是在構(gòu)造的時候把探險任務作為構(gòu)造器參數(shù)傳入。這是依賴注入的一種方式,構(gòu)造器注入(constructor injection)。
  2. 傳入的探險類型Quest,是所有的探險任務都必須實現(xiàn)的一個接口。
  3. BraveKnight沒有與特定的Quest實現(xiàn)發(fā)生耦合,只要求探險任務實現(xiàn)了Quest接口。

可以看出:
DI帶來的最大的好處就是松耦合。如果一個對象只通過接口(而不是具體實現(xiàn)或者初始化過程)來表明依賴關(guān)系,那么這種依賴就能在對象本身毫不知情的情況下,用不同的具體實現(xiàn)進行替換。

1.2 注入

對于#1中的BraveKnight類??梢越邮苋我庖环NQuest的實現(xiàn),例如如下類:

package com.junzerg.spring_knight;

import java.io.PrintStream;

public class SlayDragonQuest implements Quest {

    private PrintStream stream;

    public SlayDragonQuest(PrintStream stream) {
        this.stream = stream;
    }

    public void embark() {
        stream.println("Embarking on quest to slay the dragon!");
    }
}

創(chuàng)建了這個類之后,剩下的就是將這個類交給BraveKnight。這就是創(chuàng)建應用組件之間的寫作的行為,被稱為裝配(wiring)。

1.3 裝配

Spring支持兩種裝配的方式。

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

    <bean id="knight" class="com.junzerg.spring_knight.BraveKnight">
        <constructor-arg ref="quest" />
    </bean>

    <bean id="quest" class="com.junzerg.spring_knight.SlayDragonQuest">
        <constructor-arg value="#{T(System).out}" />
    </bean>

</beans>

以上配置功能為:

  1. 將BraveKnight和SlayDragonQuest聲明為Spring中的bean。
  2. 在構(gòu)造BraveKnight bean的時候傳入SlayDragonQuest bean的應用,作為構(gòu)造器的參數(shù)。
  3. 在構(gòu)造SlayDragonQuest bean的時候?qū)ystem.out傳入到構(gòu)造器中。
1.3.2 Java描述配置
package com.junzerg.spring_knight.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.junzerg.spring_knight.BraveKnight;
import com.junzerg.spring_knight.Knight;
import com.junzerg.spring_knight.Quest;
import com.junzerg.spring_knight.SlayDragonQuest;

@Configuration
public class KnightConfig {
    
    @Bean
    public Knight knight() {
        return new BraveKnight(quest());
    }
    
    @Bean
    public Quest quest() {
        return new SlayDragonQuest(System.out);
    }
}

作用和用 xml配置的一樣。

1.4 實現(xiàn)

1.4.1 xml配置的實現(xiàn)

對于xml配置的情況,使用ClassPathXmlApplicationContext(加載位于應用程序類路徑下的一個或者多個XML配置文件)。

package com.junzerg.spring_knight;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class KnightMain {

    @Autowired
    Knight knight;

    public static void main(String[] args) throws Exception {
         ClassPathXmlApplicationContext context = new
         ClassPathXmlApplicationContext("META-INF/spring/knight.xml");
         Knight knight = context.getBean(Knight.class);
         knight.embarkOnQuest();
         context.close();
    }
}
1.4.2 Java配置的實現(xiàn)

對于Java配置的情況,使用AnnotationConfigApplicationContext。

package com.junzerg.spring_knight;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.junzerg.spring_knight.config.KnightConfig;

public class KnightMain {

    @Autowired
    Knight knight;

    public static void main(String[] args) throws Exception {

        AnnotationConfigApplicationContext content = new AnnotationConfigApplicationContext(KnightConfig.class);
        Knight knight = content.getBean(Knight.class);
        knight.embarkOnQuest();
    }
}

1.5 上下文中其他類和結(jié)果

1.5.1 上下文中其他類
  1. Knight
package com.junzerg.spring_knight;

public interface Knight {

    void embarkOnQuest();

}
  1. Quest
package com.junzerg.spring_knight;

public interface Quest {

    void embark();

}
1.5.2 運行結(jié)果:

Embarking on quest to slay the dragon!

1.5.3 Maven

我是在Maven中添加Spring依賴的,這一節(jié)只需要用到Spring的上下文(context)依賴,如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>

2 面向切面編程(AOP)

通過面向切面編程(aspect-oriented programming, AOP),把遍布應用各處的功能分離出來形成可重用的組件。
AOP將橫切關(guān)注點(跨越系統(tǒng)的多個組件,例如日子,事務管理,安全等)模塊化,并以聲明的方式將它們應用到需要影響的組件中去,這樣能夠使這些組件有更高的內(nèi)聚性并且會更加關(guān)注自身的業(yè)務,不需要了解涉及系統(tǒng)服務帶來的復雜性,從而保證了POJO的簡單性。

2.1 AOP簡單應用

對于#1中的騎士的事跡,用一個吟游詩人來記載。

package com.junzerg.spring_knight;

import java.io.PrintStream;

public class Minstrel {

    private PrintStream stream;

    public Minstrel(PrintStream stream) {
        this.stream = stream;
    }

    public void singBeforeQuest() {
        stream.println("Fa la la, the knight is so brave!");
    }

    public void singAfterQuest() {
        stream.println("Tee hee hee, the brave knight " + "did embark on a quest!");
    }

}

Minstrel類,在騎士執(zhí)行每一個探險任務之前,singBeforeQuest被調(diào)用;在騎士完成探險任務之后,singAfterQuest()方法會被調(diào)用;這兩種情況都通過PrintStream類來歌頌事跡,這個類是通過構(gòu)造器來引入的。

**那么,在普通情況下,編寫這個類之后,會在BraceKnight中使用這個類。但是利用AOP,可以在騎士類不訪問吟游詩人類的情況下,讓吟游詩人歌頌騎士的事跡。

這種技術(shù)是通過在Spring配置文件中將Minstrel聲明為一個切面實現(xiàn)的。

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

    <bean id="knight" class="sia.knights.BraveKnight">
        <constructor-arg ref="quest" />
    </bean>

    <bean id="quest" class="sia.knights.SlayDragonQuest">
        <constructor-arg value="#{T(System).out}" />
    </bean>

    <bean id="minstrel" class="sia.knights.Minstrel">
        <constructor-arg value="#{T(System).out}" />
    </bean>

    <aop:config>
        <aop:aspect ref="minstrel">
            <aop:pointcut id="embark" expression="execution(* *.embarkOnQuest(..))" />

            <aop:before pointcut-ref="embark" method="singBeforeQuest" />

            <aop:after pointcut-ref="embark" method="singAfterQuest" />
        </aop:aspect>
    </aop:config>

</beans>

2.3 結(jié)果和Maven

2.3.1 結(jié)果

Fa la la, the knight is so brave!
Embarking on quest to slay the dragon!
Tee hee hee, the brave knight did embark on a quest!

2.3.2 Maven

本節(jié)中利用到了AspectJ切點表達式,需要在Maven中添加如下依賴:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.10</version>
</dependency>

<dependency>
    <groupId>aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.5.4</version>
</dependency>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,502評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,253評論 6 342
  • 縱覽Spring , 讀者會發(fā)現(xiàn)Spring 可以做非常多的事情。 但歸根結(jié)底, 支撐Spring的僅僅是少許的基...
    六尺帳篷閱讀 1,696評論 0 13
  • 最開始認識你的時候,其實我的心里是抱有一些成見的,第一次知道你是在《快樂大本營》的舞臺上,那時的你面對鏡頭還是有那...
    噢吧碼閱讀 865評論 7 7
  • 新鮮新鮮新鮮。。。像被念過咒語一樣,這個概念已經(jīng)植入到了寒冰童鞋腦子里。寒冰童鞋本來是撕烤人參的販子,現(xiàn)在悲摧變身...
    冰小寒閱讀 482評論 0 1

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