SSM之Spring(一)

时间:2022-10-16 00:52:14

简介

    Spring:春天->给款件行业带来了春天!

    2002,首次推出了Spring框架的谁形:nterface21推架!

    Spring框架即以interface.21架为其础经过年新设计并不断丰富其内涵,于2004年3月24日发布了1.0正式版。

    Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼达学的博士,然而他的专业不是计算机,而是音乐学。

Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!

为什么要学

  • Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%
  • 专业角度
  • 简化开发,降低企业级开发的复杂性
  • 框架整合,高效整合其他技术,提高企业级应用开发与运行效率

优点

  • spring是一个开源的免费软件(容量)!
  • spring是一个轻量级的,非入侵式的框架!
  • 控制反转(IOC),面向切面编程(AOP)!
  • 支持事物的处理,对框架整合的支持!

总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!

初识Spring

了解Spring家族

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

Spring发展史

SSM之Spring(一)

Spring Framework系统架构

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

SSM之Spring(一)

SSM之Spring(一)

核心概念

目前我们代码存在的问题

  • 代码书写现状
  • 耦合度偏高
  • 解决方案
  • 使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象

IoC(Inversion of Control)控制反转

  • 对象的创建控制权由程序转移到外部,这种思想称为控制反转

IoC/DI

IoC(Inversion of Control)控制反转

  • 使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转

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

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

DI(Dependency Injection)依赖注入

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

目的:充分解耦

  • 使用IoC容器管理bean(IoC)
  • 在IoC容器内将有依赖关系的bean进行关系绑定(DI)

SSM之Spring(一)

最终效果

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

IoC入门案例

①:导入Spring坐标

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>

②:定义Spring管理的类(接口)

BookDao接口和BookDaoImpl实现类

public interface BookDao {
public void save();
}

public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}

BookService接口和BookServiceImpl实现类

public interface BookService{
public void save();
}
public class BookServiceImpl implements BookService {

private BookDao bookDao = new BookDaoImpl();

public void save() {
System.out.println("book dao save...");
bookDao.save();
}
}

③:创建Spring配置文件,配置对应类作为Spring管理的bean

Bean标签中的属性:

  •  bean标签:表示配置bean
  •  id属性:表示给bean起名字
  •  class属性:表示给bean定义类型

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"></bean>

</beans>

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

④:初始化IoC容器(Spring核心容器/Spring容器),通过容器获取bean

public class App {
public static void main(String[] args) {
//1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2 获取资源,从IOC容器中获取Bean对象(BookService对象)
BookService bookService= (BookService)ctx.getBean("bookService");
//3 调用Bean对象(BookService对象)的方法
bookService.save();
}
}

DI入门案例

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

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

②:提供依赖对象对应的setter方法

public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
//提供依赖对象对应的setter方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}v

③:配置service与dao之间的关系

property标签中的属性:

  • property标签:表示配置当前bean的属性
  • name属性:表示配置哪一个具体的属性
  • ref属性:表示参照哪一个bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

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

图解演示:

SSM之Spring(一)

Bean

Bean基础配置

SSM之Spring(一)

Bean别名配置

SSM之Spring(一)

注意事项

获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException:No bean named 'bookServiceImpl' available

代码展示:

SSM之Spring(一)

输出结果:

SSM之Spring(一)

Bean作用范围配置

配置说明:

SSM之Spring(一)

注意:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。

代码演示

SSM之Spring(一)

打印结果:

SSM之Spring(一)

注意:在我们的实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。


为什么默认bean为单例?
  • 减少了新生成实例的消耗
  • 减少jvm垃圾回收
  • ​可以快速获取到bean

以上问题答案出处:(​面试题:Spring为什么默认bean为单例? - 简书 (jianshu.com)​

Bean实例化

bean本质上就是对象,创建bean使用构造方法完成

实例化Bean的三种方式

提供可访问的构造方法

BookDaoImpl实现类

public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}

applicationContext.xml配置

<!--方式一:构造方法实例化bean-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

AppForInstanceBook测试类

public class AppForInstanceBook {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

BookDao bookDao = (BookDao) ctx.getBean("bookDao");

bookDao.save();
}
}

运行结果

SSM之Spring(一)

注意:无参构造方法如果不存在,将抛出异常BeanCreationException

静态工厂(了解)

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

applicationContext.xml配置

<bean id="orderDao" 
class="com.itheima.factory.OrderDaoFactory"
factory-method="getOrderDao"
/>

图片演示:

SSM之Spring(一)

运行结果:

