1. Spring 基础入门

1. 初识 spring

1.1 系统架构

请添加图片描述

1.2 学习路线

请添加图片描述

1.3 核心概念

请添加图片描述请添加图片描述
在业务层实现中,若 new BookDaoImpl() 改为 new BookDaoImpl2(),可能导致整个项目都要重新编译、重新测试。这样耦合度也偏高。

【解决方案】使用对象时,在程序中不要主动使用 new 产生对象,转换为由外部提供对象。

IoC 控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转(IoC—Inversion of Control)。

Spring 技术对 IoC 思想进行了实现:

  • Spring 提供了 IoC 容器,用来充当 IoC 思想中的”外部“。
  • IoC 容器负责对象的创建、初始化等工作,被创建或管理的对象在 IoC 容器中统称为 Bean。
  • IoC 容器又称 Spring 核心容器 / Spring 容器。

请添加图片描述

DI 依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入(Dependency Injection)。(bean 就是对象)

请添加图片描述

目标:充分解耦
使用IoC容器管理bean(IoC)
在IoC容器内将有依赖关系的bean进行关系绑定(DI)

最终效果
使用对象时不仅可以直接从 IoC 容器中获取,并且获取到的 bean 已经绑定了所有的依赖关系。

2. IoC 与 DI 入门案例(xml版)

2.1 IoC(控制反转)

新建 maven 项目后:
(1) 在 pom.xml 中配置如下:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId><!--所属群组-->
        <artifactId>spring-context</artifactId><!--spring的坐标-->
        <version>5.2.10.RELEASE</version><!--一个稳定的版本号-->
    </dependency>
</dependencies>

(2) 定义接口、类

public interface BookService {
    public void save();
}
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

(3) 配置 bean:在resource下新建applicationContext.xml
在这里插入图片描述

(4) 初始化 IoC 容器,通过容器获取 bean 中的对象,并调用对象方法

public class App {
    public static void main(String[] args) {
		//获取IoC容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		//获取bean中BookService的对象
		BookService bookService = (BookService) ctx.getBean("bookService");
		bookService.save();
	}
}
//输出:book service save ...
//     book dao save ...

2.2 DI(依赖注入)

上节的方式虽然在一定程度上解耦了,但 BookServiceImpl 类还有一个 new 对象语句,故解耦不彻底。下面就来解决这个问题。
(1) 删除使用 new 形式创建对象的代码
在这里插入图片描述
(2) 提供依赖对象对应的 setter 方法
在这里插入图片描述
(3) 配置 service 与 dao 之间的关系
在这里插入图片描述

3. bean 配置

3.1 bean 基础配置

在这里插入图片描述

3.2 bean 别名配置

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
【注意事项】获取 bean 时,无论通过 id 或 name 获取,若无法获取到,将抛出异常NoSuchBeanDefinitionException。如:
NoSuchBeanDefinitionException: No bean named ‘bookServiceImpl’ available

3.3 bean 作用范围配置

由下面的例子可知,spring 默认创建的 bean 是单例的。

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService1 = (BookService) ctx.getBean("service2");
System.out.println(bookService1);
BookService bookService2 = (BookService) ctx.getBean("service2");
System.out.println(bookService2);

输出结果:

service.impl.BookServiceImpl@6adede5
service.impl.BookServiceImpl@6adede5

通过修改配置文件可以使 spring 创建非单例的 bean,具体通过修改 bean 的 scope 属性来实现。
在这里插入图片描述
经过如下修改,spring 就能创建非单例的 bean。
在这里插入图片描述
输出结果:

service.impl.BookServiceImpl@6adede5
service.impl.BookServiceImpl@2d928643

4. bean 实例化

4.1 用构造方法实例化 bean

bean 一般通过构造方法创建,构造方法常常是 public 的,该构造方法用 private 修饰也可,原因在于反射机制,后面细讲。
构造方法由 IoC 容器自动调用。
在这里插入图片描述

创建 bean 时,只能调用无参构造方法,若硬要写有参构造方法会抛异常。
在这里插入图片描述

4.2 用静态工厂实例化 bean(了解)

(1) 准备接口和类

public interface OrderDao {
    public void save();
}
public class OrderDaoImpl implements OrderDao {
    @Override
    public void save() {
        System.out.println("order dao run...");
    }
}

(2) 产生对象的工厂

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

(3) 配置 bean

<!--必须指定工厂方法,否则就创建了OrderDaoFactory的对象-->
<bean id="orderDao" class="factory.OrderDaoFactory" factory-method="getOrderDao"/>

(4) 获取 IoC 容器、bean,调用方法

public class App2 {
    public static void main(String[] args) {
        //获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
        orderDao.save();
    }
}
输出:order dao run...

4.3 用实例工厂实例化 bean(了解)

(1) 需要的接口、类

