Spring-01的升级版本是哪个型号?

2026-05-05 16:541阅读0评论SEO资源
  • 内容介绍
  • 相关推荐

本文共计7318个文字,预计阅读时间需要30分钟。

Spring-01的升级版本是哪个型号?

内容+Spring+概念+Spring+快速入门+Spring+的IoC+和+DI+Bean+基本配置+Bean+生命周期+Bean+实例化+Bean+注入+1.+Spring+概念

1.1+概念+Spring+是分层的JavaSE/EE应用full-stack轻量级开源框架+1.2+Spring+全家桶+目前“

内容
  • Spring概念
  • Spring快速入门
  • Spring的IoC 和 DI
  • Bean基本配置
  • Bean生命周期
  • Bean实例化
  • Bean注入
1. Spring概念 1.1 概念
  • Spring是分层的JavaSE/EE应用 full-stack轻量级开源框架
1.2 Spring全家桶

目前学习的是Spring Framework,是Spring全家桶的基础。

Spring-01的升级版本是哪个型号?

1.3 Spring体系
  • Spring体系结构图

  • SSM的提供的解决方案

    • MybatisDao层框架
    • SpringMVCweb层框架
    • Spring:软件三层中都可以看到Spring的应用场景
1.4 发展历程
  • Spring之父 Rod Johnson
  • EJB Enterprise Java Beansun公司提出来的大型web项目的架构
  • Expert One-on-One J2EE Design and Development 2002年 手把手教你怎么使用EJB开发大型web项目
  • Expert one-on-one J2EE Development without EJB 2004 手把手教你怎么不使用EJB开发大型web项目 (Spring的原型)
  • 官网:spring.io/projects
  • 课堂版本5.x
1.5 Spring优势
  • 方便解耦,简化开发

  • 方便集成各种优秀框架(不排斥、慢慢整合)

  • AOP(面向切面编程)编程的支持

  • 声明式事务的支持

  • Java源码是经典学习范例

  • 方便程序的测试(Spring整合junit)

1.6 Spring两大核心思想
  • IoC:Inverse of Control 控制反转 ,目的:解耦

  • AOP:Aspect Oriented Programming 面向切面编程

  • Spring演化过程

    基于接口编程servicedao之间高度耦合

    工厂+配置文件:解除了耦合,留下配置文件和dao/工厂耦合,这种耦合是我们期望的一种耦合方式

  • IoC 控制反转

  • Inverse of Control

    把对象的创建权、依赖的注入权从程序员手中,反转到了Spring容器创建并提供

2. Spring quick Start 2.0 准备工作:配置私服

<!-- 略 --> 2.1 IOC实现步骤

  1. 导入Spring依赖坐标:spring-context-5.2.10.RELEASE
  2. 编写service/dao接口和实现类
  3. Spring核心配置文件中配置service/dao实现类
  4. 测试类中创建Spring容器对象,并通过对象获取service/dao实现类对象
  5. 调用service/dao实现类对象的方法测试
2.1.1 配置依赖坐标

新建模块/导入模块

<dependencies> <!-- 配置Spring的依赖坐标 会根据依赖传传递自动导入其依赖的其他坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies> 2.1.2 编写service/dao实现类和接口

BookDao.java接口

package com.cy.dao; public interface BookDao { public void save(); }

BookDaoImpl.java实现类

package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } }

BookService接口

package com.cy.service; public interface BookService { public void save(); }

BooKServiceImpl实现类

package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.dao.impl.BookDaoImpl; import com.cy.service.BookService; public class BookServiceImpl implements BookService { private BookDao bookDao = new BookDaoImpl(); public void save() { System.out.println("book service save ..."); bookDao.save(); } } 2.1.3 新建Spring的配置文件并配置

resources 右键 选择 new--》xml configration file --》Spring config(前提是Spring的依赖已经成功导入)

配置文件名称任意,习惯写法applicationcontext.xml。本案中使用beans.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 把Bean装配进Spring容器 id 唯一标识,任意起名,但是尽量使用提示的名字 class 全限定类名(用于反射创建对象) 小提示:先写class,只写类名有提示;再写id,也有提示 --> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> </beans> 2.1.4 创建Spring容器对象并获取bean对象

