文章目录
前言
为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然,如果能帮到一些萌新进行新技术的学习那也是极好的。作者菜菜一枚,文章中如果有记录错误,欢迎读者朋友们批评指正。
(博客的参考源码以及可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)
一、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 提供了以下两种不同类型的容器。
序号容器 & 描述1Spring BeanFactory 容器 :它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。2Spring 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
publicinterfaceBookDao{publicvoidsave();}
- BookDaoImpl
publicclassBookDaoImplimplementsBookDao{publicvoidsave(){System.out.println("book dao save ...");}}
- BookService
publicinterfaceBookService{publicvoidsave();}
- BookServiceImpl
publicclassBookServiceImplimplementsBookService{privateBookDao bookDao =newBookDaoImpl();publicvoidsave(){System.out.println("book service save ...");
bookDao.save();}}
- Main
publicclassMain{publicstaticvoidmain(String[] args){BookService bookService =newBookServiceImpl();
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
publicclassMain2{publicstaticvoidmain(String[] args){//3.获取IoC容器ApplicationContext ctx =newClassPathXmlApplicationContext("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方法
packageorg.example.service.impl;importorg.example.dao.BookDao;importorg.example.service.BookService;publicclassBookServiceImplimplementsBookService{//5.删除业务层中使用new的方式创建的dao对象privateBookDao bookDao;// private BookDao bookDao = new BookDaoImpl();publicvoidsave(){System.out.println("book service save ...");
bookDao.save();}// 6.提供对应的set方法publicvoidsetBookDao(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接口
publicinterfaceBookDao{publicvoidsave();}
- BookDaoImpl实现类
publicclassBookDaoImplimplementsBookDao{//无参构造publicBookDaoImpl(){System.out.println("book dao constructor is running ....");}publicvoidsave(){System.out.println("book dao save ...");}}
- 进行测试的类 AppForInstanceBook
publicclassAppForInstanceBook{publicstaticvoidmain(String[] args){ApplicationContext ctx =newClassPathXmlApplicationContext("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接口
packageorg.example.dao;publicinterfaceOrderDao{publicvoidsave();}
- OrderDaoImpl实现类
在这里插入代码片packageorg.example.dao.impl;importorg.example.dao.OrderDao;publicclassOrderDaoImplimplementsOrderDao{publicvoidsave(){System.out.println("order dao save ...");}}
- 工厂类OrderDaoFactory(静态工厂类代理生成对象)
packageorg.example.factory;importorg.example.dao.OrderDao;importorg.example.dao.impl.OrderDaoImpl;//静态工厂创建对象publicclassOrderDaoFactory{publicstaticOrderDaogetOrderDao(){System.out.println("factory setup....");returnnewOrderDaoImpl();}}
- AppForInstanceOrder模拟测试类编写(纯JAVA开发,此处还没有Spring)
publicclassAppForInstanceOrder{publicstaticvoidmain(String[] args){//通过静态工厂创建对象OrderDao orderDao =OrderDaoFactory.getOrderDao();
orderDao.save();}}
- 模拟测试类的运行结果
- 简要分析
将 OrderDaoImpl 创建对象的 工作交给 静态工厂 OrderDaoFactory 类来完成,如果用spring代理这种工厂模式的开发,写法如下
- spring 代理静态工厂实例化对象
publicclassAppForInstanceOrder{publicstaticvoidmain(String[] args){//通过静态工厂创建对象// OrderDao orderDao = OrderDaoFactory.getOrderDao();// orderDao.save();// spring代理静态工厂实例化对象ApplicationContext ctx =newClassPathXmlApplicationContext("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接口
publicinterfaceUserDao{publicvoidsave();}
- UserDaoImpl实现类
publicclassUserDaoImplimplementsUserDao{publicvoidsave(){System.out.println("user dao save ...");}}
- UserDaoFactoryBean实例工厂类
//实例工厂创建对象publicclassUserDaoFactory{publicUserDaogetUserDao(){returnnewUserDaoImpl();}}
- AppForInstanceUser模拟测试类(纯JAVA开发)
publicclassAppForInstanceUser{publicstaticvoidmain(String[] args){// //创建实例工厂对象UserDaoFactory userDaoFactory =newUserDaoFactory();// //通过实例工厂对象创建对象UserDao userDao = userDaoFactory.getUserDao();
userDao.save();}}
- 运行结果
- 简要分析
此时与静态工厂的区别是模拟测试类中多了创建工厂对象的步骤
- spring代理下的实例工厂bean实例化模拟测试类
publicclassAppForInstanceUser{publicstaticvoidmain(String[] args){// //创建实例工厂对象// UserDaoFactory userDaoFactory = new UserDaoFactory();// //通过实例工厂对象创建对象// UserDao userDao = userDaoFactory.getUserDao();// userDao.save();ApplicationContext ctx =newClassPathXmlApplicationContext("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创建对象//实现接口,创建什么对象写什么泛型publicclassUserDaoFactoryBeanimplementsFactoryBean<UserDao>{//实现抽象方法//代替原始实例工厂中创建对象的方法,以后方法名不用指定,就用getObjectpublicUserDaogetObject()throwsException{returnnewUserDaoImpl();}//配置的类是什么类型publicClass<?>getObjectType(){returnUserDao.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初始化和销毁的方法
packageorg.example.dao.impl;importorg.example.dao.BookDao;publicclassBookDaoImplimplementsBookDao{publicvoidsave(){System.out.println("book dao save ...");}//表示bean初始化对应的操作publicvoidinit(){System.out.println("init...");}//表示bean销毁前对应的操作publicvoiddestory(){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(初始化) 方法
publicclassBookServiceImplimplementsBookService,InitializingBean,DisposableBean{privateBookDao bookDao;publicvoidsetBookDao(BookDao bookDao){this.bookDao = bookDao;}publicvoidsave(){System.out.println("book service save ...");
bookDao.save();}publicvoiddestroy()throwsException{System.out.println("service destroy");}publicvoidafterPropertiesSet()throwsException{System.out.println("service init");}}
- 模拟测试类Main2运行结果
(尽管在模拟测试类Main2并没有调用BookService 的bean,但是在核心配置文件中定义了BookService 的 bean,该创建bean的时候就创建,该初始化就初始化,该销毁就销毁)
9.依赖注入 – setter注入
- 思考
- 依赖注入 – setter注入引用类型的步骤方法(DI入门案例所用的就是setter注入引用类型)
(代码见DI入门案例)
- 探讨引用多个引用对象(在DI入门的代码基础上编码)
- 在dao包下创建并编写UserDao接口
packageorg.example.dao;publicinterfaceUserDao{publicvoidsave();}
- 在impl包下创建并编写UserDaoImpl实现类
packageorg.example.dao.impl;importorg.example.dao.UserDao;publicclassUserDaoImplimplementsUserDao{publicvoidsave(){System.out.println("user dao save ...");}}
- 在BookServiceImpl实现类中setter注入UserDao
publicclassBookServiceImplimplementsBookService{privateBookDao bookDao;privateUserDao userDao;//setter注入需要提供要注入对象的set方法publicvoidsetUserDao(UserDao userDao){this.userDao = userDao;}//setter注入需要提供要注入对象的set方法publicvoidsetBookDao(BookDao bookDao){this.bookDao = bookDao;}publicvoidsave(){System.out.println("book service save ...");
bookDao.save();
userDao.save();}}
- 在核心配置类applicationContext中配置userDAO的bean,并将其注入到BookService中
- 执行模拟测试类App2
(从运行结果中可以看到多个引用类型是可以用setter注入的)
- 依赖注入 – setter注入普通类型的步骤方法
- 在BookDaoImpl中提供两个变量,并提供对应的setter方法(以BookDaoImpl为例)
publicclassBookDaoImplimplementsBookDao{privateString databaseName;privateint connectionNum;//setter注入需要提供要注入对象的set方法publicvoidsetConnectionNum(int connectionNum){this.connectionNum = connectionNum;}//setter注入需要提供要注入对象的set方法publicvoidsetDatabaseName(String databaseName){this.databaseName = databaseName;}publicvoidsave(){System.out.println("book dao save ..."+databaseName+","+connectionNum);}}
- 在核心配置类applicationContext.xml文件中配置中注入普通变量
- 模拟测试类App2类的运行结果
10.依赖注入 – 构造器注入
(在依赖注入–setter注入的基础上编码,将依赖注入相关的代码删掉,具体见个人主页上传的代码respr_diconstouctor)
1 . 依赖注入 – 构造器注入引用类型的步骤方法
- 在BookService类中提供构造方法
publicclassBookServiceImplimplementsBookService{//5.删除业务层中使用new的方式创建的dao对象privateBookDao bookDao;//提供构造方法publicBookServiceImpl(BookDao bookDao){this.bookDao = bookDao;}publicvoidsave(){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中定义两个变量,并编写对应的构造器方法
publicclassBookDaoImplimplementsBookDao{privateString databaseName;privateint connectionNum;publicBookDaoImpl(String databaseName,int connectionNum){this.databaseName = databaseName;this.connectionNum = connectionNum;}publicvoidsave(){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接口及其实现类
packageorg.example.dao;publicinterfaceBookDao2{publicvoidsave();}
publicclassBookDaoImpl2implementsBookDao2{//数组privateint[] array;//列表privateList<String> list;//集合privateSet<String> set;//图privateMap<String,String> map;//propertiesprivateProperties properties;//提供对应的setter方法作为ioc提供bean的入口publicvoidsetArray(int[] array){this.array = array;}publicvoidsetList(List<String> list){this.list = list;}publicvoidsetSet(Set<String> set){this.set = set;}publicvoidsetMap(Map<String,String> map){this.map = map;}publicvoidsetProperties(Properties properties){this.properties = properties;}//编写测试方法publicvoidsave(){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及其运行结果
publicclassApp{publicstaticvoidmain(String[] args){ApplicationContext ctx =newClassPathXmlApplicationContext("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方法输出
publicinterfaceBookDao{publicvoidsave();}
publicclassBookDaoImplimplementsBookDao{privateString name;publicvoidsetName(String name){this.name = name;}publicvoidsave(){System.out.println("book dao save ..."+ name);}}
- 模拟测试类及输出结果
6. 小结和拓展
14.IOC容器相关
- 创建容器
- 获取bean的方式
- 容器类层次结构
(BeanFactory接口创建完毕后,所有的bean均为延迟加载)
15.spring入门总结
- IOC容器相关
- bean相关
- 依赖注入相关
16.Spring整合Junit
引用网站及博客
1.【w3cschool】
2. 【sprign教学视频】
总结
欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下。
(博客的参考源码可以在我主页的资源里找到,如果在学习的过程中有什么疑问欢迎大家在评论区向我提出)
版权归原作者 东离与糖宝 所有, 如有侵权,请联系我们删除。