Spring快速入门详解

前言

Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%。
Spring具有简化开发,降低企业级开发的复杂性和框架整合,高效整合其他技术,提高企业级应用开发与运行效率的特点。
本文详细讲解Spring快速入门。

简介

官网:spring.io
Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目,每个项目用于完成特定的功能。以下就是Spring的全家桶。

image.png

本文主要讲解Spring Framework

image.png

Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。

快速入门

1. ApplicationContext配置文件

本文需要创建applicationContext.xml文件放入resources中内容如下:

<?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的配置均是在此文件中进行配置。

2. IoC(Inversion of Control)控制反转

2.1 概念

使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。
Spring技术对IoC思想进行了实现。
Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的外部。
IoC容器负责对象的创建,初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean

2.2 IoC快速入门

2.2.1 在pom.xml中导入Spring坐标

<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 创建Spring的xml配置文件,配置对应类作为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>

注意事项:bean定义时id属性在同一个上下文中不能重复

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();
    }
}

现在运行App类可以看到这里可以正常得到bookService并使用。

3. DI(Dependency injection)依赖注入

3.1 概念

在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

3.2 快速入门

3.2.1 删除使用new的形式创建对象的代码

public class BookServiceImpl implements BookService {
    /* 删除业务层中使用new的方式创建的dao对象 */
    private BookDao bookDao;
    @Override
    public void save() {
        System.out.println("book service save...");
        bookDao.save();
    }    
}

3.2.2 提供依赖对象对应的setter方法

public class BookServiceImpl implements BookService {
    /* 删除业务层中使用new的方式创建的dao对象 */
    private BookDao bookDao;
    @Override
    public void save() {
        System.out.println("book service save...");
        bookDao.save();
    }
    /* 提供对应的setter方法 */
    public void setBookDao(BookDao bookDao) {
        System.out.println("set book dao...");
        this.bookDao = bookDao;
    }
}

3.2.3 配置Service与Dao之间的关系

<bean id="bookDao" class="com.hao.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.hao.service.impl.BookServiceImpl">
    <!-- 配置Service与Dao的关系 -->
    <!--
        property标签:表示配置当前bean的属性
        name属性:表示配置哪一个具体的属性
        ref属性:表示参照哪一个bean 可以是id,也可以是name 建议使用id
    -->
    <property name="bookDao" ref="bookDao"/>
</bean>

4. bean配置

4.1 bean基础配置

image.png

4.2 bean别名配置

image.png

注意:获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException,意思是这个bean没有被定义。此问题很大可能是配置时写错,或者是获取时候写错导致的,到时候看看修改一下就解决了。

4.3 bean作用范围

image.png

由此可知bean默认是创建的单例对象。

4.3.1 适合交给容器进行管理的bean

表现层对象
业务层对象
数据层对象
工具对象

4.3.2 不适合交给容器进行管理的bean

封装实体的域对象

5. bean实例化

bean本质上就是对象,创建bean使用构造方法完成。
实例化bean有四种方式。

5.1 构造方法(常用)

5.1.1 提供可访问的构造方法

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"/>

这里注意一个小细节,就算无参构造方法是私有的,也是可以通过无参构造方法来创建对象。但是如果无参构造方法不存在,将抛出异常BeanCreationException

5.2 静态工厂(了解)

5.2.1 提供静态工厂类

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 实例工厂(了解)

5.3.1 提供实例工厂类

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实现类

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    /* 代替原始实例工厂中创建对象的方法 */
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }
    /* 对象类型 */
    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
    /* 创建的对象是否是单例 默认是单例 */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

5.4.2 配置

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

6. bean生命周期

6.1 概念

生命周期:从创建到消亡的完整过程
bean生命周期:bean从创建到消亡的整体过程
bean生命周期控制:在bean创建后到销毁前做一些事情

6.2 bean生命周期控制

有两种方式可以来实现bean生命周期的控制。

6.2.1 提供生命周期控制方法

public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("book dao save...");
    }
    /* 定义该方法 表示bean初始化对应的操作 */
    public void init() {
        System.out.println("book dao init...");
    }
    /* 定义该方法 表示bean销毁前对应的操作 */
    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 实现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销毁时机

容器关闭前触发bean的销毁

关闭容器方式有两种:手工关闭容器和注册关闭钩子。

6.3.1 手工关闭容器

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();
        /* 关闭容器 close比较暴力 */
        cxt.close();
    }
}

6.3.2 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机

ConfigurableApplicationContext接口registerShutdownHook()操作

public class AppForLifeCycle {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
        /* 注册关闭钩 在程序退出之前会先关闭容器 */
        cxt.registerShutdownHook();
        /* 获取bean */
        BookDao bookDao = (BookDao) cxt.getBean("bookDao");
        bookDao.save();
    }
}

7. 依赖注入方式

依赖注入的方式分为setter注入和构造器注入。

  1. setter注入包含:简单类型和引用类型
  2. 构造器注入包含:简单类型和引用类型

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标签ref属性注入引用类型对象

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

7.2 setter注入--简单类型

7.2.1 在bean中定义简单类型属性并提供可访问的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标签value属性注入简单类型数据

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

7.3 构造器注入--引用类型 (了解)

7.3.1 在bean中定义引用类型属性并提供可访问的构造方法

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

7.3.2 配置中使用constructor-arg标签ref属性注入引用类型对象

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

7.4 构造器注入--简单类型(了解)

7.4.1 在bean中定义简单类型属性并提供可访问的构造方法

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标签value属性注入简单类型数据

    <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标签type属性设置按形参类型注入数据

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

该方式解决参数名耦合问题。

7.4.4 配置中使用constructor-arg标签value属性设置按形参位置注入数据

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

该方式解决参数类型重复问题。

7.5 依赖注入方式选择

a. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
b. 可选依赖使用setter注入进行,灵活性强
c. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
d. 如果有必要可以两者同时使用呢,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
e. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
f. 自己开发的模块推荐使用setter注入

8. 依赖自动装配(autowire)

8.1 概念

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程成为自动装配。

8.2 自动装配方式

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. 自动装配用于引用类型依赖注入,不能对简单类型进行操作。
b. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用。
c. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用。
d. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置无效。

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 注入数组对象

    <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对象(重点)

    <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对象

    <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对象(重点)

    <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对象

    <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为例来讲解详细步骤。

10.1 在pom.xml中导入druid坐标

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

10.2 配置数据源对象作为Spring管理的bean

这个bean其实就是管理DruidDataSource对象

    <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>

测试一下如下:

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文件

比如创建一个jdbc.properties文件,加载jdbc.properties有多种写法如下:

11.2.1 正常加载properties

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

11.2.2 不加载系统属性

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

11.2.3 加载多个properties文件

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

11.2.4 加载所有properties文件

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

11.2.5 加载properties文件标准格式

<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

那么关于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>

总结

以上就是关于Spring快速入门详解的全部内容,本文详细介绍了使用xml配置的方式来使用Spring Framework

如果有什么问题,我们可以一起交流讨论解决。

最后,希望可以帮助到有需要的码友。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容