public interface UserDao {
    public void save();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("user dao is running...");
    }
}

(2) 产生对象的工厂

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

(3) 配置 bean

<!--产生工厂对象-->
<bean id="userDaoFactory" class="factory.UserDaoFactory"/>
<!--利用工厂对象调用工厂方法,获得要生产的对象-->
<bean id="userDao" factory-bean="userDaoFactory" factory-method="getUserDao"/>

(4) 获取 IoC 容器、bean,调用方法

public class App2 {
    public static void main(String[] args) {
    	//原始方法
        //UserDaoFactory userDaoFactory = new UserDaoFactory();
        //UserDao userDao = userDaoFactory.getUserDao();
        //userDao.save();

        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}

4.4 FactoryBean

(1) 需要的接口、类

public interface UserDao {
    public void save();
}
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("user dao is running...");
    }
}

(2) 产生对象的 FactoryBean

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
    @Override
    //得到bean实例
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    //得到bean类型
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}

(3) 配置 bean

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

(4) 获取 IoC 容器、bean,调用方法

public class App2 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();
    }
}

关于 FactoryBean 接口中三个方法的作用:

public class UserDaoFactoryBean implements FactoryBean<UserDao> {
	//前两个方法是 FactoryBean 接口中的抽象方法,必须要实现
    @Override
    //得到bean实例
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    //得到bean类型
    public Class<?> getObjectType() {
        return UserDao.class;
    }

    @Override
    //控制bean是单例或非单例
    //不重写该方法时,默认单例,打印获取的bean可看出
    public boolean isSingleton() {
        return true;//单例
    }
}

5. 控制 bean 的生命周期

5.1 bean 的生命周期

bean 的生命周期:

  • 初始化容器
    (1) 创建对象(new 内存分配)
    (2) 执行构造方法
    (3) 执行属性注入(set 操作)
    (4) 执行bean初始化方法
  • 使用 bean
    执行业务操作
  • 关闭 / 销毁容器
    执行 bean 销毁方法

容器关闭前会触发 bean 的销毁,关闭容器方式有:

  • 手工关闭容器
    ConfigurableApplicationContext 接口 close() 操作
  • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
    ConfigurableApplicationContext 接口 registerShutdownHook() 操作

5.2 提供方法控制 bean 的生命周期

接口:

public interface BookDao {
    public void save();
}

提供生命周期控制方法:

public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
    //bean生命周期开始时执行的方法
    public void init(){
        System.out.println("init...");
    }
    //bean生命周期结束时执行的方法
    public void destory(){
        System.out.println("destory...");
    }
}

配置生命周期控制方法:

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

控制 bean 的生命周期:

public class app {
    public static void main(String[] args) {
        //IoC容器加载
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //bean初始化,拿到bean
        BookDao bookDao = (BookDao)ctx.getBean("bookDao");
        bookDao.save();
        //程序执行完,虚拟机马上退出,没有机会销毁bean,也就执行不了destroy方法
        //若要销毁bean,有两个方法
        //(1)在虚拟机退出之前,关闭容器(暴力方法)
        //ClassPathXmlApplicationContext类有close方法
        //ctx.close();
        //(2)注册关闭钩子,关闭虚拟机之前先关闭容器(温和方法)
        //在哪里加这句都可以,因为总是在程序结束之前
        ctx.registerShutdownHook();
    }
}

输出结果:

init...
book dao save ...
destory...

5.3 使用接口控制 bean 的生命周期(了解)

用service来演示:

public interface BookService {
    public void save();
}

实现 InitializingBean、DisposableBean 接口

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao;
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }

    public void setBookDao(BookDao bookDao) {
    	//System.out.println("setBookDao...");
        this.bookDao = bookDao;
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("service destroy");
    }

    @Override
    //afterPropertiesSet:在设置属性(set方法)之后执行
    public void afterPropertiesSet() throws Exception {
        System.out.println("service init");
    }
}
<bean id="bookDao" class="dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
<bean id="bookService" class="service.impl.BookServiceImpl">
    <property name="bookDao" ref="bookDao"/>
</bean>

加上上面的代码后,运行 app.java,输出如下:

init...
setBookDao...
service init
book dao save ...
service destroy
destory...

虽然 app.java 运行的是 bookDao 的方法,但是也输出了 bookService 的相关信息,这是因为 bean 加载了。

6. 依赖注入(DI)

6.1 依赖注入引入

向一个类中传递数据的方式有 2 种:

  • 普通方法(set 方法)
  • 构造方法

依赖注入描述了在容器中建立 bean 与 bean 之间依赖关系的过程,如果 bean 运行需要的是数字或字符串呢?所以下面要研究两种依赖注入方式:setter 注入构造器注入对于下面两种情况的处理方式:

  • 简单类型(基本数据类型与string)
  • 引用类型