SSM之Spring(一)

实例工厂(了解)

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

applicationContext.xml配置

<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>

<bean id="userDao"
factory-method="getUserDao"
factory-bean="userFactory"
/>

图片演示:

SSM之Spring(一)

运行结果:

SSM之Spring(一)

FactoryBean

//FactoryBean创建对象
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//代替原始实例工厂中创建对象的方法
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}

public Class<?> getObjectType() {
return UserDao.class;
}
}

applicationContext.xml

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

Bean生命周期

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

Bean生命周期控制

提供生命周期控制方法

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...");
}
}

applicationContext.xml

<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名-->
<bean id="bookDao"
class="com.itheima.dao.impl.BookDaoImpl"
init-method="init"
destroy-method="destory"
/>

Bean生命周期控制--接口控制(了解)

实现InitializingBean, DisposableBean接口

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
System.out.println("set .....");
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}

Bean生命周期

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

Bean销毁时机

  • 容器关闭前触发Bean的销毁
  • 关闭容器方式:
  • 手工关闭容器 ConfigurableApplicationContext接口close()操作
  • 注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机 ConfigurableApplicationContext接口registerShutdownHook()操作

public class AppForLifeCycle {
public static void main( String[] args ) {
//此处需要使用实现类类型,接口类型没有close方法
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
ctx.registerShutdownHook();
//关闭容器
//ctx.close();
}
}

依赖注入方式

  • 思考:向一个类中传递数据的方式有几种?
  • 普通方法(set方法)
  • 构造方法
  • 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?
  • 引用类型
  • 简单类型(基本数据类型与String)
  • 依赖注入方式
  • setter注入
  • 简单类型
  • 引用类型
  • 构造器注入
  • 简单类型
  • 引用类型

setter注入

引用类型

SSM之Spring(一)

简单类型

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

SSM之Spring(一)

构造器注入

引用类型(了解)

SSM之Spring(一)

简单类型(了解)

SSM之Spring(一)

参数适配(了解)

配置中使用constructor-arg标签type属性设置按形参类型注入

SSM之Spring(一)

配置中使用constructor-arg标签index属性设置按形参位置注入

SSM之Spring(一)

总结:

依赖注入方式选择

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

依赖自动装配

  • IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
  • 自动装配方式
  • 按类型(常用)
  • 按名称
  • 按构造方法
  • 不启用自动装配
  • 配置中使用bean标签autowire属性设置自动装配的类型

依赖自动装配特征

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

集合注入

数组

注入数组对象

<property name="array">
<array>
<value>1</value>
<value>2</value>
</array>
</property>

List

注入List对象(重点)

<property name="list">
<list>
<value>hello</value>
<value>world</value>
</list>
</property>

Set

注入Set对象

<property name="set">
<set>
<value>hello</value>
<value>world</value>
</set>
</property>

Map

注入Map对象(重点)

<property name="set">
<map>
<entry key="country" value="china"/>
<entry key="name" value="XiaoXiao"/>
<entry key="city" value="Guangzhou"/>
</map>
</property>

Properties

  • 注入Properties对象
<property name="set">
<props>
<prop key="country">china</prop>
<prop key="name">XiaoXiao</prop>
<prop key="city">Guangzhou</prop>
</props>
</property>

案例:数据源对象管理

说明:以管理DataSource连接池对象为例讲解第三方资源配置管理

管理DataSource连接池对象

数据库准备

create database if not exists spring_db character set utf8;
use spring_db;
create table if not exists tbl_account(
id int primary key auto_increment,
name varchar(20),
money double
);
insert into tbl_account values(null,'Tom',1000);
insert into tbl_account values(null,'Jerry',1000);

添加Druid连接池依赖

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>

注意:除了添加以上两个依赖之外,别忘了添加spring-context依赖。

配置DruidDataSource连接池Bean对象

<bean id="dataSource" 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>

在测试类中从IOC容器中获取连接池对象并打印

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

管理c3p0连接池

添加c3p0连接池依赖

<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>

配置c3p0连接池Bean对象

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

注意:同一个Spring容器中不能有两个的连接池。 在测试类中从IOC容器中获取连接池对象并打印

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

加载properties配置信息

开启context命名空间

SSM之Spring(一)

使用context命名空间,加载指定properties文件

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

使用${}读取加载的属性值

<property name="username" value"${jdbc.username}"/>

加载properties文件

不加系统属性载

加载多个properties文件

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

加载所有properties文件

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

加性properties文件标准格式

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

从类路径或jar包中搜索并加载properties文件

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