Spring IOC 一——容器裝配Bean的簡單使用

下文:SpringIOC 二—— 容器 和 Bean的深入理解

寫在前面

這篇文章去年寫的,緣起於去年某段時間被領導臨時“抓壯丁”般的叫過去做java開發,然後在網上找了一個 SpringMVC 的 demo,學習一下,然後依葫蘆畫瓢,開始了自己的項目開發,也還順利完成了任務。在使用 SpringMVC 的過程中,我被這個被稱作“最優秀”的 java 框架 —— Spring 深深地吸引了,那些曾經掌握的多種設計模式的思想在其中都有實現,比如工廠模式、單例模式、觀察者模式等等,於是在工作之餘認真地學習了這個框架。
學習新東西總是令人興奮的,然而大多數學過的知識很容易又會忘記,所以便想整理一下,寫點筆記,方便自己以後複習查看。

部分參考資料:
《Spring實戰(第4版)》
《輕量級 JavaEE 企業應用實戰(第四版)》
Spring 官方文檔
W3CSchool Spring教程
易百教程 Spring教程

一、Spring簡介

Spring是一個開源框架,Spring是於2003年興起的一個輕量級的Java開發框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中闡述的部分理念和原型衍生而來。它是爲了解決企業應用開發的複雜性而創建的。框架的主要優勢之一就是其分層架構,分層架構允許使用者選擇使用哪一個組件。Spring提供了約20多個組件,開發者可以根據自己需要選擇組件。Spring的核心是控制反轉(IoC)和麪向切面編程(AOP)

  • IoC:控制反轉。
    控制反轉(Inversion of Control),又叫依賴注入(Dependency Injection)。舉例來說,在之前的操作中,比方說有一個類,我們想要調用類裏面的方法(不是靜態方法),就要創建類的對象,使用對象調用方法實現。對於Spring來說,Spring創建對象的過程,不是在代碼裏面實現的,而是交給Spring來進行配置實現的。
  • AOP:面向切面編程。
    面向切面編程(Aspect Orient Programming)支持允許將一些通用的任務入安全、事物、日誌、緩存等進行集中式處理,從而提供了更好的複用,AOP通常用來處理一些具有橫切性質的系統級服務。

二、Hello Spring 實例

從最簡單的 Hello,Spring 例子來體會一下使用 Spring 框架。首先看看不使用 Spring 框架的代碼:
HelloSpring.java 類:

package com.sharpcj;

public class HelloSpring {
    private String name;

