1. Spring 基础入门

news2024/11/26 11:31:25

文章目录

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/181024.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

file控件与input标签的属性type=“hidden“标签

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>file控件于与input标签的属性type"hidden"标签</title> </head> <body bgcolor"antiquewhite"> …

k8s中使用Deployment控制器实现升级、回滚、弹性伸缩

前置条件&#xff1a;linux机器已安装k8s集群基于yaml文件创建pod,本次创建pod使用的web.yaml如下apiVersion: apps/v1 kind: Deployment metadata:creationTimestamp: nulllabels:app: webname: web spec:replicas: 2selector:matchLabels:app: webstrategy: {}template:metad…

从零开始的数模(八)TOPSIS模型

一、概念 1.1评价方法概述 1.2概念 TOPSIS &#xff08;Technique for Order Preference by Similarity to an Ideal Solution &#xff09;模型中文叫做“逼近理想解排序方法”&#xff0c;是根据评价对象与理想化目标的接近程度进行排序的方法&#xff0c;是一种距离综合评…

SAP入门技术分享六:搜索帮助

搜索帮助1.概要&#xff08;1&#xff09;利用ABAP数据字典的搜索帮助&#xff08;2&#xff09;利用画面的搜索帮助&#xff08;3&#xff09;Dialog程序中的搜索帮助&#xff08;4&#xff09;报表选择屏幕PARAMETERS的搜索帮助&#xff08;5&#xff09;搜索帮助类型2.创建搜…

plot4gmns:面向通用建模网络范式(GMNS)的快速可视化【v0.1.1】

一款面向通用建模网络范式&#xff08;GMNS&#xff09;的快速可视化工具 目录1. 标准数据框架2. 标准数据框架下的生态2.1 数据解析2.2 数据处理2.3 数据可视化3. 标准数据框架下的可视化3.1 基础语法3.2 进阶语法1. 标准数据框架 制定一套标准的数据框架&#xff0c;可实现不…

python图像处理(中值滤波)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 中值滤波和均值滤波的区别,有点像中位数收入和平均收入的区别。比如有三个人,年收入分别是10万、1万和1千,那么他们的平均收入就是(10+1+0.1)/3,平均数是3.3万左右,但是中位数…

《真象还原》读书笔记——第二章 编写 MBR 主引导记录

2.1 计算机的启动过程 开机后运行的第一个程序是 BIOS 。 BIOS 搬运 MBR 并 跳转运行 MBR… 2.2 软件接力第一棒 BIOS 全名 基本输入输出系统。 2.2.1 实模式下的 1MB 内存分布 2.2.2 BIOS 是如何苏醒的 BIOS本身不需要修改&#xff0c;于是被写入了ROM中&#xff0c;被映…

更换新电脑,如何将旧电脑数据/文件传输到新电脑?

最好的数据迁移工具提供了一种简单的解决方案&#xff0c;可将您的数据从一台 PC 传输到另一台 PC。 如果您以前没有做过&#xff0c;那么数据迁移的整个过程可能看起来很吓人。无论您是企业用户还是家庭用户&#xff0c;尝试将所有文​​件和文件夹从一台计算机迁移到另一台计…

CCPC2022(桂林)

题目链接&#xff1a;https://codeforces.com/gym/104008 G Group Homework 题目大意&#xff1a;在树上选出两条链&#xff0c;使得在两条链选中的点中&#xff0c;只被一条链选中的点的点权和最大。 题解&#xff1a;显然两条链要么不相交&#xff0c;要么只相交于一个点。…

WhiteHole Base beta版本正式发布!

体验 当前版本为基础测试版本&#xff0c;测试效果可以前往演示视频查看&#xff1a;https://www.bilibili.com/video/BV18Y411D7sA/?spm_id_from333.999.0.0&vd_source641e71dfd1a118fb834c4a5d156688d5 在线体验地址为&#xff1a; http://47.100.239.95 数据将保存~ …

BGP基础实验

1.先配置好IP和环回 [R1]interface GigabitEthernet 0/0/0 [R1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [R1-GigabitEthernet0/0/0]int l 0 [R1-LoopBack0]ip add 1.1.1.1 24 其他同理 2.在R2&#xff0c;R3&#xff0c;R4上配置OSPF ospf 1 area 0.0.0.0 network 3.3.3.3…

线段树(原理,模板)

文章目录线段树线段树代码(单点修改、区间查询)懒惰标记与区间修改树状数组与区间修改线段树 线段树是用来维护 区间信息 的数据结构 它可以在 O(log⁡n)O(\log n)O(logn) 的时间复杂度内实现单点修改、区间修改、区间查询&#xff08;区间求和&#xff0c;求区间最大值&…

Reasoning Through Memorization: Nearest Neighbor Knowledge Graph Embeddings论文阅读

研究问题 将基于记忆的方法与预训练语言模型相结合&#xff0c;以完成知识图谱补全任务 背景动机 传统模型无法处理未见实体记忆增强神经网络的相关进展&#xff0c;即在传统的计算模块之外添加单独的记忆存储模块 模型方法 首先使用预训练语言模型构建实体的知识库&#…

计算机网络第一章 计算机网络与因特网

1.0 目录[TOC]1.1 什么是Internet&#xff1f;1.1.1 最细微&#xff1a;图&#xff08;Graph&#xff09;Internet由结点Node和边Edge组成结点Node分为主机结点和交换结点边Edge分为接入网链路Access和主干链路Backbone结构图如下&#xff1a;1.1.2 网络的网络&#xff08;Netw…

【Python】数值计算基础

note scipy和numpy库可以便捷地进行科学计算&#xff0c;如线性代数、常微分方程数值求解、信号处理、图像处理、稀疏矩阵等。 文章目录note一、多项式基础1. 1 多项式表示和拟合1.2 多项式插值二、微积分计算2.1 数值积分2.2 符号积分三、矩阵运算3.1 线性方程组的求解3.2 矩…

PHP代码审计之MVC与ThinkPHP简介

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是PHP代码审计之MVC与ThinkPHP简介。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严…

文化向技术投降

《技术垄断:文化向技术投降》泼斯曼 技术发展三个阶段 1&#xff0c;工具使用文化 2&#xff0c;技术统治文化 3&#xff0c;技术垄断文化 趣讲大白话&#xff1a;科技是一把双刃剑 泛滥的信息已经把人给弄懵了 *********** 广义上来讲&#xff0c;公司是技术公司 才有可能有更…

Windows压缩工具 “ Bandizip 与 7-zip ”

前言 &#x1f4dc;“作者 久绊A” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 目录 前言 一、什么是压缩 二、Bandizip的简介 1、大概介绍 2、详细…

Acwing---1238.日志统计

日志统计1.题目2.基本思想3.代码实现1.题目 小明维护着一个程序员论坛。现在他收集了一份”点赞”日志&#xff0c;日志共有 NNN 行。 其中每一行的格式是&#xff1a; ts id 表示在 tststs 时刻编号 ididid 的帖子收到一个”赞”。 现在小明想统计有哪些帖子曾经是”热帖…

一起自学SLAM算法:9.3 SVO算法

连载文章&#xff0c;长期更新&#xff0c;欢迎关注&#xff1a; 下面将从原理分析、源码解读和安装与运行这3个方面展开讲解SVO算法。 9.3.1 SVO原理分析 前面已经说过&#xff0c;SVO算法是半直接法的典型代表。因此在下面的分析中&#xff0c;首先介绍一下半直接法的基本原…