Spring快速入門詳解

前言

Spring技術(shù)是JavaEE開發(fā)必備技能,企業(yè)開發(fā)技術(shù)選型命中率>90%。
Spring具有簡(jiǎn)化開發(fā),降低企業(yè)級(jí)開發(fā)的復(fù)雜性和框架整合,高效整合其他技術(shù),提高企業(yè)級(jí)應(yīng)用開發(fā)與運(yùn)行效率的特點(diǎn)。
本文詳細(xì)講解Spring快速入門。

簡(jiǎn)介

官網(wǎng):spring.io
Spring發(fā)展到今天已經(jīng)形成了一種開發(fā)的生態(tài)圈,Spring提供了若干個(gè)項(xiàng)目,每個(gè)項(xiàng)目用于完成特定的功能。以下就是Spring的全家桶。

image.png

本文主要講解Spring Framework

image.png

Spring Framework是Spring生態(tài)圈中最基礎(chǔ)的項(xiàng)目,是其他項(xiàng)目的根基。

快速入門

1. ApplicationContext配置文件

本文需要?jiǎng)?chuàng)建applicationContext.xml文件放入resources中內(nèi)容如下:

<?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 -->
    
</beans>

下文所提到的bean的配置均是在此文件中進(jìn)行配置。

2. IoC(Inversion of Control)控制反轉(zhuǎn)

2.1 概念

使用對(duì)象時(shí),由主動(dòng)new產(chǎn)生對(duì)象轉(zhuǎn)換為由外部提供對(duì)象,此過程中對(duì)象創(chuàng)建控制權(quán)由程序轉(zhuǎn)移到外部,此思想稱為控制反轉(zhuǎn)。
Spring技術(shù)對(duì)IoC思想進(jìn)行了實(shí)現(xiàn)。
Spring提供了一個(gè)容器,稱為IoC容器,用來充當(dāng)IoC思想中的外部。
IoC容器負(fù)責(zé)對(duì)象的創(chuàng)建,初始化等一系列工作,被創(chuàng)建或被管理的對(duì)象在IoC容器中統(tǒng)稱為Bean

2.2 IoC快速入門

2.2.1 在pom.xml中導(dǎo)入Spring坐標(biāo)

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

2.2.2 定義Spring管理的類(接口)

public interface BookService {
    void save();
}
public class BookServiceImpl implements BookService {
    
    private BookDao bookDao = new BookDaoImpl();
    @Override
    public void save() {
        bookDao.save();
    }
}

2.2.3 創(chuàng)建Spring的xml配置文件,配置對(duì)應(yīng)類作為Spring管理的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.xsd">

    <bean id="bookService" class="com.hao.service.impl.BookServiceImpl"/>
</beans>

注意事項(xiàng):bean定義時(shí)id屬性在同一個(gè)上下文中不能重復(fù)

2.2.4 初始化IoC容器,通過容器獲取bean

public class App {
    public static void main(String[] args) {
        /* 加載配置文件 獲取IoC容器 */
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
        /* 獲取bean */
        BookService bookService = (BookService) cxt.getBean("bookService");
        bookService.save();
    }
}

現(xiàn)在運(yùn)行App類可以看到這里可以正常得到bookService并使用。

3. DI(Dependency injection)依賴注入

3.1 概念

在容器中建立bean與bean之間的依賴關(guān)系的整個(gè)過程,稱為依賴注入。

3.2 快速入門

3.2.1 刪除使用new的形式創(chuàng)建對(duì)象的代碼

public class BookServiceImpl implements BookService {
    /* 刪除業(yè)務(wù)層中使用new的方式創(chuàng)建的dao對(duì)象 */
    private BookDao bookDao;
    @Override
    public void save() {
        System.out.println("book service save...");
        bookDao.save();
    }    
}

3.2.2 提供依賴對(duì)象對(duì)應(yīng)的setter方法

public class BookServiceImpl implements BookService {
    /* 刪除業(yè)務(wù)層中使用new的方式創(chuàng)建的dao對(duì)象 */
    private BookDao bookDao;
    @Override
    public void save() {
        System.out.println("book service save...");
        bookDao.save();
    }
    /* 提供對(duì)應(yīng)的setter方法 */
    public void setBookDao(BookDao bookDao) {
        System.out.println("set book dao...");
        this.bookDao = bookDao;
    }
}

3.2.3 配置Service與Dao之間的關(guān)系

<bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.hao.service.impl.BookServiceImpl">
    <!-- 配置Service與Dao的關(guān)系 -->
    <!--
        property標(biāo)簽:表示配置當(dāng)前bean的屬性
        name屬性:表示配置哪一個(gè)具體的屬性
        ref屬性:表示參照哪一個(gè)bean 可以是id,也可以是name 建議使用id
    -->
    <property name="bookDao" ref="bookDao"/>
</bean>

4. bean配置

4.1 bean基礎(chǔ)配置

image.png

4.2 bean別名配置

image.png

注意:獲取bean無論是通過id還是name獲取,如果無法獲取到,將拋出異常NoSuchBeanDefinitionException,意思是這個(gè)bean沒有被定義。此問題很大可能是配置時(shí)寫錯(cuò),或者是獲取時(shí)候?qū)戝e(cuò)導(dǎo)致的,到時(shí)候看看修改一下就解決了。

4.3 bean作用范圍

image.png

由此可知bean默認(rèn)是創(chuàng)建的單例對(duì)象。

4.3.1 適合交給容器進(jìn)行管理的bean

表現(xiàn)層對(duì)象
業(yè)務(wù)層對(duì)象
數(shù)據(jù)層對(duì)象
工具對(duì)象

4.3.2 不適合交給容器進(jìn)行管理的bean

封裝實(shí)體的域?qū)ο?/p>

5. bean實(shí)例化

bean本質(zhì)上就是對(duì)象,創(chuàng)建bean使用構(gòu)造方法完成。
實(shí)例化bean有四種方式。

5.1 構(gòu)造方法(常用)

5.1.1 提供可訪問的構(gòu)造方法

public class BookDaoImpl implements BookDao {
    private BookDaoImpl() {
        System.out.println("book dao constructor is running...");
    }
    @Override
    public void save() {
        System.out.println("book dao save...");
    }
}

5.1.2 配置

<bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl"/>

這里注意一個(gè)小細(xì)節(jié),就算無參構(gòu)造方法是私有的,也是可以通過無參構(gòu)造方法來創(chuàng)建對(duì)象。但是如果無參構(gòu)造方法不存在,將拋出異常BeanCreationException

5.2 靜態(tài)工廠(了解)

5.2.1 提供靜態(tài)工廠類

public class OrderDaoFactory {
    public static OrderDao getOrderDao() {
        return new OrderDaoImpl();
    }
}

5.2.2 配置

<bean id="orderDao" class="com.hao.factory.OrderDaoFactory" factory-method="getOrderDao"/>

5.3 實(shí)例工廠(了解)

5.3.1 提供實(shí)例工廠類

public class UserDaoFactory {
    public UserDao getUserDao() {
        return new UserDaoImpl();
    }
}

5.3.2 配置

<bean id="userFactory" class="com.hao.factory.UserDaoFactory"/>
<bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/>

5.4 使用FactoryBean(了解)

5.4.1 提供FactoryBean實(shí)現(xiàn)類

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    /* 代替原始實(shí)例工廠中創(chuàng)建對(duì)象的方法 */
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    /* 對(duì)象類型 */
    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
    /* 創(chuàng)建的對(duì)象是否是單例 默認(rèn)是單例 */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

5.4.2 配置

<bean id="userDao" class="com.hao.factory.UserDaoFactoryBean"/>

6. bean生命周期

6.1 概念

生命周期:從創(chuàng)建到消亡的完整過程
bean生命周期:bean從創(chuàng)建到消亡的整體過程
bean生命周期控制:在bean創(chuàng)建后到銷毀前做一些事情

6.2 bean生命周期控制

有兩種方式可以來實(shí)現(xiàn)bean生命周期的控制。

6.2.1 提供生命周期控制方法

public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("book dao save...");
    }
    /* 定義該方法 表示bean初始化對(duì)應(yīng)的操作 */
    public void init() {
        System.out.println("book dao init...");
    }
    /* 定義該方法 表示bean銷毀前對(duì)應(yīng)的操作 */
    public void destory() {
        System.out.println("book dao destory...");
    }
}

配置如下

<bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>

6.2.2 實(shí)現(xiàn)InitializingBean, DisposableBean接口

public class BookServiceImpl implements BookService , InitializingBean, DisposableBean {
    @Override
    public void save() {
        System.out.println("book service save...");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("book service destroy...");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("book service init...");
    }
}

6.3 bean銷毀時(shí)機(jī)

容器關(guān)閉前觸發(fā)bean的銷毀

關(guān)閉容器方式有兩種:手工關(guān)閉容器和注冊(cè)關(guān)閉鉤子。