    public void sayHello() {
        System.out.println("Hello," + name + "!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Test.java 類:

package com.sharpcj;

public class Test {
    public static void main(String[] args) {
        HelloSpring hs = new HelloSpring();
        hs.setName("Spring");
        hs.sayHello();
    }
}

輸出結果:

Hello,Spring!

下面我們用 Spring 框架來實現這個例子。
Spring 框架官方下載地址: http://repo.springsource.org/libs-release-local/
Spring 框架阿里雲下載地址:http://maven.aliyun.com/nexus/content/groups/public/springframework/

添加從 Spring 框架核心 JAR 文件:

  • commons-logging-1.1.1
  • spring-aop-5.0.6.RELEASE
  • spring-aspects-5.0.6.RELEASE
  • spring-beans-5.0.6.RELEASE
  • spring-context-5.0.6.RELEASE
  • spring-context-support-5.0.6.RELEASE
  • spring-core-5.0.6.RELEASE
  • spring-expression-5.0.6.RELEASE
  • spring-instrument-5.0.6.RELEASE
  • spring-instrument-tomcat-5.0.6.RELEASE
  • spring-jdbc-5.0.6.RELEASE
  • spring-jms-5.0.6.RELEASE
  • spring-messaging-5.0.6.RELEASE
  • spring-orm-5.0.6.RELEASE
  • spring-oxm-5.0.6.RELEASE
  • spring-test-5.0.6.RELEASE
  • spring-tx-5.0.6.RELEASE
  • spring-web-5.0.6.RELEASE
  • spring-webmvc-5.0.6.RELEASE
  • spring-webmvc-portlet-5.0.6.RELEASE
  • spring-websocket-5.0.6.RELEASE

這裏只是使用Spring的基本功能,所以需要使用到下面的這幾個Jar包:

這裏我使用的 idea,用 gradle 編譯的(用 maven 過程類似)。爲了提高下載速度,我使用了阿里雲的 maven 倉庫,然後添加依賴,最新穩定版本是 5.0.6 , build.gradle文件部分截圖:

代碼更改如下:
HelloSpring.java 類

package com.sharpcj;

public class HelloSpring {
    private String name;

    public void sayHello() {
        System.out.println("Hello," + name + "!");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Test.java 類

package com.sharpcj;

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

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new FileSystemXmlApplicationContext("src/beans.xml");
        HelloSpring hs = context.getBean("helloSpring", HelloSpring.class);
        hs.sayHello();
    }
}

此時在 src 目錄下新建了一個文件 beans.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-3.0.xsd">

    <bean id="helloSpring" class="com.sharpcj.HelloSpring">
        <property name="name" value="Spring"/>
    </bean>

</beans>

此時運行 Test.java 的 main 方法,打印結果如下:

Hello,Spring!

這樣我們就用 Spring 框架實現了最簡單的 Hello Spring 程序。

三、認識 spring 容器和 Bean

上面用 Spring 框架實現的代碼中,我們在 Test.java 類中,並沒有通過 “new HelloSpring()” 這樣的調用 Spring 構造方法去創建 HelloSpring 的對象,而是使用 Spring 核心容器創建的。

  • 第一步是我們使用框架 API FileSystemXmlApplicationContext() 來創建應用程序的上下文。這個 API 加載 beans 的配置文件並最終基於所提供的 API,它處理創建並初始化所有的對象,即在配置文件中提到的 beans。

  • 第二步是使用已創建的上下文的 getBean() 方法來獲得所需的 bean。這個方法使用 bean 的 ID 返回一個最終可以轉換爲實際對象的通用對象。一旦有了對象,你就可以使用這個對象調用任何類的方法。能通過這種方式創建的對象,一定是在 beans.xml 文件中配置的。

Spring 核心容器就好像是一個超級大的工廠,在配置文件中配置過的對象都會被當成 Spring 容器管理的對象。Spring 把容器中的一切對象統稱爲 Bean 。 Spring 中的 Bean 與傳統的 java Bean 不同,對 Spring 而言,任何一個 java 類,都可以當成是 Bean 來處理。

四、Spring容器裝配Bean的三種方式

  • 在XML中進行裝配
  • 自動裝配 bean
  • 在Java中進行裝配

還是用上面 HelloSpring 的例子,該例子實在過於簡單,只有一個 bean, 沒有涉及到兩個 bean 之間的依賴關係,不過還是可以用它來理解Spring容器裝配Bean的三種裝配方式。爲了說明依賴注入的場景,舉個其它例子:
人用筆寫字。僞代碼如下:
Pen 類:

public class Pen {
    // property 暫不關心
}

Person 類:

public class Person {
    private Pen pen;

    public Person(Pen pen) {
        this.pen = pen;
    }

    public Pen getPen() {
        return this.pen;
    }

    public void setPen(Pen pen) {
        this.pen = pen;
    }

    // 這裏我們暫不關心該方法
    public void write() {

    }
}

下面對於這種依賴關係,將分別用僞代碼來說明構造注入和設置注入。

在 XML 中進行裝配

基本使用

上面例子即是,不再贅述。

依賴注入

如果存在多個Bean, 之間有依賴關係:
構造注入:

<?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-3.0.xsd">

    <bean id="pen" class="com.sharpcj.Pen"> </bean>

    <bean id="person" class="com.sharpcj.Person">
        <constructor-arg name = "pen", ref = "pen">
    </bean>
</beans>

設值注入:

<?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-3.0.xsd">

    <bean id="pen" class="com.sharpcj.Pen"> </bean>

    <bean id="person" class="com.sharpcj.Person">
        <property name = "pen",  ref = "pen">
    </bean>
</beans>

4.2 自動裝配 bean

基本使用

com.sharpcj.HelloSpring.java 代碼如下:

package com.sharpcj;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class HelloSpring {
    private String name;

    public void sayHello() {
        System.out.println("Hello," + name + "!");
    }

    public String getName() {
        return name;
    }

    @Value("Spring")
    public void setName(String name) {
        this.name = name;
    }
}

創建類 com.sharpcj.HelloConfig.java用來開啓組件掃描:

package com.sharpcj;

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

@Configuration
@ComponentScan
public class HelloConfig {
}

修改com.sharpcj.Test.java

package com.sharpcj;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(com.sharpcj.HelloConfig.class);
        HelloSpring hello = context.getBean("helloSpring", HelloSpring.class);
        hello.sayHello();
    }
}

@Component 註解的類即爲 Bean 。 @Configuration 註解的即爲配置文件,@ComponentScan 註解表示開啓自動掃描,默認掃描該配置類所在的包,如果掃描其它包,多個包,形式如下:

@Configuration
@ComponentScan(basePackageClasses = {com.a.A.class, com.b.B.class})

也可以每個包內配置之後,再配置一個總的配置文件:

@Configuration
@Import({com.a.AConfig.class, com.b.BConfig.class})
public class TotalConfig {
}

依賴注入

如果存在多個Bean, 之間有依賴關係:

// pen 類:

@Component
public class Pen {
    // property 暫不關心
}

構造注入:

@Component
public class Person {