/** * @Description: 测试Spring容器创建和获取对象 */ package com.cy; import com.cy.dao.BookDao; import com.cy.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App2 { public static void main(String[] args) { //3.获取IoC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //4.获取bean(根据bean配置id获取) // BookDao bookDao = (BookDao) ctx.getBean("bookDao"); // bookDao.save(); BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); } } 2.2 DI实现步骤 2.2.1 DI概念

全称:Dependency InjectionService用到daoService就依赖了Dao,就需要把Dao注入到Service中。

之前的注入方式:

  • 之前Service中的dao都是我们自己new的;

使用Spring中的依赖注入

  • 我们就不需要自己newSpring会自动找到(创建)Dao对象,并设置给Service中的成员变量。
2.2.2 实现步骤
  1. 基于IoC快速入门代码,完成下面操作。
  2. 删除被依赖对象的new创建代码,并提供setter
  3. Spring配置文件中配置依赖关系
2.2.3 修改代码

BookServiceImpl.java

public class BookServiceImpl implements BookService { //5.删除业务层中使用new的方式创建的dao对象 private BookDao xxx; public void save() { System.out.println("book service save ..."); xxx.save(); } //6.提供对应的set方法 public void setBookDao(BookDao xxx) { this.xxx = xxx; } } 2.2.4 修改配置

<!-- 把Bean装配进Spring容器 id 唯一标识,任意起名,但是尽量使用提示的名字 class 全限定类名(用于反射创建对象) 小提示:先写class,只写类名有提示;再写id,也有提示 --> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <!--7.配置server与dao的关系--> <!-- property标签表示配置当前bean的属性 name属性值为对应类中成员变量名。本质上是通过成员变量的setter为其赋值。 ref属性值为spring容器中已经存在的另一bean的id --> <property name="bookDao" ref="bookDao"/> </bean> </bean>

其他代码保持不变,直接运行测试方法即可。

3. Spring配置-Bean标签 3.1 id&class属性
  • id:唯一标识,同一个Spring容器中不允许重复
  • class:全限定类名,用于反射创建对象

XML配置

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 把Bean装配进Spring容器 id 唯一标识,任意起名,但是尽量使用提示的名字 class 全限定类名(用于反射创建对象) --> <bean class="com.cy.dao.impl.BookDaoImpl" id="bookDao"/> </beans>

测试代码

/** * @Description: 测试Spring容器创建和获取对象 */ public class UserServiceImpl { public static void main(String[] args) { // 创建容器对象,并加载配置文件 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); // 从容器对象中获取bean对象 BookDao bookDao = (BookDao) app.getBean("bookDao"); // 使用获取的bean对象 bookDao.save(); } } 3.2 name 属性

bean其别名,可以配置多个值,多个值之间使用空格/逗号/分号分隔

  • XML配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔--> <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> </beans>

  • 演示代码

    package com.cy; import com.cy.dao.BookDao; import com.cy.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppForName { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // 可以通过bean标签name属性的值,获取对应的bean对象 // BookService bookService = (BookService) ctx.getBean("service"); // 如果传递参数不能成功匹配id和name的值,则会报错。NoSuchBean*** BookService bookService = (BookService) ctx.getBean("service"); bookService.save(); } }

3.3 scope 属性

这个很重要,但是一般使用默认值,单例!

  • 概念:单例:在整个项目中,某个类的对象有且仅有一个,这种情况,就是单(个实)例。

  • Spring中的Bean默认是单例的。

  • XML配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype--> <bean id="bookDao" name="dao" class="com.cy.dao.impl.BookDaoImpl" scope="prototype"/> </beans>

  • 演示代码

    package com.cy; import com.cy.dao.BookDao; import com.cy.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppForScope { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao1 = (BookDao) ctx.getBean("bookDao"); BookDao bookDao2 = (BookDao) ctx.getBean("bookDao"); System.out.println(bookDao1); System.out.println(bookDao2); } }

  • Spring可以帮我们维护已有项目中哪些类和对象

    可以单例的

    • Dao
    • Service
    • Servlet/Controller
    • Utils

    不是单例的一般不会让Spring维护

    • 实体类(数据传输的载体)
4. Bean的实例化 4.1 Spring之前对象实例化方式
  • 方式1:通过构造方法直接创建

    // 方式1:通过构造方法直接创建 BookDaoImpl bookDao = new BookDaoImpl();

  • 方式2:实例工厂方式

    /* 工厂类 */ public class BookDaoImplFactory { // 提供方法,返回一个BookDaoImpl的对象 public BookDaoImpl getObject(){ // 假装这里有非常复杂的流程 return new BookDaoImpl(); } }

    /** 测试代码***/ // 方式2:实例工厂方式 // 2.1 创建工厂对象 BookDaoImplFactory factory = new BookDaoImplFactory(); // 2.2 通过工厂对象获取目标对象 BookDaoImpl booDao1 = factory.getObject();

  • 方式3:静态工厂方式

    /* 静态工厂类 */ class BookDaoImplFactoryStatic { // 提供静态方法,返回一个BookDaoImpl的对象 public static BookDaoImpl getObject(){ // 假装这里有非常复杂的流程 return new BookDaoImpl(); } }

    // 方式3:静态工厂方式 BookDaoImpl bookDao2 = BookDaoImplFactoryStatic.getObject();

4.2 Spring中构造方法实例化
  • 快速入门案例中,Spring使用的就是通过反射无参构造创建的对象。

  • 无参构造

    OrderDao OrderDao2 = new OrderDaoImpl();

    对应Spring中的配置

    <!-- 如下配置的效果: 通过class的值获取全限定类名,然后通过反射调用无参构造方法, 创建对象并装配进Spring容器,起名为id的值。 --> <bean id="bookDao" class="com.cy.dao.impl.OrderDaoImpl"/>

  • 如果未提供给无参构造方法,会因为找不到该方法而报错。NoSuchMethodException *** init()

4.3 Spring中静态工厂实例化
  • 静态工厂

    // 方式3:静态工厂方式 OrderDao OrderDao2 = OrderDaoFactory.getOrderDao();

    对应Spring中配置

    <!-- 通过OrderDaoFactory的静态方法,获取OrderDao对象 Spring容器中会产生一个orderDao对象 该对象的名字是id的值 --> <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

    Spring容器中,获取方式和之前一样,通过id获取对象并使用。

  • 应用场景

    1. 兼容老的项目
    2. 创建过程比较复杂的对象,一般都是使用工厂模式
4.4 Spring中实例工厂实例化
  • 实例工厂

    // 方式3:实例工厂方式 // 创建工厂对象 UserDaoFactory factory = new UserDaoFactory(); // 通过工厂对象,得到目标对象 UserDao userDao = factory.getUserDao();

    对应Spring中配置

    <!-- 通过UserDaoFactory的成员方法,获取UserDao对象 Spring容器中会产生一个UserDaoFacotry对象、UserDao对象 UserDaoFacotry对象的名字是其id的值 UserDao=对象的名字是其id的值 --> <!--方式三:使用实例工厂实例化bean--> <!-- 装配工厂Bean,得到一个工厂的Bean对象 --> <bean id="userFactory" class="com.cy.factory.UserDaoFactory"/> <!-- 通过工厂Bean对象获取目标Bean对象 --> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

    Spring容器中,获取方式和之前一样,通过id获取对象并使用。

4.5 SpringFactoryBean实例化
  • 该方式是在第三种方法的简化改良。编码基本雷同,配置相对简单。

  • 实现步骤

    1. 编写工厂类实现FactoryBean。类名一般为xxxFactoryBean,泛型为目标对象类型xxx
    2. 实现getObject()方法、getObjectType()方法。
    3. Spring配置文件中简单配置。
  • xxxFactoryBean

    package com.cy.factory; import com.cy.dao.UserDao; import com.cy.dao.impl.UserDaoImpl; import org.springframework.beans.factory.FactoryBean; //FactoryBean创建对象 public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始实例工厂中创建对象的方法 public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } /** * 该方法一般不用重写 * 决定获取的Bean是否为单例。默认返回true。 * true 单例 singleton * false 多例(非单例) prototype * @return */ public boolean isSingleton() { return true; } }

  • XML配置

    <!-- 方式四:使用FactoryBean实例化bean 配置方式和第一种使用构造方法实例化凡是类似,但是class属性值是一个FactoryBean的实现类 Spring容器中会产生一个UserDaoFactoryBean对象、UserDao对象 UserDao对象的名字是改标签的id值 --> <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

  • 应用场景

    Spring在整合其他框架时,多用该方式。

5 生命周期

生命周期:对象从出生到死亡的整个过程。

5.1 配置实现
  1. 提前准备好两个方法,方法名任意 xxx yyy

    package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } //表示bean初始化对应的操作 public void xxx(){ System.out.println("init..."); } //表示bean销毁前对应的操作 public void yyy(){ System.out.println("destory..."); } }

  2. Spring配置文件对应bean标签上添加两个属性,属性值不用带小括号

    <!--init-method:设置bean初始化生命周期回调函数--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象--> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl" init-method="xxx" destroy-method="yyy"/>

5.2 实现接口

package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean { public void save() { System.out.println("book dao save ..."); } // 实现InitializingBean中抽象方法,该方法会在init-method指定的方法执行后执行 public void afterPropertiesSet() throws Exception { System.out.println("service init"); } // 实现DisposableBean充抽象方法 public void destroy() throws Exception { System.out.println("service destroy"); } } 5.3 注意

需要手动关闭容器才能看到销毁代码的执行。

  • Spring容器关闭的功能,在Config***的子接口中规定的,需要向下转型到其子类才能调用,一般直接使用ClasspathXMLApplicationContext
  • 也可以注册关闭的钩子ctx.registerShutdownHook(),会在执行完代码后自动关闭。
5.4 声明周期(11步)
  • 初始化容器
    • 创建Bean对象(内存分配)
    • 执行构造方法
    • 执行属性注入(set操作)
    • 执行bean初始化方法
  • 使用bean
    • 执行业务操作
  • 关闭/销毁容器
    • 执行bean销毁方法
6. 依赖注入 6.1 概念

Dependency Injection,DI

依赖:在A类中用到了B类,就说A依赖B,需要在A类中添加一个B类型的成员变量;

依赖注入:把B类对象设置进A中B类型的成员变量的过程,称为依赖注入。

Spring会把B类对象注入到A类中B类型的属性上。自动完成注入。

// 伪代码演示 class A{ // 为B类型的b变量初始化的过程,称为依赖注入 B b; }

依赖注入可以理解成IoC的一种应用场景,反转的是对象间依赖关系维护注入权

6.2 IoCDI的关系(面试题)

IoC是一种思想(规范),可以把对象的创建权、对象间依赖关系的维护注入权等从程序员手中,反转到了Spring容器中;

DI依赖注入,只是IoC在某个方面的一个具体实现,在 依赖关系维护注入 方面的一个实现。

6.3 注入方式

本质上就是为某个类的成员变量赋值的方式:setter/有参构造

/* 1. 提供有参构造方法,通过构造方法在创建对象的同时为成员变量赋值 2. 提供setter,通过setter为成员变量赋值 */ 6.4 Setter方式注入

注入引用类型(容器中已经存在的其他Bean对象)

  1. 保证被注入的Bean和目标Bean都已经装配到Spring容器

    <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"></bean> <bean id="userDao" class="com.cy.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"></bean>

  2. BookServiceImpl类中添加UserDao/BookDao的属性并提供setter

    package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.dao.UserDao; import com.cy.service.BookService; public class BookServiceImpl implements BookService{ private BookDao bookDao; private UserDao userDao; //setter注入需要提供要注入对象的set方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } //setter注入需要提供要注入对象的set方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); userDao.save(); } }

  3. 通过<property>子标签完成注入

    <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"></bean> <bean id="userDao" class="com.cy.dao.impl.UserDaoImpl"/> <!--注入引用类型--> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <!--property标签:设置注入属性--> <!--name属性:设置注入的属性名,实际是set方法对应的名称--> <!--ref属性:Spring容器中已经存在的符合要求的Bean--> <property name="bookDao" ref="bookDao"/> <property name="userDao" ref="userDao"/> </bean>

注入简单数据类型数据

String + 基本数据类型

只需要把生面的配置文件中ref属性换成value属性即可。

<!--注入简单类型--> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <!--property标签:设置注入属性--> <!--name属性:设置注入的属性名,实际是set方法对应的名称--> <!--value属性:设置注入简单类型数据值--> <property name="connectionNum" value="100"/> <property name="databaseName" value="mysql"/> </bean>

package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao { private String databaseName; private int connectionNum; //setter注入需要提供要注入对象的set方法 public void setConnectionNum(int connectionNum) { this.connectionNum = connectionNum; } //setter注入需要提供要注入对象的set方法 public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } public void save() { System.out.println("book dao save ..."+databaseName+","+connectionNum); } } 6.5 构造器注入

不常用

  • 被装配的类中提供有参构造,而不需要提供setter

    package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.dao.UserDao; import com.cy.service.BookService; public class BookServiceImpl implements BookService{ private BookDao bookDao; private UserDao userDao; // 有参构造,不需要提供setter 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(); } }

  • XML中通过子标签配置constructor-arg

    <!-- 标准书写 --> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"></bean> <bean id="userDao" class="com.cy.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <!-- 根据构造方法参数名称注入 name值只为有参构造中形参的名称 ref值为Spring容器中已近存在的其他Bean的id value:简单类型使用value注入 --> <constructor-arg name="userDao" ref="userDao"/> <constructor-arg name="bookDao" ref="bookDao"/> </bean>

  • value属性注入简单类型

    <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <!-- 根据构造方法参数类型注入 --> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean>

6.6 自动装配

自动为当前Bean完成依赖注入,简称自动装配,可取值byName | byType | constructor,分别代表按照

  1. byType:按照属性类型Spring容器中bean进行匹配,完成自动装配注入
  2. byName:按照属性名Spring容器中bean的id进行匹配,完成自动装配注入
  3. constructor:按照构造方法的形参类型Spring容器中bean进行匹配,完成自动装配注入

注意:上述中属性值的是setter或者是构造形参,而非成员变量本身。

xml中配置:把所有的Bean都配置进Spring容器。

<bean id = "bookDao" class="com.cy.dao.impl.BookDaoImpl"/> <!-- <bean class="com.cy.dao.impl.BookDaoImpl"/> --> <!-- autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl" autowire="byType"/>

java代码

package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.service.BookService; public class BookServiceImpl implements BookService{ private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } } 6.7 注意事项

  1. 优选自动装配
  2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
6.8 集合注入

了解即可。

<bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <!-- 单例集合 list set array 配置通用 ,建议使用list 双列集合 map properties 配置通用 ,建议使用Map --> <!--set集合注入--> <property name="set"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property> <!--map集合注入--> <property name="map"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property> <!--Properties注入--> <property name="properties"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property> </bean>

package com.cy.dao.impl; import com.cy.dao.BookDao; import java.util.*; public class BookDaoImpl implements BookDao { private String[] array; private List<String> list; private Set<String> set; private Map<String,String> map; private Properties properties; public void setArray(String[] 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; } 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); } } 7. 案例练习

无论是自己写的类要装配进Spring容器,还是第三方的类要装配进Spring容器,只需要遵循Spring的配置规则即可。

后者与前者的不同,仅仅是把自己编写代码变成了导入依赖坐标,配置方式一致。

7.1 DruidDataSource 7.1.1 导入依赖坐标

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="maven.apache.org/POM/4.0.0" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="maven.apache.org/POM/4.0.0 maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cy</groupId> <artifactId>ssm01_spring01_11_datasource</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> </dependencies> </project> 7.1.2 Spring装配配置

<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> 7.1.3 测试

package com.itheima; import com.itheima.dao.BookDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; 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); } } 7.2 C3P0数据源

老牌数据源管理工具,曾经久不衰。

7.2.1 导入依赖坐标

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="maven.apache.org/POM/4.0.0" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="maven.apache.org/POM/4.0.0 maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>ssm01_spring01_11_datasource</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies> </project> 7.2.2 Spring装配配置

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="user" value="root"/> <property name="password" value="root"/> <property name="maxPoolSize" value="1000"/> </bean> 7.2.3 测试

package com.cy; import com.cy.dao.BookDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; 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); } } 8 引入properties文件 8.1 创建properties文件

  • jdbc.properties

    # 不要使用username,否则会错误的获取到当前系统的用户名。建议使用jdbc.username jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db jdbc.username=root jdbc.password=root

8.2 beans.xml文件引入 jdbc.properties文件

<!-- 在类路径下加载指定名称的properties配置文件,classpath:可以省略不写。下同 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 在类路径下加载多个指定名称的properties配置文件 --> <context:property-placeholder location="classpath:jdbc.properties,jdbc2.properties"/> <!-- 在类路径下加载所有的properties配置文件 --> <context:property-placeholder location="classpath:*.properties"/> <!-- 在类路径+jar包中(整个项目下)加载所有的properties配置文件 统配会造成效率降低,速度变慢 --> <context:property-placeholder location="classpath*:*.properties"/> <!-- 使用属性占位符${},可以通过properties文件中的key读取到对应的值 OGNL ${} 所有的框架都支持这个种写法,从当前容器对象中根据key获取值 Spring容器会把当前系统的内置变量整合进自己的容器 username=当前系统的用户名 且优先级高于我们自己配置的。 ${username} 会获取当前系统的用户名 解决方案: 1. 不要使用username,使用诸如jdbc.username。推荐写法。 2. 通过其属性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> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <property name="name" value="${username}"/> </bean> 8.3 代码测试

package com.cy; import com.cy.dao.BookDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; public class App { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); } }