6.3.1 手工關(guān)閉容器

ConfigurableApplicationContext接口close()操作

public class AppForLifeCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
        /* 獲取bean */
        BookDao bookDao = (BookDao) cxt.getBean("bookDao");
        bookDao.save();
        /* 關(guān)閉容器 close比較暴力 */
        cxt.close();
    }
}

6.3.2 注冊(cè)關(guān)閉鉤子,在虛擬機(jī)退出前先關(guān)閉容器再退出虛擬機(jī)

ConfigurableApplicationContext接口registerShutdownHook()操作

public class AppForLifeCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
        /* 注冊(cè)關(guān)閉鉤 在程序退出之前會(huì)先關(guān)閉容器 */
        cxt.registerShutdownHook();
        /* 獲取bean */
        BookDao bookDao = (BookDao) cxt.getBean("bookDao");
        bookDao.save();
    }
}

7. 依賴注入方式

依賴注入的方式分為setter注入和構(gòu)造器注入。

  1. setter注入包含:簡(jiǎn)單類型和引用類型
  2. 構(gòu)造器注入包含:簡(jiǎn)單類型和引用類型

7.1 setter注入--引用類型

7.1.1 在bean中定義引用類型屬性并提供可訪問的set方法

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

7.1.2 配置中使用property標(biāo)簽ref屬性注入引用類型對(duì)象

    <bean id="bookService" class="com.hao.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>

7.2 setter注入--簡(jiǎn)單類型

7.2.1 在bean中定義簡(jiǎn)單類型屬性并提供可訪問的set方法

public class BookDaoImpl implements BookDao {
    private int connectionNum;
    private String databaseName;
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }
    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }
}

7.2.2 配置中使用property標(biāo)簽value屬性注入簡(jiǎn)單類型數(shù)據(jù)

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <property name="connectionNum" value="123"/>
        <property name="databaseName" value="mysql"/>
    </bean>

7.3 構(gòu)造器注入--引用類型 (了解)