    private Pen pen;
    
    @Autowired
    public Person(Pen pen) {
        this.pen = pen;
    }

    public Pen getPen() {
        return this.pen;
    }

    public void setPen(Pen pen) {
        this.pen = pen;
    }

    // 這裏我們暫不關心該方法
    public void write() {

    }
}

設值注入:

@Component
public class Person {

    private Pen pen;

    public Pen getPen() {
        return this.pen;
    }

    @Autowired
    public void setPen(Pen pen) {
        this.pen = pen;
    }

    // 這裏我們暫不關心該方法
    public void write() {

    }
}

通過 java 代碼進行裝配

基本使用

此時 java 類無需使用註解。
同樣創建一個類,com.sharpcj.HelloConfig.java來進行裝配 Bean。

package com.sharpcj;

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

@Configuration
public class HelloConfig {
    @Bean
    public HelloSpring helloSpring(){
        return new HelloSpring();
    }
}

被 @Bean 標註的方法返回的即爲唯一 Bean(默認單例模式),方法名隨便取。

Test:

ApplicationContext context=new AnnotationConfigApplicationContext(com.sharpcj.HelloConfig.class);
Person person = context.getBean(Person.class);
person.write();

依賴注入

如果存在多個Bean, 之間有依賴關係:
構造注入:

@Configuration
public class PConfig {
    @Bean
    public GPen hehe() {
        return new GPen();
    }

    @Bean
    public QPen haha() {
        return new QPen();
    }

    @Bean
    public Person xixi() {
        Person person = new Person(hehe());
        return person;
    }
}

設值注入:

@Configuration
public class PConfig {
    @Bean
    public GPen hehe() {
        return new GPen();
    }

    @Bean
    public QPen haha() {
        return new QPen();
    }

    @Bean
    public Person xixi() {
        Person person = new Person();
        person.setPen(hehe());
        return person;
    }
}

寫在後面

這篇文章記錄了Spring容器和Bean的概念,Spring 的基本使用,以及Spring容器裝配Bean的三種方式。關於Spring 容器的知識點比較多,下篇文章接着寫點 Spring 容器裝配 Bean 的高級知識點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章