本文共计7318个文字,预计阅读时间需要30分钟。

Spring-01的升级版本是哪个型号?

内容+Spring+概念+Spring+快速入门+Spring+的IoC+和+DI+Bean+基本配置+Bean+生命周期+Bean+实例化+Bean+注入+1.+Spring+概念

1.1+概念+Spring+是分层的JavaSE/EE应用full-stack轻量级开源框架+1.2+Spring+全家桶+目前“

内容
  • Spring概念
  • Spring快速入门
  • Spring的IoC 和 DI
  • Bean基本配置
  • Bean生命周期
  • Bean实例化
  • Bean注入
1. Spring概念 1.1 概念
  • Spring是分层的JavaSE/EE应用 full-stack轻量级开源框架
1.2 Spring全家桶

目前学习的是Spring Framework,是Spring全家桶的基础。

Spring-01的升级版本是哪个型号?

1.3 Spring体系
  • Spring体系结构图

  • SSM的提供的解决方案

    • MybatisDao层框架
    • SpringMVCweb层框架
    • Spring:软件三层中都可以看到Spring的应用场景
1.4 发展历程
  • Spring之父 Rod Johnson
  • EJB Enterprise Java Beansun公司提出来的大型web项目的架构
  • Expert One-on-One J2EE Design and Development 2002年 手把手教你怎么使用EJB开发大型web项目
  • Expert one-on-one J2EE Development without EJB 2004 手把手教你怎么不使用EJB开发大型web项目 (Spring的原型)
  • 官网:spring.io/projects
  • 课堂版本5.x