6.2 setter 注入

6.2.1 引用类型的 setter 注入

定义引用类型属性并提供可访问的 set 方法

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

配置文件中使用 property 标签和 ref 属性注入引用类型对象

<bean id="bookDao" class="dao.impl.BookDaoImpl"/>
<bean id="userDao" class="dao.impl.UserDaoImpl"/>

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

测试:

public class app {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookService bookService = (BookService)ctx.getBean("bookService");
        bookService.save();
    }
}

输出结果:

book service save ...
book dao save ...
user dao save...

6.2.2 简单类型的 setter 注入

定义简单类型属性并提供可访问的 set 方法

public class BookDaoImpl implements BookDao {
    private int connectNum;
    private String database;

    public void setConnectNum(int connectNum) {
        this.connectNum = connectNum;
    }

    public void setDatabase(String database) {
        this.database = database;
    }

    public void save() {
        System.out.println("book dao save ..."+connectNum+" "+database);
    }
}

在配置中使用 property 标签 value 属性注入简单类型的数据

<bean id="bookDao" class="dao.impl.BookDaoImpl">
	<!--spring内部会把value的类型转换好-->
    <property name="connectNum" value="100"/>
    <property name="database" value="mysql"/>
</bean>

测试:

public class app {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao)ctx.getBean("bookDao");
        bookDao.save();
    }
}

输出结果:

book dao save ...100 mysql

6.3 构造器注入

6.3.1 引用类型的构造器注入

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    public BookServiceImpl(BookDao bookDao, UserDao userDao) {
        this.bookDao = bookDao;
        this.userDao = userDao;
    }

    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
        userDao.save();
    }
}
<bean id="bookDao" class="dao.impl.BookDaoImpl"/>
<bean id="userDao" class="dao.impl.UserDaoImpl"/>

<bean id="bookService" class="service.impl.BookServiceImpl">
	<!--顺序无妨-->
    <constructor-arg name="bookDao" ref="bookDao"/>
    <constructor-arg name="userDao" ref="userDao"/>
</bean>
public class app {
    public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		BookService bookService = (BookService)ctx.getBean("bookService");
		bookService.save();
	}
}

输出结果:

book service save ...
book dao save ...
user dao save...

6.3.2 简单类型的构造器注入

public class BookDaoImpl implements BookDao {
    private int connectNum;
    private String database;

    public BookDaoImpl(int connectNum, String database) {
        this.connectNum = connectNum;
        this.database = database;
    }

    public void save() {
        System.out.println("book dao save ..."+connectNum+" "+database);
    }
}
<bean id="bookDao" class="dao.impl.BookDaoImpl">
	<!--顺序无妨-->
    <constructor-arg name="connectNum" value="100"/>
    <constructor-arg name="database" value="mysql"/>
</bean>
public class app {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao)ctx.getBean("bookDao");
        bookDao.save();
    }
}

输出结果:

book dao save ...100 mysql

6.3.3 传参方式

方式 1:
在这里插入图片描述
当构造方法的形参不是 connectNum、database 时(如:num、data),方式 1 失效。

方式 2: 指定参数类型
在这里插入图片描述
当有重复类型的参数时,方式 2 失效。

方式 3: 指定参数顺序
在这里插入图片描述
当参数很多,且需要去掉 / 增加一些参数时,就要大规模变动 index,比较繁琐。

6.3.4 注入方式的选择

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

6.4 依赖自动装配

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

自动装配方式:

(1) 按类型装配(常用):autowire="byType"

在这里插入图片描述

【注意事项】

① 按类型装配时,可以连 id 都不要:

在这里插入图片描述

找不到要装配的类型或者该类型的 bean 不止一个时,报错。

在这里插入图片描述
在这里插入图片描述
该类型的 bean 不止一个时,可以按名称装配。

(2) 按名称装配:autowire="byName"

在这里插入图片描述

(3) 按构造方法(很少用)
(4) 不启用自动装配

自动装配的细节:

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

