文章目录
- 前言
- 一、Spring是什么?
- 1.概述
- 2.了解spring家族
- 3.spring系统概述
- 4.spring优点
- 5.spring学习路线
- 二、入门spring
- 1.核心概念
- 2.IOC入门案例
- 3.DI入门案例
- 4.bean的配置
- 5.spring 中 bean的实例化--构造方法
- 6.bean的实例化 -- 静态工厂实例化
- 7.bean实例化--实例工厂和FactoryBean
- 8.bean的生命周期
- 9.依赖注入 -- setter注入
- 10.依赖注入 -- 构造器注入
- 11.自动装配
- 12.数据源对象管理
- 13.加载properties配置文件
- 14.IOC容器相关
- 15.spring入门总结
- 引用网站及博客
- 总结
前言
为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。
(博客的参考源码以及可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)
一、Spring是什么?
1.概述
- Spring Framework 是一个功能强大的 Java 应用程序框架,旨在提供高效且可扩展的开发环境。
- 它结合了轻量级的容器(IOC)和 依赖注入(DI) 功能,提供了一种使用 POJO 进行容器配置和面向切面的编程的简单方法,以及一组用于 AOP(切面编程) 的模块。
- Spring 框架还支持各种移动应用开发技术,如 Android 和 iOS。此外,它还提供了对事务管理、对象/关系映射、JavaBeans、JDBC、JMS 和其他技术的支持,从而确保高效开发。
2.了解spring家族
3.spring系统概述
Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。下面的部分对在 Spring 框架中所有可用的模块给出了详细的介绍。
Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用。
- 核心容器(Core Container)
核心容器由 spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成,它们的细节如下:
spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 Java EE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。spring-context-support 提供了对第三方集成到 Spring 上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。
spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。
- 数据访问/集成(Data Access/Integration)
数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:
(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)
JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。
OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。
事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)
- Web
Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:
Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。
- Test模块
Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。
- 其他
还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:
AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试
4.spring优点
- 方便解耦,简化开发
Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理
- 方便集成各种优秀框架
Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持
- 降低 Java EE API 的使用难度
Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低
- 方便程序的测试
Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序
- AOP 编程的支持
Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能
- 声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无须手动编程。
5.spring学习路线
二、入门spring
1.核心概念
- 依赖注入(DI)
-
Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。
-
当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。
-
到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。
-
依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。
2.面向切面的程序设计(AOP):
-
Spring 框架的一个关键组件是面向切面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。
-
在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。
-
Spring 框架的 AOP 模块提供了面向方面的程序设计实现,可以定义诸如方法拦截器和切入点等,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于 .Net 属性的方式合并行为信息到代码中。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。
- Spring IoC 容器
-
Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans
-
通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。下图是 Spring 如何工作的高级视图。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序
-
IOC 容器具有依赖注入功能的容器,它可以创建对象,IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。在Spring中BeanFactory是IOC容器的实际代表者。
-
Spring 提供了以下两种不同类型的容器。
序号 | 容器 & 描述 |
---|---|
1 | Spring BeanFactory 容器 :它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。 |
2 | Spring ApplicationContext 容器 :该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。 |
ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常不建议使用BeanFactory。BeanFactory 仍然可以用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。
- Spring Bean 定义
-
被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的。bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建的,例如,已经在先前章节看到的,在 XML 的表单中的 定义。
-
bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据:
-
如何创建一个 bean
-
bean 的生命周期的详细信息
-
bean 的依赖关系
-
上述所有的配置元数据转换成一组构成每个 bean 定义的下列属性。
属性 | 描述 |
---|---|
class | 这个属性是强制性的,并且指定用来创建 bean 的 bean 类。 |
name | 这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。 |
scope | 这个属性指定由特定的 bean 定义创建的对象的作用域,它将会在 bean 作用域的章节中进行讨论。 |
constructor-arg | 它是用来注入依赖关系的,并会在接下来的章节中进行讨论。 |
properties | 它是用来注入依赖关系的,并会在接下来的章节中进行讨论。 |
autowiring mode | 它是用来注入依赖关系的,并会在接下来的章节中进行讨论。 |
lazy-initialization mode | 延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。 |
initialization 方法 | 在 bean 的所有必需的属性被容器设置之后,调用回调方法。它将会在 bean 的生命周期章节中进行讨论。 |
destruction 方法 | 当包含该 bean 的容器被销毁时,使用回调方法。它将会在 bean 的生命周期章节中进行讨论。 |
- Bean 与 Spring 容器的关系
## 5.spring三层架构
A 表现层 web层 MVC是表现层的一个设计模型
B 业务层 service层
C 持久层 dao层
2.IOC入门案例
- 入门案例思路分析
- 创建maven模块
- 编写接口和Dao实现类(此时无spring环境,纯JAVA开发)
-
模块代码结构
-
BookDao
public interface BookDao {
public void save();
}
- BookDaoImpl
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
- BookService
public interface BookService {
public void save();
}
- BookServiceImpl
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
- Main
public class Main {
public static void main(String[] args) {
BookService bookService = new BookServiceImpl();
bookService.save();
}
}
- Main类运行结果
- 示例代码解析
- 首先写了两个数据层接口 BookDao 和 BookService,两个接口中都定义了save()方法
- 然后写了两个数据层接口的实现类 BookDaoImpl 和 BookServiceImpl,分别实现了save() 方法,方法里都要一条输出语句,但是两个实现类save方法打印的内容不同
- 其中 BookServiceImpl 类中还通过new创建对象的方式调用了 BookDaoImpl的save方法
- 最后在Main类中通过new创建对象的方式调用了BookServiceImpl的save方法将两个save()方法中的语句打印了出来
- 在pom.xml中导入spring坐标spring-context
<dependencies>
<!--spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.21.RELEASE</version>
</dependency>
</dependencies>
- 创建spring核心配置文件applicationContext.xml
resources 目录右键 --> new --> XML Configuration File --> Spring Config(导入spring坐标后才有对应选项)
- 配置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">
<!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->
<!--2.配置bean-->
<!--bean标签标示配置bean
id属性标示给bean起名字
class属性表示给bean定义类型-->
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="org.example.service.impl.BookServiceImpl"/>
</beans>
- 在org.example下新建一个类Main2
public class Main2 {
public static void main(String[] args) {
//3.获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//4.获取bean(根据bean配置id获取)
//左边是对象,右边是接口,所以要强转类型
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}
- 程序运行结果(通过spring创建对象而不是通过new创建对象)
- 总结 :spring程序的开发步骤
3.DI入门案例
- 删除BookServiceImpl类中通过new方式创建对象的代码,并提供对应的setter方法
package org.example.service.impl;
import org.example.dao.BookDao;
import org.example.service.BookService;
public class BookServiceImpl implements BookService {
//5.删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
// private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
// 6.提供对应的set方法
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
- 在全局配置文件applicationContext.xml文件中将BookDao注入到BookService中
<?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">
<!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->
<!--2.配置bean-->
<!--bean标签标示配置bean
id属性标示给bean起名字
class属性表示给bean定义类型-->
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
<!--7.配置server与dao的关系-->
<!--property标签表示配置当前bean的属性
name属性表示配置哪一个具体的属性
ref属性表示参照哪一个bean-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
- 运行结果
- 注意事项
name 的值是类的属性值,ref的值是id值
4.bean的配置
- bean的基础配置
- bean的别名设置
- 控制bean的作用范围
5.spring 中 bean的实例化–构造方法
- 创建新的maven模块respr_newbean,并在pom.xml添加spring的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.22</version>
<scope>compile</scope>
</dependency>
- 创建核心配置文件applicationContext.xml文件、dao接口及其实现类以及相关的类(先写标记部分)
- 编写dao接口及其实现类
- BookDao接口
public interface BookDao {
public void save();
}
- 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 ...");
}
}
- 进行测试的类 AppForInstanceBook
public class AppForInstanceBook {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
- 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--方式一:构造方法实例化bean-->
<bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>
</beans>
- AppForInstanceBook运行结果
- 结论
spring构造方法实例化bean使用了无参构造器,可以省略无参构造器的书写。实例化bean就是用构造方法来实例化对象。
6.bean的实例化 – 静态工厂实例化
- 创建dao接口及其实现类以及相关的类(先写标记部分)
- 编写dao接口及其实现类以及相关的类
- OrderDao接口
package org.example.dao;
public interface OrderDao {
public void save();
}
- OrderDaoImpl实现类
在这里插入代码片package org.example.dao.impl;
import org.example.dao.OrderDao;
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
- 工厂类OrderDaoFactory(静态工厂类代理生成对象)
package org.example.factory;
import org.example.dao.OrderDao;
import org.example.dao.impl.OrderDaoImpl;
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");
return new OrderDaoImpl();
}
}
- AppForInstanceOrder模拟测试类编写(纯JAVA开发,此处还没有Spring)
public class AppForInstanceOrder {
public static void main(String[] args) {
//通过静态工厂创建对象
OrderDao orderDao = OrderDaoFactory.getOrderDao();
orderDao.save();
}
}
- 模拟测试类的运行结果
- 简要分析
将 OrderDaoImpl 创建对象的 工作交给 静态工厂 OrderDaoFactory 类来完成,如果用spring代理这种工厂模式的开发,写法如下
- spring 代理静态工厂实例化对象
public class AppForInstanceOrder {
public static void main(String[] args) {
//通过静态工厂创建对象
// OrderDao orderDao = OrderDaoFactory.getOrderDao();
// orderDao.save();
// spring代理静态工厂实例化对象
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
}
}
- applicationContext.xml文件配置静态工厂 OrderDaoFactory bean (注意factory-method属性)
<?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-->
<!-- <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>-->
<!-- 方式二:使用静态工厂实例化bean-->
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
</beans>
- 运行结果
7.bean实例化–实例工厂和FactoryBean
- 创建dao接口及其实现类以及相关的类(标记部分)
- 编写dao接口及其实现类以及相关的类
- UserDao接口
public interface UserDao {
public void save();
}
- UserDaoImpl实现类
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
- UserDaoFactoryBean实例工厂类
//实例工厂创建对象
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
- AppForInstanceUser模拟测试类(纯JAVA开发)
public class AppForInstanceUser {
public static void main(String[] args) {
// //创建实例工厂对象
UserDaoFactory userDaoFactory = new UserDaoFactory();
// //通过实例工厂对象创建对象
UserDao userDao = userDaoFactory.getUserDao();
userDao.save();
}
}
- 运行结果
- 简要分析
此时与静态工厂的区别是模拟测试类中多了创建工厂对象的步骤
- spring代理下的实例工厂bean实例化模拟测试类
public class AppForInstanceUser {
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();
}
}
- 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--方式一:构造方法实例化bean-->
<!-- <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>-->
<!-- 方式二:使用静态工厂实例化bean-->
<!-- <bean id="orderDao" class="org.example.factory.OrderDaoFactory" factory-method="getOrderDao"/>-->
<!--方式三:使用实例工厂实例化bean-->
<bean id="userFactory" class="org.example.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
</beans>
- 模拟测试类运行结果
- spring代理实例工厂bean实例化简要分析 --> 改进为BeanFactory bean实例化
- 创建并编写BeanFactory工厂类UserDaoFactoryBean
//FactoryBean创建对象
//实现接口,创建什么对象写什么泛型
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
//实现抽象方法
//代替原始实例工厂中创建对象的方法,以后方法名不用指定,就用getObject
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
//配置的类是什么类型
public Class<?> getObjectType() {
return UserDao.class;
}
}
- 配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--方式一:构造方法实例化bean-->
<!-- <bean id="bookDao" class="org.example.dao.impl.BookDaoImpl"/>-->
<!-- 方式二:使用静态工厂实例化bean-->
<!-- <bean id="orderDao" class="org.example.factory.OrderDaoFactory" factory-method="getOrderDao"/>-->
<!--方式三:使用实例工厂实例化bean-->
<!-- <bean id="userFactory" class="org.example.factory.UserDaoFactory"/>-->
<!-- <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>-->
<!--方式四:使用FactoryBean实例化bean-->
<bean id="userDao" class="org.example.factory.UserDaoFactoryBean"/>
</beans>
- 模拟测试类运行结果
8.bean的生命周期
- 概念
-
理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作
-
尽管还有一些在 Bean 实例化和销毁之间发生的活动,有两个重要的生命周期回调方法,它们在 bean 的初始化和销毁的时候是必需的
-
为了定义安装和拆卸一个 bean,我们只要声明带有 init-method 和/或 destroy-method 参数的 。init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。同样,destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法
-
Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
- 编写代码(IOC 和 DI入门案例的代码,模块名为respr_ioc)
- 在BookDaoImpl实现类中定义代表创建bena初始化和销毁的方法
package org.example.dao.impl;
import org.example.dao.BookDao;
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文件中配置BookDao bean 的 初始化方法 int-method 和销毁方法 destory-method
- 将BookService的代码注释掉,运行模拟测试类,观察BookDao bean的创建和销毁过程
- 运行结果
-
简要分析
我们从运行结果可以看到bean初始化成功了,但是并没有进行销毁工作,原因是java虚拟机(java在虚拟机运行)在执行玩程序退出时并没有做销毁操作,我们需要自己添加关闭语句,ctx.close()。但是ApplicationContext接口中并没有这个方法,而它的实现类中有,所以我们要用它的实现类ClassPathXmlApplicationContext来调用这个方法 -
关闭ioc容器的代码及运行结果如下
- 关闭ioc容器的第二种方式:关闭钩子(概念、代码及运行结果如下)
在Java程序退出时——尤其是非正常退出时,我们可能需要先执行一些善后工作,如关闭线程池、连接池、文件句柄等。如何保证善后工作的代码能够被执行到呢?Java为用户提供了关闭钩子(shutdown hook)registerShutdownHook()方法来注册关闭钩子
-
两种关闭ioc容器的简要分析
关闭钩子函数代码在程序中的位置要求没有close()方法那么苛刻,如果将其挪到bookDao.save()方法的下面也能用,close()方法比较暴力 -
绑定销毁方法和初始化方法的改进–继承接口(以BookServiceImpl为例)
- 实现InitializingBean, DisposableBean接口
- 重写 destroy(销毁) 和 afterPropertiesSet(初始化) 方法
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
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");
}
}
- 模拟测试类Main2运行结果
(尽管在模拟测试类Main2并没有调用BookService 的bean,但是在核心配置文件中定义了BookService 的 bean,该创建bean的时候就创建,该初始化就初始化,该销毁就销毁)
9.依赖注入 – setter注入
- 思考
- 依赖注入 – setter注入引用类型的步骤方法(DI入门案例所用的就是setter注入引用类型)
(代码见DI入门案例)
- 探讨引用多个引用对象(在DI入门的代码基础上编码)
- 在dao包下创建并编写UserDao接口
package org.example.dao;
public interface UserDao {
public void save();
}
- 在impl包下创建并编写UserDaoImpl实现类
package org.example.dao.impl;
import org.example.dao.UserDao;
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
- 在BookServiceImpl实现类中setter注入UserDao
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();
}
}
- 在核心配置类applicationContext中配置userDAO的bean,并将其注入到BookService中
- 执行模拟测试类App2
(从运行结果中可以看到多个引用类型是可以用setter注入的)
- 依赖注入 – setter注入普通类型的步骤方法
- 在BookDaoImpl中提供两个变量,并提供对应的setter方法(以BookDaoImpl为例)
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);
}
}
- 在核心配置类applicationContext.xml文件中配置中注入普通变量
- 模拟测试类App2类的运行结果
10.依赖注入 – 构造器注入
(在依赖注入–setter注入的基础上编码,将依赖注入相关的代码删掉,具体见个人主页上传的代码respr_diconstouctor)
1 . 依赖注入 – 构造器注入引用类型的步骤方法
- 在BookService类中提供构造方法
public class BookServiceImpl implements BookService {
//5.删除业务层中使用new的方式创建的dao对象
private BookDao bookDao;
//提供构造方法
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
- 在核心配置类中注入BookDao相关的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="org.example.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="org.example.service.impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
- 模拟测试类App2运行结果(同理,构造器注入可以注入多个引用类型,此处省略相关代码)
- 依赖注入 – 构造器注入普通类型的步骤和方法
- 在BookDao中定义两个变量,并编写对应的构造器方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public BookDaoImpl(String databaseName, int connectionNum) {
this.databaseName = databaseName;
this.connectionNum = connectionNum;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
- 在核心配置文件配置相关属性
- 方式一:根据构造方法参数名称注入
- 方式二:根据构造方法参数类型注入
- 方式三:根据构造方法参数位置注入
- 模拟测试类App2运行结果
- 依赖注入的选择
11.自动装配
- 自动装配基础知识
-
我们已经学会如何使用元素来声明 bean 和通过使用 XML 配置文件中的和元素来注入 。
-
Spring 容器可以在不使用和 元素的情况下自动装配相互协作的 bean 之间的关系,这有助于减少编写一个大的基于 Spring 的应用程序的 XML 配置的数量。
-
下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可以使用元素的 autowire 属性为一个 bean 定义指定自动装配模式。
模式 | 描述 |
no | 这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线做特殊的事。在依赖注入章节你已经看到这个了。 |
byName(按名称) | 由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。然后尝试匹配,并且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行连接。 |
byType(按类型) | 由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。然后如果它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和连接属性的类型。如果存在不止一个这样的 bean,则一个致命的异常将会被抛出。 |
constructor | 类似于 byType,但该类型适用于构造函数参数类型。如果在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。 |
autodetect(3.0版本不支持) | Spring首先尝试通过 constructor 使用自动装配来连接,如果它不执行,Spring 尝试通过 byType 来自动装配。 |
可以使用 byType 或者 constructor 自动装配模式来连接数组和其他类型的集合。
- 在入门案例的基础上编码(详情见个人主页spring代码资源respr_autowire模块)
- 自动装配
- 手动配置
- 按类型自动装配(byType)
(需要提供setter方法,ioc通过setter入口给bean)
- 按名称装配
(要确保BookDao装配bean的id与BookService中的其中一个属性名对应上)
- 依赖自动装配特征
-
集合注入(比较少用)(数组,List,Set,Map,properties)
-
新建BookDao2接口及其实现类
package org.example.dao;
public interface BookDao2 {
public void save();
}
public class BookDaoImpl2 implements BookDao2 {
//数组
private int[] array;
//列表
private List<String> list;
//集合
private Set<String> set;
//图
private Map<String,String> map;
//properties
private Properties properties;
//提供对应的setter方法作为ioc提供bean的入口
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;
}
//编写测试方法
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);
}
}
- 核心配置类文件编写
<?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="org.example.dao.impl.BookDaoImpl"/>-->
<!-- <bean id="bookService" class="org.example.service.impl.BookServiceImpl" autowire="byName"/>-->
<bean id="bookDao2" class="org.example.dao.impl.BookDaoImpl2">
<!--数组注入-->
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<!--list集合注入-->
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
<!--set集合注入-->
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
<!--map集合注入-->
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
<!--Properties注入-->
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
</bean>
</beans>
- 模拟测试类编写及运行结果
12.数据源对象管理
- 导入数据源坐标(以druid数据源为例)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<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>
- 创建编写模拟配置类App及其运行结果
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);
}
}
13.加载properties配置文件
- 在resources目录下创建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
- 在核心配置类中开启context命名空间
- 使用context空间加载properties文件
<?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文件-->
<!-- 属性占位符,location:加载的文件-->
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
<!-- 3.使用属性占位符${}读取properties文件中的属性-->
<!-- 说明:idea自动识别${}加载的属性值,需要手工点击才可以查阅原始书写格式-->
<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="org.example.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
</bean>
</beans>
- 将绑定好的properties属性注入到bookdao中,通过bookdao中的save方法输出
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
public void save() {
System.out.println("book dao save ..." + name);
}
}
- 模拟测试类及输出结果
6. 小结和拓展
14.IOC容器相关
- 创建容器
- 获取bean的方式
- 容器类层次结构
(BeanFactory接口创建完毕后,所有的bean均为延迟加载)
15.spring入门总结
- IOC容器相关
- bean相关
- 依赖注入相关
16.Spring整合Junit
引用网站及博客
1.【w3cschool】
2. 【sprign教学视频】
总结
欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)