当前位置: 首页 > news >正文

1. Spring 基础入门

文章目录

  • 1. 初识 spring
    • 1.1 系统架构
    • 1.2 学习路线
    • 1.3 核心概念
  • 2. IoC 与 DI 入门案例(xml版)
    • 2.1 IoC(控制反转)
    • 2.2 DI(依赖注入)
  • 3. bean 配置
    • 3.1 bean 基础配置
    • 3.2 bean 别名配置
    • 3.3 bean 作用范围配置
  • 4. bean 实例化
    • 4.1 用构造方法实例化 bean
    • 4.2 用静态工厂实例化 bean(了解)
    • 4.3 用实例工厂实例化 bean(了解)
    • 4.4 FactoryBean
  • 5. 控制 bean 的生命周期
    • 5.1 bean 的生命周期
    • 5.2 提供方法控制 bean 的生命周期
    • 5.3 使用接口控制 bean 的生命周期(了解)
  • 6. 依赖注入(DI)
    • 6.1 依赖注入引入
    • 6.2 setter 注入
      • 6.2.1 引用类型的 setter 注入
      • 6.2.2 简单类型的 setter 注入
    • 6.3 构造器注入
      • 6.3.1 引用类型的构造器注入
      • 6.3.2 简单类型的构造器注入
      • 6.3.3 传参方式
      • 6.3.4 注入方式的选择
    • 6.4 依赖自动装配
    • 6.5 集合注入
  • 7. 数据源对象管理
    • 7.1 spring 管理第三方数据源对象
    • 7.2 加载 properties文件
  • 8. 容器

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 创建容器(略)
在这里插入图片描述

相关文章:

  • springboot 分布式全局唯一id的生成-雪花算法snowflake
  • 如何使用VMware虚拟机(带你快速了解)
  • Python---学生管理系统(pyinstaller)
  • 客快物流大数据项目(一百零八):Spring Cloud 技术栈
  • ZYNQ IP核之RAM
  • Day10 C++STL入门基础知识七——案例1【评委打分】
  • 计算机相关专业混体制的解决方案(考公务员)
  • OpenCV-PyQT项目实战(1)安装与环境配置
  • 【HTML | CSS】春节将至,为网页挂上精美的灯笼吧(附源码)程序员的浪漫
  • 字节青训前端笔记 | Next.js 入门
  • 下载Windows ISO镜像的方法 (超详细 适合新手入门)
  • OpenCV实战(8)——直方图详解
  • 这些低代码平台,你是否知悉?
  • TCP/IP网络编程——基于 TCP 的服务端/客户端(下)
  • 【高阶数据结构】海量数据如何处理? (位图 布隆过滤器)
  • 《深入 React 技术栈》
  • 【5+】跨webview多页面 触发事件(二)
  • Java反射-动态类加载和重新加载
  • PhantomJS 安装
  • SpiderData 2019年2月25日 DApp数据排行榜
  • Spring-boot 启动时碰到的错误
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • Xmanager 远程桌面 CentOS 7
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 从tcpdump抓包看TCP/IP协议
  • 对象引论
  • 飞驰在Mesos的涡轮引擎上
  • 搞机器学习要哪些技能
  • 记录一下第一次使用npm
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • #HarmonyOS:Web组件的使用
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (C)一些题4
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (办公)springboot配置aop处理请求.
  • (附源码)springboot 智能停车场系统 毕业设计065415
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (五)IO流之ByteArrayInput/OutputStream
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .chm格式文件如何阅读
  • .net快速开发框架源码分享
  • .net用HTML开发怎么调试,如何使用ASP.NET MVC在调试中查看控制器生成的html?
  • .Net语言中的StringBuilder:入门到精通
  • 。Net下Windows服务程序开发疑惑
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • @Autowired 与@Resource的区别
  • @require_PUTNameError: name ‘require_PUT‘ is not defined 解决方法
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • []Telit UC864E 拨号上网