1.5 Spring优势
  • 方便解耦,简化开发

  • 方便集成各种优秀框架(不排斥、慢慢整合)

  • AOP(面向切面编程)编程的支持

  • 声明式事务的支持

  • Java源码是经典学习范例

  • 方便程序的测试(Spring整合junit)

1.6 Spring两大核心思想
  • IoC:Inverse of Control 控制反转 ,目的:解耦

  • AOP:Aspect Oriented Programming 面向切面编程

  • Spring演化过程

    基于接口编程servicedao之间高度耦合

    工厂+配置文件:解除了耦合,留下配置文件和dao/工厂耦合,这种耦合是我们期望的一种耦合方式

  • IoC 控制反转

  • Inverse of Control

    把对象的创建权、依赖的注入权从程序员手中,反转到了Spring容器创建并提供

2. Spring quick Start 2.0 准备工作:配置私服

<!-- 略 --> 2.1 IOC实现步骤

  1. 导入Spring依赖坐标:spring-context-5.2.10.RELEASE
  2. 编写service/dao接口和实现类
  3. Spring核心配置文件中配置service/dao实现类
  4. 测试类中创建Spring容器对象,并通过对象获取service/dao实现类对象
  5. 调用service/dao实现类对象的方法测试
2.1.1 配置依赖坐标

