前言
这篇文章主要是从基础开始一步步学习SSM框架。因为这是一份学习笔记,所以会按照课程将模块分成多章节来写。
系列文章传送
文章目录
一、认识SSM框架
学技术的时候,我们首先要了解我们学习的东西是什么,有什么用处。
SSM(Spring+SpringMVC+MyBatis)框架集由Spring、MyBatis两个开源框架整合而成(SpringMVC是Spring中的部分内容)。常作为数据源较简单的web项目的框架。–来源:百度百科
1.Spring框架是什么?
Spring是分层的JavaSE/EE full-stack 轻量级开源框架,以IoC (Inverse of Control 控制反转) 和AOP(Aspect Oriented Programming 面向切面编程) 为内核,使用基本的JavaBean来完成以前只可能由EJB完成的工作,取代了EJB的臃肿、低效的开发模式。
2.SpringMVC是什么?
SpringMVC在项目中拦截用户请求,它的核心Servlet即DispatcherServlet承担中介或是前台这样的职责,将用户请求通过HandlerMapping去匹配Controller,Controller就是具体对应请求所执行的操作。SpringMVC相当于SSH框架中struts。–来源:百度百科
3.MyBatis框架是什么?
MyBatis(前身是iBatis)是一个支持普通SQL查询、存储过程以及高级映射的持久层框架。 也被称之为ORM(Object/Relation Mapping,即对象关系映射) 框架。
所谓的ORM就是一种为了解决面向对象与关系型数据库中数据类型不匹配的技术,它通过描述Java对象与数据库表之间的映射关系,自动将Java应用程序中的对象持久化到关系型数据库的表中。
OK,了解这SSM框架的三个组成部分,接下来我们来详细学习每一个部分。
二、Spring基础
1-1.Spring的技术支持
在实际开发中,通常服务器端在采用三层体系架构,分别为表示层(Web)、业务逻辑层(Service)、持久层(Dao), Spring对每一层都提供了技术支持。
1-2.Spring框架的优点
1.非侵入式设计
2.方便解耦、简化开发
3.支持AOP
4.支持声明式事务处理
5.方便程序测试
6.方便集成各种优秀框架
7.降低Java EE API的使用难度
1-3.Spring的体系结构
Spring框架采用分层架构,灰色为主要模块。
(1)Core Container (核心容器)
Beans: 提供了BeanFactory,Spring将管理对象称为Bean。
Core: 提供了Spring框架的基本组成部分,包括IoC和DI功能。
Context: 建立在Core和Beans模块的基础之上,它是访问定义和配置的任何对象的媒介。
SpEL: Spring3.0后新增的模块,是运行时查询和操作对象图的强大的表达式语言。
(2)Data Access/Integration (数据访问/集成)
JDBC: 提供了一个JDBC的抽象层,大幅度的减少了在开发过程中对数据库操作的编码。
ORM: 对流行的对象关系映射API,包括JPA、JDO和Hibernate提供了集成层支持。
OXM: 提供了一个支持对象/ XML映射的抽象层实现,如JAXB、Castor、XMLBeans、JiBX和XStream。
JMS: 指Java消息传递服务,包含使用和产生信息的特性,自4.1版本后支持与Spring-message模块的集成。
Transactions: 支持对实现特殊接口以及所有POJO类的编程和声明式的事务管理。
(3)Web (网络)
WebSocket: Spring4.0以后新增的模块,它提供了WebSocket 和SockJS的实现,以及对STOMP的支持。
Servlet: 也称Spring-webmvc模块,包含Spring模型—视图—控制器(MVC)和REST Web Services实现的Web程序
Web: 提供了基本的Web开发集成特性,如:多文件上传、使用Servlet监听器来初始化IoC容器以及Web应用上下文。
Portlet: 提供了在portlet环境中使用MVC实现,类似Servlet模块的功能。
(4)其他模块
AOP: 提供了面向切面编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以降低耦合性。
Aspects: 提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的面向切面编程(AOP)框架。
Instrumentation: 提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
Messaging: Spring4.0以后新增的模块,它提供了对消息传递体系结构和协议的支持。
Test: 支持对实现特殊接口以及所有POJO类的编程和声明式的事务管理。
1-4.Spring的目录结构
Spring框架包下载地址:
https://repo.spring.io/release/org/
springframework/spring/5.2.3.RELEASE/
(1)spring基础包
libs目录中有四个Spring的基础包,分别对应Spring核心容器的四个模块。
spring-core-5.2.3.RELEASE.jar
核心工具类,Spring其它组件都要用到这个包里的类。
spring-beans-5.2.3.RELEASE.jar
所有应用都要用到的JAR包,包含访问配置文件、创建和管理Bean以及进行控制反转或者依赖注入操作相关的所有类。
spring-context-5.2.3.RELEASE.jar
提供了在基础IoC功能上的扩展服务及企业级服务的支持。
spring-expression-5.2.3.RELEASE.jar
表达式语言。
(2)lib的三种文件
在libs目录里有三种文件结尾分别是:class文件、API文档、源码文件。
2-1.BeanFactory
BeanFactory 是容器最基础的类,Spring核心容器之一。
创建BeanFactory实例时,需提供Spring所管理容器的详细配置信息。
通常采用XML文件形式来管理,其加载配置信息:
2-2.ApplicationContext
BeanFactory的子接口,也是Spring核心容器之一。
不仅包含了BeanFactory的所有功能,还添加了对国际化、资源访问、事件传播等方面的支持。
创建该接口实例,通常采用两种方法:
(1)通过ClassPathXmlApplicationContext创建
从类路径classPath中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作。
(2)通过FileSystemXmlApplicationContext创建
从指定的文件系统路径 (绝对路径) 中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作。
2-3.获取Bean方法
创建Spring容器后,就可以获取Spring容器中的Bean。
Spring获取Bean的实例通常采用以下两种方法:
(1)Object getBean(String name);
根据容器中Bean的id或name来获取指定的Bean,获取之后需要进行强制类型转换。
(2) T getBean(Class requiredType);
根据类的类型来获取Bean的实例。由于此方法为泛型方法,因此在获取Bean之后不需要进行强制类型转换。
3-1.Spring的Hello World!
入门程序----让程序输出 Hello World!
项目结构如下:
如果不会在IDEA里构建Web结构,可以参考一下这篇文章:
https://blog.csdn.net/weixin_48425200/article/details/120091735
在src目录下,创建一个com.itheima.ioc包,并在包中创建接口UserDao,代码如下:
package com.itheima.ioc;
public interface UserDao {public void say();}
在com.itheima.ioc包下,创建UserDao接口的实现类UserDaoImpl,代码如下:
package com.itheima.ioc;
public class UserDaoImpl implements UserDao {
public void say() {
System.out.println("userDao say hello World !");
}
}
在src目录下,创建Spring的applicationContext.xml配置文件,并在配置文件中创建一个id为userDao的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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 将指定类配置给Spring,让Spring创建其对象的实例 -->
<bean id="userDao" class="com.itheima.ioc.UserDaoImpl"/>
</beans>
在com.itheima.ioc包下,创建测试类TestIoC,代码如下:
package com.itheima.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestIoC {
public static void main(String[] args) {
//初始化Spring容器,并加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过Spring容器获取userDao实例(即Java对象),
UserDao userDao = (UserDao)
applicationContext.getBean("userDao");
//调用实例中的say()方法
userDao.say();
}
}
预期结果为:
4-1.依赖注入
DI(Dependency Injection,依赖注入)。它与控制反转(IoC) 的含义相同,只是它们是从两个角度描述的同一个概念。
(1)IoC (控制反转)
在Spring框架中,对象的实例不再由调用者来创建,而是由Spring容器来创建,程序之间的关系由Spring容器控制,而不是调用者的程序代码。 这样,控制权由应用代码转移到了Spring容器,控制权发生了反转。
(2)DI (依赖注入)
从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是Spring的依赖注入。
4-2.依赖注入的实现方式
使用setter方法实现依赖注入
项目结构如下:
在src目录下,创建一个com.itheima.ioc包,并在包中创建接口UserDao,代码如下:
package com.itheima.ioc;
public interface UserDao {
public void say();
}
在com.itheima.ioc包下,创建UserDao接口的实现类UserDaoImpl,代码如下:
package com.itheima.ioc;
public class UserDaoImpl implements UserDao {
public void say() {
System.out.println("userDao say hello World !");
}
}
在src目录下,创建一个com.itheima.ioc包,并在包中创建接口UserService,代码如下:
package com.itheima.ioc;
public interface UserService {
public void say();
}
在com.itheima.ioc包中,创建UserService接口的实现类UserServiceImpl,在类中声明userDao属性及setter方法,代码如下:
package com.itheima.ioc;
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void say() {
this.userDao.say();
System.out.println("userService say hello World !");
}
}
在配置文件applicationContext.xml中,创建一个id为userService的Bean,该Bean用于实例化UserServiceImpl类的信息,并将userDao的实例注入到userService中。
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 将指定类配置给Spring,让Spring创建其对象的实例 -->
<bean id="userDao" class="com.itheima.ioc.UserDaoImpl" />
<!--添加一个id为userService的实例 -->
<bean id="userService" class="com.itheima.ioc.UserServiceImpl">
<!-- 将id为userDao的Bean实例注入到userService实例中 -->
<property name="userDao" ref="userDao" />
</bean>
</beans>
在com.itheima.ioc包中,创建测试类TestDI,代码如下:
package com.itheima.ioc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestDI {
public static void main(String[] args){
ApplicationContext applicationContext = new
ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService=(UserService)
applicationContext.getBean("userService");
userService.say();
}
}
预期结果为:
三、Spring的Bean
1-1.什么是Spring的Bean?
Bean的本质就是Java中的类,而Spring中的Bean其实就是对实体类的引用,来生产Java类对象,从而实现生产和管理Bean 。
如果把Spring看做一个大型工厂,则Spring容器中的Bean就是该工厂的产品。要想使用这个工厂生产和管理Bean,就需要在配置文件中告诉它需要哪些Bean,以及需要使用何种方式将这些Bean装配到一起。
1-2.Bean的配置文件格式
在实际开发中,最常使用的是XML文件格式的配置方式,这种配置方式是通过XML文件来注册并管理Bean之间的依赖关系。
1-3.beans元素的属性
beans是XML配置文件的根元素,包含了多个bean子元素,每一个bean子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。
beans元素的常用属性
属性或子元素名称 | 描述 |
---|---|
id | 是一个Bean的唯一标识符,Spring容器对Bean的配置、管理都通过该属性来完成 |
name | Spring容器同样可以通过此属性对容器中的Bean进行配置和管理,name属性中可以未Bean指定多个名称,每个名称之间用逗号或分号隔开 |
class | 该属性指定了Bean的具体实现类,它必须是一个完整的类名,使用类的权限定名 |
scope | 用来设定Bean实例的作用域,其属性有singleton(单例)、prototype(原型)、request、session、global Session、application 和websocket。其默认值为singleton |
constructor-arg | Bean元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的index属性指定构造参数的序号(从0开始),type属性指定构造参数的类型,参数值可以通过ref属性或value属性直接指定,也可以通过ref或value子元素指定 |
property | Bean元素的子元素,用于调用Bean实例中的setter方法完成属性赋值,从而完成依赖注入。该元素的name属性指定Bean实例中的相应属性名,ref属性或value属性用于指定参数值 |
ref | property、constructor-arg 等元素的属性或子元素,可以用于指定对Bean工厂中某个Bean实例的引用 |
value | property、constructor-arg 等元素的属性或子元素。可以用于直接指定一个常量值 |
list | 用于封装List或数组类型的依赖注入 |
set | 用于封装Set类型属性的依赖注入 |
map | 用于封装Map类型属性的依赖注入 |
entry | map 元素的子元素,用于设置一个键值对。其key属性指定字符串类型的键值,ref或value子元素指定其值,也可以通过value-ref或value属性指定其值 |
1-4.Bean的配置文件
在配置文件中,通常一个普通的Bean只需要定义id(或name)和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="bean1" class="com.itheima.Bean1" />
<bean name="bean2" class="com.itheima.Bean2" />
</beans>
如果在Bean中未指定id和name属性,则Spring会将class属性当作id使用。
(1)多个配置文件来创建Bean
将Bean都配置在同一个xml文件中,将不利于阅读和维护。在Spring中,一般是将一个大的配置文件按模块分成多个小的配置文件来管理,在运行时再将这些配置文件加载汇总成一个配置文件。实际项目中,将Spring配置文件按模块、按组件类型分开配置,有利于团队开发和后期维护,因此程序需要根据多个配置文件来创建Spring容器。
(2)加载多个配置文件的方法
Spring自动将多个配置文件在内存中整合成一个配置文件。
方法:
ClassPathXmlApplicationContext(java.lang.String… configLocations)
FileSystemXmlApplicationContext(java.lang.String… configLocations)
配置文件的加载方式有如下几种:
1.在XML配置文件中导入其它XML配置文件
(1)在配置文件中使用标签导入其它配置文件
(2)每个配置文件使用一个来导入。如bean.xml
(3)ApplicationContext contex=new ClassXmlApplicationContext(“bean.xml");
2.使用ApplcationContext加载多个配置文件
ApplicationContext ctx=new ClassXmlApplicationContext(
new String["bean1.xml", "bean2.xml"]);
BeanDefinitionRegistry a=new DefaultListableBeanFactory();
XmlBeanDefinitionReader r=new XmlBeanDefinitionReader(a);
r.loadBeanDefinitions(new ClassPathResource("bean1.xml"));
r.loadBeanDefinitions(new classPathResource("bean2.xml"));
BeanFactory bf = (BeanFactory)reg;
3.Web应用启动时加载多个配置文件
(1)在web.xml中定义contextConfigLocation参数,加载所有逗号分割的xml。如果没有这个参数,spring默认加载WEB-INF/applicationContext.xml文件。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:conf/spring/applicationContext_core*.xml,
classpath*:conf/spring/applicationContext_dict*.xml,
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener> 利用ServletContextListener实现
2-1.Bean的实例化
在面向对象的程序中,想要使用某个对象,就需要先实例化这个对象。同样,在Spring中,要想使用容器中的Bean,也需要实例化Bean。实例化Bean有三种方式,分别为构造器实例化、静态工厂方式实例化和实例工厂方式实例化(其中最常用的是构造器实例化)。
三个方式的目录结构(写在一个项目里):
(1)构造器实例化
构造器实例化是指Spring容器通过Bean对应的类中默认的构造函数来实例化Bean。方法如下:
1.创建Web项目,导入相关Jar包;
2.创建名为Bean1的Java类;
package com.itheima.instance.constructor;
public class Bean1 {
}
3.创建Spring配置文件beans1.xml,并配置Bean1实体类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-4.3.xsd">
<bean id="bean1" class="com.itheima.instance.constructor.Bean1" />
</beans>
4.创建测试类,测试程序。
public class InstanceTest1 {
public static void main(String[] args) {
String xmlPath = "com/itheima/instance/constructor/beans1.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
Bean1 bean = (Bean1) applicationContext.getBean("bean1");
System.out.println(bean);
}
}
(2)静态工厂方式实例化
静态工厂是实例化Bean的另一种方式。该方式要求自己创建一个静态工厂的方法来创建Bean的实例。方法如下:
1.创建名为Bean2的Java类;
package com.itheima.instance.static_factory;
public class Bean2 {
}
2.创建一个Java工厂类,在类中使用静态方法获取Bean2实例;
package com.itheima.instance.static_factory;
public class MyBean2Factory {
//使用自己的工厂创建Bean2实例
public static Bean2 createBean(){
return new Bean2();
}
}
3.创建Spring配置文件beansxml,并配置工厂类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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bean2"
class="com.itheima.instance.static_factory.MyBean2Factory"
factory-method="createBean" />
</beans>
4.创建测试类,测试程序。
package com.itheima.instance.static_factory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InstanceTest2 {
public static void main(String[] args) {
// 定义配置文件路径
String xmlPath =
"com/itheima/instance/static_factory/beans2.xml";
// ApplicationContext在加载配置文件时,对Bean进行实例化
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
System.out.println(applicationContext.getBean("bean2"));
}
}
(3)实例工厂方式实例化
采用直接创建Bean实例的方式,在配置文件中,通过factory-bean属性配置一个实例工厂,然后使用factory-method属性确定使用工厂中的哪个方法。方法如下:
1.创建名为Bean3的Java类;
package com.itheima.instance.factory;
public class Bean3 {
}
2.创建一个Java工厂类,在类中使用非静态方法获取Bean3实例;
package com.itheima.instance.factory;
public class MyBean3Factory {
public MyBean3Factory() {
System.out.println("bean3工厂实例化中");
}
//创建Bean3实例的方法
public Bean3 createBean(){
return new Bean3();
}
}
3.创建Spring配置文件beans3.xml,并配置工厂类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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置工厂 -->
<bean id="myBean3Factory"
class="com.itheima.instance.factory.MyBean3Factory" />
<!-- 使用factory-bean属性指向配置的实例工厂,
使用factory-method属性确定使用工厂中的哪个方法-->
<bean id="bean3" factory-bean="myBean3Factory"
factory-method="createBean" />
</beans>
4.创建测试类,测试程序。
package com.itheima.instance.factory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class InstanceTest3 {
public static void main(String[] args) {
// 指定配置文件路径
String xmlPath = "com/itheima/instance/factory/beans3.xml";
// ApplicationContext在加载配置文件时,对Bean进行实例化
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext(xmlPath);
System.out.println(applicationContext.getBean("bean3"));
}
}
3-1.Bean的作用域
作用域的种类
作用域名称 | 说明 |
---|---|
singleton(单例) | 使用singleton定义的Bean在Spring容器中将只有一个实例,也就是说,无论有多少个Bean引用它,始终将指向同一个对象。这也是Spring容器默认的作用域。 |
prototype(原型) | 每次通过Spring容器获取的prototype定义的Bean时,容器都将创建一个新的Bean实例。 |
request | 在一次HTTP请求中,容器会返回该Bean的同一个实例。对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Request内有效。 |
session | 在一次HTTP Session 中,容器返回该Bean的同一个实例。对不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前HTTP Session内有效。 |
globalSession | 在一个全局的HTTP Session中,容器会返回该Bean的同一个实例。仅在使用portlet上下文时有效。 |
application | 为每个ServletContext对象创建一个实例。仅在web相关的ApplicationContext中生效。 |
websocket | 为每个websocket对象创建一个实例。仅在Web相关的ApplicationContext中生效。 |
singleton和prototype是最常用的两种作用域。
(1)singleton作用域
Spring容器默认的作用域,此作用域下,Spring容器只会存在一个共享的Bean实例。对于无会话状态的Bean(如Dao 组件、Service组件)来说, singleton作用域是最理想的选择。
在Spring配置文件中,可以使用bean元素的scope属性,将Bean的作用域定义成singleton。代码如下:
<bean id="scope" class="com.itheima.scope.Scope" scope="singleton"/>
(2)prototype作用域
对需要保持会话状态的Bean(如Struts 2的Action类)应该使用prototype作用域。在使用prototype作用域时,Spring容器会为每个对该Bean的请求都创建一个新的实例。
在Spring配置文件中,同样使用bean元素的scope属性,将Bean的作用域定义成prototype。代码如下:
<bean id="scope" class="com.itheima.scope.Scope" scope=" prototype "/>
4-1.Bean的生命周期
Spring中Bean的生命周期有何意义?
其意义就在于,可以利用Bean在其存活期间的特定时刻完成一些相关操作。这种时刻可能有很多,但一般情况下,常会在Bean的postinitiation (初始化后) 和predestruction (销毁前) 执行一些相关操作。
Spring容器可以管理Bean部分作用域的生命周期。说明如下:
作用域 | 说明 |
---|---|
singleton作用域 | 在此作用域下,Spring能够精确的知道该Bean何时被创建,何时初始化完成,以及何时被销毁。 |
prototype作用域 | prototype作用域的Bean,Spring只负责创建,当容器创建了Bean实例后,Bean的实例就交给客户端代码来管理,Spring容器将不再跟踪其生命周期。 |
总结(持续学习中)
第二章小结
本讲主要介绍了Spring框架入门的一些基础知识,包括Spring的概念、优点、体系结构、核心容器、依赖注入等,同时通过一个入门程序讲解了Spring的基本使用。
第三章小结
本讲对Spring的Bean进行了详细讲解,首先介绍了Bean的配置,然后通过案例讲解了Bean实例化的三种方式,最后介绍了Bean的作用域和生命周期。