6.5 集合注入

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

    @Override
    public void save() {
        System.out.println("book dao save ...");
        System.out.println("遍历数组:"+ Arrays.toString(array));
        System.out.println("遍历List:"+list);
        System.out.println("遍历Set:"+ set);
        System.out.println("遍历Map:"+map);
        System.out.println("遍历Properties:"+properties);
    }
}
<bean id="bookDao" class="dao.impl.BookDaoImpl">
    <property name="array"><!--与set方法形参名保持一致-->
        <array><!--标签名,array写成list也可-->
            <value>100</value>
            <value>200</value>
            <value>300</value>
            <!--如果元素是引用类型,这样写:-->
            <!--<ref bean="beanId"/>-->
        </array>
    </property>
    <property name="list"><!--与set方法形参名保持一致-->
        <list><!--标签名,list写成array也可-->
            <value>itcast</value>
            <value>itheima</value>
            <value>boxuegu</value>
        </list>
    </property>
    <property name="set"><!--与set方法形参名保持一致-->
        <set><!--标签名-->
            <value>itcast</value>
            <value>itheima</value>
            <value>boxuegu</value>
            <value>boxuegu</value>
        </set>
    </property>
    <property name="map"><!--与set方法形参名保持一致-->
        <map><!--标签名-->
            <entry key="country" value="china"/>
            <entry key="province" value="henan"/>
            <entry key="city" value="kaifeng"/>
        </map>
    </property>
    <property name="properties"><!--与set方法形参名保持一致-->
        <props><!--标签名-->
            <prop key="country">china</prop>
            <prop key="province">henan</prop>
            <prop key="city">kaifeng</prop>
        </props>
    </property>
</bean>
public class app {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao)ctx.getBean("bookDao");
        bookDao.save();
    }
}

输出结果:

book dao save ...
遍历数组:[100, 200, 300]
遍历List[itcast, itheima, boxuegu]
遍历Set[itcast, itheima, boxuegu]
遍历Map{country=china, province=henan, city=kaifeng}
遍历Properties{province=henan, city=kaifeng, country=china}

7. 数据源对象管理

7.1 spring 管理第三方数据源对象

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId><!--druid数据源-->
    <version>1.1.16</version>
</dependency>
<bean class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>
public class app {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource = (DataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

输出结果:

{
	CreateTime:"2023-01-27 19:56:05",
	ActiveCount:0,
	PoolingCount:0,
	CreateCount:0,
	DestroyCount:0,
	CloseCount:0,
	ConnectCount:0,
	Connections:[
	]
}

7.2 加载 properties文件

在上节中,第三方 bean 的 property 标签中的 value 是写死的,除了这种方式,还可以从 properties 文件中加载 value。

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root

BookDaoImpl.java(用来验证)

public class BookDaoImpl implements BookDao {
    private String name;

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

    @Override
    public void save() {
        System.out.println("book dao save ..."+name);
    }
}

applicationContext.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: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
        "><!--1. 开启context命名空间-->
    <!--2. 使用context空间加载properties文件-->
    <context:property-placeholder location="jdbc.properties"/>
    <!--3. 使用属性占位符${}读取properties文件中的属性-->
    <bean 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>
    <!--上面加载properties文件的结果难以验证,
    所以下面做了一个类似的bean来验证-->
    <bean id="bookDao" class="dao.impl.BookDaoImpl">
        <property name="name" value="${jdbc.driver}"/>
    </bean>
</beans>
public class app {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}

输出结果:

book dao save ...com.mysql.jdbc.Driver

开启 context 命名空间时,applicationContext.xml 中需要更改的地方:
在这里插入图片描述

一些特殊情况:

(1)下面的第二个 bean 中,value 被赋的值不是 user666,而是系统的环境变量中的 username(系统的环境变量优先级高)。如果想要不被干扰,可以在加载 properities 文件时加入 system-properties-mode="NEVER"

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
username=user666
<!--使用context空间加载properties文件-->
<context:property-placeholder location="jdbc.properties"/>
<!--<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>-->
<bean 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>
<!--上面加载properties文件的结果难以验证,
所以下面做了一个类似的bean来验证-->
<bean id="bookDao" class="dao.impl.BookDaoImpl">
    <property name="name" value="${username}"/>
</bean>

(2)加载多个 properties 文件:

jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root

jdbc2.properties:

username=user666
<!--使用context空间加载properties文件-->
<context:property-placeholder location="jdbc.properties, jdbc2.properties" system-properties-mode="NEVER"/>
<bean 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>
<!--上面加载properties文件的结果难以验证,
所以下面做了一个类似的bean来验证-->
<bean id="bookDao" class="dao.impl.BookDaoImpl">
    <property name="name" value="${username}"/>
</bean>

(3)加载类路径下(自己工程下)的所有 properties 文件

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

或标准格式:

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

(3)加载类路径下(自己工程下)或 jar 包中的所有 properties 文件

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

8. 容器

(1) 加载配置文件(创建容器)

//方式1:加载类路径下的配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//方式2:从文件系统下加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\IdeaProjects\\spring10_container\\src\\main\\resources\\applicationContext.xml");

加载多个配置文件时(上面两种方式都能实现),配置文件之间用逗号隔开,如:"bean1.xml", "bean2.xml"

(2) 获取 bean

//方式1:强制转换
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//方式2:指定类型
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
//方式3:根据类型获取bean(不能有重复类型的bean)
BookDao bookDao = ctx.getBean(BookDao.class);

(3)容器层次结构
在这里插入图片描述

(4)spring 早期用 BeanFactory 创建容器(略)
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值