新建模块/导入模块

<dependencies> <!-- 配置Spring的依赖坐标 会根据依赖传传递自动导入其依赖的其他坐标 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies> 2.1.2 编写service/dao实现类和接口

BookDao.java接口

package com.cy.dao; public interface BookDao { public void save(); }

BookDaoImpl.java实现类

package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } }

BookService接口

package com.cy.service; public interface BookService { public void save(); }

BooKServiceImpl实现类

package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.dao.impl.BookDaoImpl; import com.cy.service.BookService; public class BookServiceImpl implements BookService { private BookDao bookDao = new BookDaoImpl(); public void save() { System.out.println("book service save ..."); bookDao.save(); } } 2.1.3 新建Spring的配置文件并配置

resources 右键 选择 new--》xml configration file --》Spring config(前提是Spring的依赖已经成功导入)

配置文件名称任意,习惯写法applicationcontext.xml。本案中使用beans.xml

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 把Bean装配进Spring容器 id 唯一标识,任意起名,但是尽量使用提示的名字 class 全限定类名(用于反射创建对象) 小提示:先写class,只写类名有提示;再写id,也有提示 --> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> </beans> 2.1.4 创建Spring容器对象并获取bean对象

/** * @Description: 测试Spring容器创建和获取对象 */ package com.cy; import com.cy.dao.BookDao; import com.cy.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App2 { public static void main(String[] args) { //3.获取IoC容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //4.获取bean(根据bean配置id获取) // BookDao bookDao = (BookDao) ctx.getBean("bookDao"); // bookDao.save(); BookService bookService = (BookService) ctx.getBean("bookService"); bookService.save(); } } 2.2 DI实现步骤 2.2.1 DI概念

全称:Dependency InjectionService用到daoService就依赖了Dao,就需要把Dao注入到Service中。

之前的注入方式:

  • 之前Service中的dao都是我们自己new的;

使用Spring中的依赖注入

  • 我们就不需要自己newSpring会自动找到(创建)Dao对象,并设置给Service中的成员变量。
2.2.2 实现步骤
  1. 基于IoC快速入门代码,完成下面操作。
  2. 删除被依赖对象的new创建代码,并提供setter
  3. Spring配置文件中配置依赖关系
2.2.3 修改代码

BookServiceImpl.java

public class BookServiceImpl implements BookService { //5.删除业务层中使用new的方式创建的dao对象 private BookDao xxx; public void save() { System.out.println("book service save ..."); xxx.save(); } //6.提供对应的set方法 public void setBookDao(BookDao xxx) { this.xxx = xxx; } } 2.2.4 修改配置

<!-- 把Bean装配进Spring容器 id 唯一标识,任意起名,但是尽量使用提示的名字 class 全限定类名(用于反射创建对象) 小提示:先写class,只写类名有提示;再写id,也有提示 --> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <!--7.配置server与dao的关系--> <!-- property标签表示配置当前bean的属性 name属性值为对应类中成员变量名。本质上是通过成员变量的setter为其赋值。 ref属性值为spring容器中已经存在的另一bean的id --> <property name="bookDao" ref="bookDao"/> </bean> </bean>

其他代码保持不变,直接运行测试方法即可。

3. Spring配置-Bean标签 3.1 id&class属性
  • id:唯一标识,同一个Spring容器中不允许重复
  • class:全限定类名,用于反射创建对象

XML配置

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 把Bean装配进Spring容器 id 唯一标识,任意起名,但是尽量使用提示的名字 class 全限定类名(用于反射创建对象) --> <bean class="com.cy.dao.impl.BookDaoImpl" id="bookDao"/> </beans>

测试代码

/** * @Description: 测试Spring容器创建和获取对象 */ public class UserServiceImpl { public static void main(String[] args) { // 创建容器对象,并加载配置文件 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); // 从容器对象中获取bean对象 BookDao bookDao = (BookDao) app.getBean("bookDao"); // 使用获取的bean对象 bookDao.save(); } } 3.2 name 属性

bean其别名,可以配置多个值,多个值之间使用空格/逗号/分号分隔

  • XML配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!--name:为bean指定别名,别名可以有多个,使用逗号,分号,空格进行分隔--> <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> </beans>

  • 演示代码

    package com.cy; import com.cy.dao.BookDao; import com.cy.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppForName { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); // 可以通过bean标签name属性的值,获取对应的bean对象 // BookService bookService = (BookService) ctx.getBean("service"); // 如果传递参数不能成功匹配id和name的值,则会报错。NoSuchBean*** BookService bookService = (BookService) ctx.getBean("service"); bookService.save(); } }

3.3 scope 属性

这个很重要,但是一般使用默认值,单例!

  • 概念:单例:在整个项目中,某个类的对象有且仅有一个,这种情况,就是单(个实)例。

  • Spring中的Bean默认是单例的。

  • XML配置

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="www.springframework.org/schema/beans" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.springframework.org/schema/beans www.springframework.org/schema/beans/spring-beans.xsd"> <!--scope:为bean设置作用范围,可选值为单例singloton,非单例prototype--> <bean id="bookDao" name="dao" class="com.cy.dao.impl.BookDaoImpl" scope="prototype"/> </beans>

  • 演示代码

    package com.cy; import com.cy.dao.BookDao; import com.cy.service.BookService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AppForScope { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao1 = (BookDao) ctx.getBean("bookDao"); BookDao bookDao2 = (BookDao) ctx.getBean("bookDao"); System.out.println(bookDao1); System.out.println(bookDao2); } }

  • Spring可以帮我们维护已有项目中哪些类和对象

    可以单例的

    • Dao
    • Service
    • Servlet/Controller
    • Utils

    不是单例的一般不会让Spring维护

    • 实体类(数据传输的载体)
4. Bean的实例化 4.1 Spring之前对象实例化方式
  • 方式1:通过构造方法直接创建

    // 方式1:通过构造方法直接创建 BookDaoImpl bookDao = new BookDaoImpl();

  • 方式2:实例工厂方式

    /* 工厂类 */ public class BookDaoImplFactory { // 提供方法,返回一个BookDaoImpl的对象 public BookDaoImpl getObject(){ // 假装这里有非常复杂的流程 return new BookDaoImpl(); } }

    /** 测试代码***/ // 方式2:实例工厂方式 // 2.1 创建工厂对象 BookDaoImplFactory factory = new BookDaoImplFactory(); // 2.2 通过工厂对象获取目标对象 BookDaoImpl booDao1 = factory.getObject();

  • 方式3:静态工厂方式

    /* 静态工厂类 */ class BookDaoImplFactoryStatic { // 提供静态方法,返回一个BookDaoImpl的对象 public static BookDaoImpl getObject(){ // 假装这里有非常复杂的流程 return new BookDaoImpl(); } }

    // 方式3:静态工厂方式 BookDaoImpl bookDao2 = BookDaoImplFactoryStatic.getObject();

4.2 Spring中构造方法实例化
  • 快速入门案例中,Spring使用的就是通过反射无参构造创建的对象。

  • 无参构造

    OrderDao OrderDao2 = new OrderDaoImpl();

    对应Spring中的配置

    <!-- 如下配置的效果: 通过class的值获取全限定类名,然后通过反射调用无参构造方法, 创建对象并装配进Spring容器,起名为id的值。 --> <bean id="bookDao" class="com.cy.dao.impl.OrderDaoImpl"/>

  • 如果未提供给无参构造方法,会因为找不到该方法而报错。NoSuchMethodException *** init()

4.3 Spring中静态工厂实例化
  • 静态工厂

    // 方式3:静态工厂方式 OrderDao OrderDao2 = OrderDaoFactory.getOrderDao();

    对应Spring中配置

    <!-- 通过OrderDaoFactory的静态方法,获取OrderDao对象 Spring容器中会产生一个orderDao对象 该对象的名字是id的值 --> <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>

    Spring容器中,获取方式和之前一样,通过id获取对象并使用。

  • 应用场景

    1. 兼容老的项目
    2. 创建过程比较复杂的对象,一般都是使用工厂模式
4.4 Spring中实例工厂实例化
  • 实例工厂

    // 方式3:实例工厂方式 // 创建工厂对象 UserDaoFactory factory = new UserDaoFactory(); // 通过工厂对象,得到目标对象 UserDao userDao = factory.getUserDao();

    对应Spring中配置

    <!-- 通过UserDaoFactory的成员方法,获取UserDao对象 Spring容器中会产生一个UserDaoFacotry对象、UserDao对象 UserDaoFacotry对象的名字是其id的值 UserDao=对象的名字是其id的值 --> <!--方式三:使用实例工厂实例化bean--> <!-- 装配工厂Bean,得到一个工厂的Bean对象 --> <bean id="userFactory" class="com.cy.factory.UserDaoFactory"/> <!-- 通过工厂Bean对象获取目标Bean对象 --> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

    Spring容器中,获取方式和之前一样,通过id获取对象并使用。

4.5 SpringFactoryBean实例化
  • 该方式是在第三种方法的简化改良。编码基本雷同,配置相对简单。

  • 实现步骤

    1. 编写工厂类实现FactoryBean。类名一般为xxxFactoryBean,泛型为目标对象类型xxx
    2. 实现getObject()方法、getObjectType()方法。
    3. Spring配置文件中简单配置。
  • xxxFactoryBean

    package com.cy.factory; import com.cy.dao.UserDao; import com.cy.dao.impl.UserDaoImpl; import org.springframework.beans.factory.FactoryBean; //FactoryBean创建对象 public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始实例工厂中创建对象的方法 public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } /** * 该方法一般不用重写 * 决定获取的Bean是否为单例。默认返回true。 * true 单例 singleton * false 多例(非单例) prototype * @return */ public boolean isSingleton() { return true; } }

  • XML配置

    <!-- 方式四:使用FactoryBean实例化bean 配置方式和第一种使用构造方法实例化凡是类似,但是class属性值是一个FactoryBean的实现类 Spring容器中会产生一个UserDaoFactoryBean对象、UserDao对象 UserDao对象的名字是改标签的id值 --> <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

  • 应用场景

    Spring在整合其他框架时,多用该方式。

5 生命周期

生命周期:对象从出生到死亡的整个过程。

5.1 配置实现
  1. 提前准备好两个方法,方法名任意 xxx yyy

    package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } //表示bean初始化对应的操作 public void xxx(){ System.out.println("init..."); } //表示bean销毁前对应的操作 public void yyy(){ System.out.println("destory..."); } }

  2. Spring配置文件对应bean标签上添加两个属性,属性值不用带小括号

    <!--init-method:设置bean初始化生命周期回调函数--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象--> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl" init-method="xxx" destroy-method="yyy"/>

5.2 实现接口

package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao, InitializingBean, DisposableBean { public void save() { System.out.println("book dao save ..."); } // 实现InitializingBean中抽象方法,该方法会在init-method指定的方法执行后执行 public void afterPropertiesSet() throws Exception { System.out.println("service init"); } // 实现DisposableBean充抽象方法 public void destroy() throws Exception { System.out.println("service destroy"); } } 5.3 注意

需要手动关闭容器才能看到销毁代码的执行。

  • Spring容器关闭的功能,在Config***的子接口中规定的,需要向下转型到其子类才能调用,一般直接使用ClasspathXMLApplicationContext
  • 也可以注册关闭的钩子ctx.registerShutdownHook(),会在执行完代码后自动关闭。
5.4 声明周期(11步)
  • 初始化容器
    • 创建Bean对象(内存分配)
    • 执行构造方法
    • 执行属性注入(set操作)
    • 执行bean初始化方法
  • 使用bean
    • 执行业务操作
  • 关闭/销毁容器
    • 执行bean销毁方法
6. 依赖注入 6.1 概念

Dependency Injection,DI

依赖:在A类中用到了B类,就说A依赖B,需要在A类中添加一个B类型的成员变量;

依赖注入:把B类对象设置进A中B类型的成员变量的过程,称为依赖注入。

Spring会把B类对象注入到A类中B类型的属性上。自动完成注入。

// 伪代码演示 class A{ // 为B类型的b变量初始化的过程,称为依赖注入 B b; }

依赖注入可以理解成IoC的一种应用场景,反转的是对象间依赖关系维护注入权

6.2 IoCDI的关系(面试题)

IoC是一种思想(规范),可以把对象的创建权、对象间依赖关系的维护注入权等从程序员手中,反转到了Spring容器中;

DI依赖注入,只是IoC在某个方面的一个具体实现,在 依赖关系维护注入 方面的一个实现。

6.3 注入方式

本质上就是为某个类的成员变量赋值的方式:setter/有参构造

/* 1. 提供有参构造方法,通过构造方法在创建对象的同时为成员变量赋值 2. 提供setter,通过setter为成员变量赋值 */ 6.4 Setter方式注入

注入引用类型(容器中已经存在的其他Bean对象)

  1. 保证被注入的Bean和目标Bean都已经装配到Spring容器

    <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"></bean> <bean id="userDao" class="com.cy.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"></bean>

  2. BookServiceImpl类中添加UserDao/BookDao的属性并提供setter

    package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.dao.UserDao; import com.cy.service.BookService; public class BookServiceImpl implements BookService{ private BookDao bookDao; private UserDao userDao; //setter注入需要提供要注入对象的set方法 public void setUserDao(UserDao userDao) { this.userDao = userDao; } //setter注入需要提供要注入对象的set方法 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); userDao.save(); } }

  3. 通过<property>子标签完成注入

    <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"></bean> <bean id="userDao" class="com.cy.dao.impl.UserDaoImpl"/> <!--注入引用类型--> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <!--property标签:设置注入属性--> <!--name属性:设置注入的属性名,实际是set方法对应的名称--> <!--ref属性:Spring容器中已经存在的符合要求的Bean--> <property name="bookDao" ref="bookDao"/> <property name="userDao" ref="userDao"/> </bean>

注入简单数据类型数据

String + 基本数据类型

只需要把生面的配置文件中ref属性换成value属性即可。

<!--注入简单类型--> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <!--property标签:设置注入属性--> <!--name属性:设置注入的属性名,实际是set方法对应的名称--> <!--value属性:设置注入简单类型数据值--> <property name="connectionNum" value="100"/> <property name="databaseName" value="mysql"/> </bean>

package com.cy.dao.impl; import com.cy.dao.BookDao; public class BookDaoImpl implements BookDao { private String databaseName; private int connectionNum; //setter注入需要提供要注入对象的set方法 public void setConnectionNum(int connectionNum) { this.connectionNum = connectionNum; } //setter注入需要提供要注入对象的set方法 public void setDatabaseName(String databaseName) { this.databaseName = databaseName; } public void save() { System.out.println("book dao save ..."+databaseName+","+connectionNum); } } 6.5 构造器注入

不常用

  • 被装配的类中提供有参构造,而不需要提供setter

    package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.dao.UserDao; import com.cy.service.BookService; public class BookServiceImpl implements BookService{ private BookDao bookDao; private UserDao userDao; // 有参构造,不需要提供setter 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(); } }

  • XML中通过子标签配置constructor-arg

    <!-- 标准书写 --> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"></bean> <bean id="userDao" class="com.cy.dao.impl.UserDaoImpl"/> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl"> <!-- 根据构造方法参数名称注入 name值只为有参构造中形参的名称 ref值为Spring容器中已近存在的其他Bean的id value:简单类型使用value注入 --> <constructor-arg name="userDao" ref="userDao"/> <constructor-arg name="bookDao" ref="bookDao"/> </bean>

  • value属性注入简单类型

    <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <!-- 根据构造方法参数类型注入 --> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean>

6.6 自动装配

自动为当前Bean完成依赖注入,简称自动装配,可取值byName | byType | constructor,分别代表按照

  1. byType:按照属性类型Spring容器中bean进行匹配,完成自动装配注入
  2. byName:按照属性名Spring容器中bean的id进行匹配,完成自动装配注入
  3. constructor:按照构造方法的形参类型Spring容器中bean进行匹配,完成自动装配注入

注意:上述中属性值的是setter或者是构造形参,而非成员变量本身。

xml中配置:把所有的Bean都配置进Spring容器。

<bean id = "bookDao" class="com.cy.dao.impl.BookDaoImpl"/> <!-- <bean class="com.cy.dao.impl.BookDaoImpl"/> --> <!-- autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.cy.service.impl.BookServiceImpl" autowire="byType"/>

java代码

package com.cy.service.impl; import com.cy.dao.BookDao; import com.cy.service.BookService; public class BookServiceImpl implements BookService{ private BookDao bookDao; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } } 6.7 注意事项

  1. 优选自动装配
  2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
  3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
  4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
6.8 集合注入

了解即可。

<bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <!-- 单例集合 list set array 配置通用 ,建议使用list 双列集合 map properties 配置通用 ,建议使用Map --> <!--set集合注入--> <property name="set"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property> <!--map集合注入--> <property name="map"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property> <!--Properties注入--> <property name="properties"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property> </bean>

package com.cy.dao.impl; import com.cy.dao.BookDao; import java.util.*; public class BookDaoImpl implements BookDao { private String[] array; private List<String> list; private Set<String> set; private Map<String,String> map; private Properties properties; public void setArray(String[] 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; } 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); } } 7. 案例练习

无论是自己写的类要装配进Spring容器,还是第三方的类要装配进Spring容器,只需要遵循Spring的配置规则即可。

后者与前者的不同,仅仅是把自己编写代码变成了导入依赖坐标,配置方式一致。

7.1 DruidDataSource 7.1.1 导入依赖坐标

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="maven.apache.org/POM/4.0.0" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="maven.apache.org/POM/4.0.0 maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cy</groupId> <artifactId>ssm01_spring01_11_datasource</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> </dependencies> </project> 7.1.2 Spring装配配置

<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> 7.1.3 测试

package com.itheima; import com.itheima.dao.BookDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; 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); } } 7.2 C3P0数据源

老牌数据源管理工具,曾经久不衰。

7.2.1 导入依赖坐标

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="maven.apache.org/POM/4.0.0" xmlns:xsi="www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="maven.apache.org/POM/4.0.0 maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>ssm01_spring01_11_datasource</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies> </project> 7.2.2 Spring装配配置

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="user" value="root"/> <property name="password" value="root"/> <property name="maxPoolSize" value="1000"/> </bean> 7.2.3 测试

package com.cy; import com.cy.dao.BookDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; 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); } } 8 引入properties文件 8.1 创建properties文件

  • jdbc.properties

    # 不要使用username,否则会错误的获取到当前系统的用户名。建议使用jdbc.username jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db jdbc.username=root jdbc.password=root