7.3.1 在bean中定義引用類型屬性并提供可訪問的構(gòu)造方法

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    public BookServiceImpl(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

7.3.2 配置中使用constructor-arg標(biāo)簽ref屬性注入引用類型對(duì)象

    <bean id="bookService" class="com.hao.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/>
    </bean>

7.4 構(gòu)造器注入--簡(jiǎn)單類型(了解)

7.4.1 在bean中定義簡(jiǎn)單類型屬性并提供可訪問的構(gòu)造方法

public class BookDaoImpl implements BookDao {
    private int connectionNum;
    private String databaseName;
    public BookDaoImpl(int connectionNum, String databaseName) {
        this.connectionNum = connectionNum;
        this.databaseName = databaseName;
    }
}

7.4.2 配置中使用constructor-arg標(biāo)簽value屬性注入簡(jiǎn)單類型數(shù)據(jù)

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <constructor-arg name="connectionNum" value="10"/>
        <constructor-arg name="databaseName" value="mysql"/>
    </bean>

該方式耦合度比較高。

7.4.3 配置中使用constructor-arg標(biāo)簽type屬性設(shè)置按形參類型注入數(shù)據(jù)

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <constructor-arg type="int" value="10"/>
        <constructor-arg type="java.lang.String" value="mysql"/>
    </bean>

該方式解決參數(shù)名耦合問題。

7.4.4 配置中使用constructor-arg標(biāo)簽value屬性設(shè)置按形參位置注入數(shù)據(jù)

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <constructor-arg index="0" value="666"/>
        <constructor-arg index="1" value="mysql"/>
    </bean>

該方式解決參數(shù)類型重復(fù)問題。

7.5 依賴注入方式選擇

a. 強(qiáng)制依賴使用構(gòu)造器進(jìn)行,使用setter注入有概率不進(jìn)行注入導(dǎo)致null對(duì)象出現(xiàn)
b. 可選依賴使用setter注入進(jìn)行,靈活性強(qiáng)
c. Spring框架倡導(dǎo)使用構(gòu)造器,第三方框架內(nèi)部大多數(shù)采用構(gòu)造器注入的形式進(jìn)行數(shù)據(jù)初始化,相對(duì)嚴(yán)謹(jǐn)
d. 如果有必要可以兩者同時(shí)使用呢,使用構(gòu)造器注入完成強(qiáng)制依賴的注入,使用setter注入完成可選依賴的注入
e. 實(shí)際開發(fā)過程中還要根據(jù)實(shí)際情況分析,如果受控對(duì)象沒有提供setter方法就必須使用構(gòu)造器注入
f. 自己開發(fā)的模塊推薦使用setter注入

8. 依賴自動(dòng)裝配(autowire)

8.1 概念

IoC容器根據(jù)bean所依賴的資源在容器中自動(dòng)查找并注入到bean中的過程成為自動(dòng)裝配。

8.2 自動(dòng)裝配方式

public class BookServiceImpl implements BookService{
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

8.2.1 按類型(常用)

<bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.hao.service.impl.BookServiceImpl" autowire="byType"/>

8.2.2 按名稱

<bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.hao.service.impl.BookServiceImpl" autowire="byName"/>

注意:屬性名稱bookDao必須與屬性beanidname一致

8.3 特征

a. 自動(dòng)裝配用于引用類型依賴注入,不能對(duì)簡(jiǎn)單類型進(jìn)行操作。
b. 使用按類型裝配時(shí)(byType)必須保障容器中相同類型的bean唯一,推薦使用。
c. 使用按名稱裝配時(shí)(byName)必須保障容器中具有指定名稱的bean,因變量名與配置耦合,不推薦使用。
d. 自動(dòng)裝配優(yōu)先級(jí)低于setter注入與構(gòu)造器注入,同時(shí)出現(xiàn)時(shí)自動(dòng)裝配配置無效。

9. 集合注入

public class BookDaoImpl implements BookDao {
    private int[] array;
    private List<String> list;
    private Set<String> set;
    private Map<String, String> map;
    private Properties properties;
    
    public void setArray(int[] array) {
        this.array = array;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }

}

9.1 注入數(shù)組對(duì)象

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <property name="array">
            <array>
                <value>100</value>
                <value>200</value>
                <value>300</value>
            </array>
        </property>
    </bean>

9.2 注入List對(duì)象(重點(diǎn))

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <property name="list">
            <list>
                <value>ithao</value>
                <value>hao</value>
                <value>java</value>
            </list>
        </property>
    </bean>

9.3 注入Set對(duì)象

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <property name="set">
            <set>
                <value>ithao</value>
                <value>hao</value>
                <value>spring</value>
            </set>
        </property>
    </bean>

9.4 注入Map對(duì)象(重點(diǎn))

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <property name="map">
            <map>
                <entry key="country" value="China"/>
                <entry key="province" value="henan"/>
                <entry key="city" value="yuzhou"/>
            </map>
        </property>
    </bean>

9.5 注入Properties對(duì)象

    <bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl">
        <property name="properties">
            <props>
                <prop key="country">China</prop>
                <prop key="province">henan</prop>
                <prop key="city">yuzhou</prop>
            </props>
        </property>
    </bean>

10. 第三方資源配置管理

這里以第三方資源druid為例來講解詳細(xì)步驟。

10.1 在pom.xml中導(dǎo)入druid坐標(biāo)

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.9</version>
    </dependency>

10.2 配置數(shù)據(jù)源對(duì)象作為Spring管理的bean

這個(gè)bean其實(shí)就是管理DruidDataSource對(duì)象

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Diver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

測(cè)試一下如下:

public class App {
    public static void main(String[] args) {
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource) cxt.getBean("dataSource");
        System.out.println(dataSource);
    }
}

11. 加載properties文件

11.1 在配置文件中開啟context命名空間

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

11.2 使用context命名空間,加載指定properties文件

比如創(chuàng)建一個(gè)jdbc.properties文件,加載jdbc.properties有多種寫法如下:

11.2.1 正常加載properties

<context:property-placeholder location="jdbc.properties"/>

11.2.2 不加載系統(tǒng)屬性

<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>

11.2.3 加載多個(gè)properties文件

<context:property-placeholder location="jdbc.properties, jdbc2.properties"/>

11.2.4 加載所有properties文件

<context:property-placeholder location="*.properties"/>

11.2.5 加載properties文件標(biāo)準(zhǔn)格式

<context:property-placeholder location="classpath:*.properties"/>

11.2.6 從類路徑或jar包中搜索并加載properties文件

<context:property-placeholder location="classpath*:*.properties"/>

11.3 使用${}讀取加載的屬性值

jdbc.properties文件中存入druid的配置信息如下:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456

那么關(guān)于druidbean配置就可以寫成如下:

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

總結(jié)

以上就是關(guān)于Spring快速入門詳解的全部內(nèi)容,本文詳細(xì)介紹了使用xml配置的方式來使用Spring Framework

如果有什么問題,我們可以一起交流討論解決。

最后,希望可以幫助到有需要的碼友。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容