8.2 beans.xml文件引入 jdbc.properties文件

<!-- 在类路径下加载指定名称的properties配置文件,classpath:可以省略不写。下同 --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 在类路径下加载多个指定名称的properties配置文件 --> <context:property-placeholder location="classpath:jdbc.properties,jdbc2.properties"/> <!-- 在类路径下加载所有的properties配置文件 --> <context:property-placeholder location="classpath:*.properties"/> <!-- 在类路径+jar包中(整个项目下)加载所有的properties配置文件 统配会造成效率降低,速度变慢 --> <context:property-placeholder location="classpath*:*.properties"/> <!-- 使用属性占位符${},可以通过properties文件中的key读取到对应的值 OGNL ${} 所有的框架都支持这个种写法,从当前容器对象中根据key获取值 Spring容器会把当前系统的内置变量整合进自己的容器 username=当前系统的用户名 且优先级高于我们自己配置的。 ${username} 会获取当前系统的用户名 解决方案: 1. 不要使用username,使用诸如jdbc.username。推荐写法。 2. 通过其属性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> <bean id="bookDao" class="com.cy.dao.impl.BookDaoImpl"> <property name="name" value="${username}"/> </bean> 8.3 代码测试

package com.cy; import com.cy.dao.BookDao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import javax.sql.DataSource; public class App { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); } }