【Java】Jee 02 SSM原理
SSM (Spring + SpringMVC + MyBatis)
框架集由 Spring、MyBatis 两个开源框架整合而成,常作为数据源较简单的 Web 项目框架。本文总结SSM 框架的基本原理。
1 Spring
概念:Spring 是一个开源的轻量级 Java SE / Java EE 开发应用框架,其目的是用于简化企业级应用程序开发。
简化开发
- 面向 Bean:IoC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系
- IoC/DI(Inversion of Control 控制反转 / Dependency Injection 依赖注入)
- Spring 通过控制反转(IoC)的技术促进了松耦合。
- AOP(Aspect Oriented Programming 面向切面):Spring 提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现业务逻辑。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
- 实现原理:动态代理,基于 Java 代理机制。
- 面向切面编程:通过预编译和运行期动态代理的方式实现在不修改源代码的情况下给程序动态添加功能的技术
Spring生命周期:
- getBean;
- 调用 bean 的缺省构造函数;
- 根据 XML 中的配置设置 bean 的相关属性;
- 检查 bean 所实现的 aware 接口;
- BeanPostProcessor 前置处理;
- 检查 InitializingBean 接口;
- 检查 init-method 方法;
- BeanPostProcessor 后置处理;
- In Use;
- 检查 Disposable 接口;
- destroy 方法。
Spring 的配置文件中的内容
- 开启事务注解驱动
- 事务管理器
- 开启注解功能,并配置扫描包
- 配置数据库
- 配置 SQL 会话工厂,别名,映射文件
- 不用编写 Dao 层的实现类
1.1 系统架构
Spring 七大模块
- 核心模块:提供基础功能,核心类 BeanFactory 类。
- Context 模块:继承自 BeanFactory 类。
- AOP 模块:AOP 功能。
- DAO 模块:JDBC 底层抽象。
- O/R 映射模块:提供对 ORM 框架的支持。
- Web 模块:以 Spring Context 为基础。
- MVC 模块
1.2 IoC/DI与bean
IoC:将创建实例的任务交给 IoC 容器,开发应用代码时只需要直接使用类的实例。IoC 容器的初始化包括 BeanDefinition 的 Resource 定位、载入和注册这三个基本的过程
DI:IoC 的另一种表达形式。相对于 IoC 而言,这种表达更直接。DI 的三种方式,即为一个 bean 设置属性:
- Setter 注入:通过 setter 方法初始化,使用
<property>
标签(最常用)。 - 构造器注入:通过构造方法初始化,保证了 Bean 实例在实例化后就可以使用,使用
<constructor-arg>
标签。 - 接口注入(Spring 不支持)。
字面值
- 可用字符串表示的值,可以通过
<value>
元素标签或 value 属性进行注入。 - 基本数据类型及其封装类、String等类型都可以采取字面值注入的方式。
依赖注入的时间
- 用户第一次通过 getBean() 方法向 IoC 容索要 Bean 时,IoC 容器触发依赖注入。
- 当用户在 Bean 定义资源中为
<Bean>
元素配置了 lazy-init 属性,即让容器在解析注册 Bean 定义时进行预实例化,触发依赖注入。
1.2.1 bean
bean 生命周期(IoC 容器容器管理)
- Bean 的定义:通过配置文件定义 Bean
- Bean 的初始化
- 在配置文档中指定 init-method 属性
- 实现 org.springframwork.beans.factory.InitializingBean 接口,并且增加 afterPropertiesSet() 方法
- Bean 的调用
- 使用 BeanWrapper
- 使用 BeanFactory
- 使用 ApplicationContext
- Bean 的销毁
- 在配置文档中指定 destory-method 属性
- 实现 org.springframwork.bean.factory.DisposebleBean 接口
两种类型的 IoC 容器实现,Spring Bean 的创建是典型的工厂模式
BeanFactory
是 Spring 中比较原始、比较古老的 Factory。ApplicationContext
是 BeanFactory 的子类,基本上代替了 BeanFactory 的工作,以一种更面向框架的工作方式以及对上下文进行分层和实现继承,并在这个基础上对功能进行扩展。ApplicationContext 的实现类ClassPathXmlApplicationContext
:从当前类路径中检索配置文件并装在它来创建容器。FileSystemXmlApplicationContext
:通过参数指定配置文件的位置,可以获取类路径之外的资源。WebApplicationContext
:Spring 的 Web 应用容器。- 在 Servlet 的 web.xml 文件中配置 Spring 的 ContextLoaderListener 监听器;
- 在 web.xml 配置文件中添加 Servlet,定义使用 Spring 的 org.springframework.web.context.ContextLoaderServlet 类。
比较 | BeanFactory | ApplicationContext |
---|---|---|
创建 Bean | 延迟加载,调用 getBean() | 容器启动时一次性创建 |
创建方式 | 编程式 | 声明式 |
bean 实例化的方式
- 使用类构造器实例化(默认无参数)
<bean id="bean1" class="com.Bean1"></bean>
- 使用静态工厂方法实例化(简单工厂模式):调用 Bean2Factory 的 getBean2 方法得到 bean2
<bean id="bean2" class="com.Bean2Factory" factory-method="getBean2"></bean>
- 使用实例工厂方法实例化(工厂方法模式):先创建工厂实例 bean3Facory,再通过工厂实例创建目标 bean 实例
<bean id="bean3Factory" class="com.Bean3Factory"></bean> <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
配置 bean
- 依赖注入
- Setter 注入
<property name="name"><value>nju</value></property>
- 构造器注入
<constructor-arg name="name"><value>nju</value></constructor-arg>
- 匿名内部 JavaBean
<property name="student"><bean class="Student"/></property> <constructor-arg name="student"><bean class="Student"/></constructor-arg>
- 引用其它的 bean
<constructor-arg name="user"><ref local="user"/></constructor-arg>
- 自动装配(autowire):将一个 Bean 注入到其他 Bean 的 Property 中
- 按 bean 名称装配
<bean autowire="byName" id="printInfo" class="com.PrintInfo"/>
- 按 bean 类型装配
<bean autowire="byName" id="printInfo" class="com.PrintInfo"/>
- no 属性
- constructor 属性
- autodetect 属性
- 按 bean 名称装配
- 自动装配(autowire):将一个 Bean 注入到其他 Bean 的 Property 中
- Setter 注入
bean 作用域:在 <bean>
元素的 scope 属性里设置 bean 的作用域
singleton
:在 Spring IoC 容器中仅存在一个 Bean 实例,bean 以单例的方式存在。(默认)prototype
:每次调用 getBean() 时都会返回一个新的实例。request
:每次 http 请求都会创建一个新的 bean,该作用域仅适用于 WebpplicationContext 环境。session
:同一个 HTTP Session 共享一个 Bean,不同的 HTTP Sessionn 使用不同的 Beana.该作用域仅适用于 WebApplicationContext 环境。
1.3 AOP
AOP 解决的问题:代码混乱、代码分散、动态代理。
AspectJ
是 Java 社区里最完整最流行的 AOP 框架
AOP 术语
- 切面(Aspect):对象操作中的截面。实际上是一段程序代码。
- 连接点(Join Point):对象操作中的某个阶段点。实际上是对象的一个操作,如调用某个方法、读写对象。
- 切入点(PointCut):切入点是连接点的集合。
- 通知(Advice):某个切入点被横切后,所采取的逻辑操作。即,在“切入点”初拦截程序后,通过“通知”来执行“切面”。
- 目标对象(Target):被通知的对象。
- 织入(Weaving):将切面功能应用到模板对象的过程。
- 编译时期织入、类加载时期织入、执行器织入(常见)
- 引入(Introduction):对一个已编译完的类,在运行时期动态地向这个类中加载属性和方法。
1.3.1 事务
Spring 事务的本质其实就是数据库对事务的支持。基于 AOP 实现。
Spring 事务管理:一般使用 TransactionMananger
进行管理,可以通过 Spring 的注入来完成此功能。
- 编程式事务管理:编程方式管理事务,极大灵活性,难维护。主要使用
TransactionTemplate
实现。 - 声明式事务管理:可以将业务代码和事务管理分离,用注解和 xml 配置来管理事务。使用
TransactionProxyFactoryBean
实现。主要选择。
配置事务隔离级别
- 在
@Transactional
的isolation
属性中设置隔离级别 - 在
<tx:method>
元素中指定隔离级别
1.4 Spring下的注解
- 注册:@Controller、@Service、@Repository
@Controller
对应表现层的 Bean,也就是 Action。使用 @Controller 注解标识 UserController 之后,就表示要把 UserController 交给Spring容器管理,在 Spring 容器中会存在一个名字为 “userController” 的 Action,这个名字是根据 UserController 类名来取的。@Service
对应的是业务层 Bean。@Repository
对应数据访问层 Bean。
- 注入:@Autowired 与 @Resource
@Autowired
按 byType 自动注入,默认情况下必须要求依赖对象必须存在。@Resource
默认按 byName 自动注入,有两个重要属性 name 和 type- @Autowired 与 @Resource 都可以用来装配 bean。都可以写在字段上,或写在 setter 方法上。
- 请求地址:@RequestMapping
@RequestMapping
是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。@RequestMapping 注解有六个属性:value、method、consumes、produces、params、headers。
- 返回具体数据类型而非跳转:
@ResponseBody
Spring中主要的设计模式
- 工厂模式:每个 Bean 的创建通过方法
- 单例模式:默认的每个 Bean 的作用域都是单例
- 代理模式:关于 AOP 的实现通过代理模式
- 策略模式:定义一系列的算法,把它们一个个的封装起来,并且使它们可以相互替换。在实例化对象时用到。
2 SpringMVC
SpringMVC 在项目中拦截用户请求,它的核心 Servlet 即 DispatcherServlet 承担中介或是前台这样的职责,将用户请求通过 HandlerMapping去匹配 Controller,Controller 就是具体对应请求所执行的操作。
基本组成
- DispatcherServlet:找到对应请求的 HandlerMapping,将请求转发给对应的 HandlerAdapter
- 处理器映射器 HandlerMapping:保存请求的URL与Handler(可以是 Controller 或 Servlet 等)的对应关系
- 处理器适配器 HandlerAdapter:调用对应的Handler进行处理,并返回 ModelAndView对象给DispatcherServlet
- 控制器 Controller
- 拦截器 HandlerInterceptor:preHandle、postHandle、afterCompletion 方法
- HandlerExecutionChain:负责 Handler 执行前后的 HandlerInterceptor 的调用
- 模型视图 ModelAndView
- 模型 Model/ModelMap
- 视图解析器 ViewResolver:将逻辑视图转换成物理视图
SpringMVC工作流程
- 用户发送请求至前端控制器 DispatcherServlet
- DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。
- 处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给 DispatcherServlet
- DispatcherServlet 调用 HandlerAdapter 处理器适配器
- HandlerAdapter 经过适配调用具体的处理器(Controller,也叫后端控制器)。
- Controller 执行完成返回 ModelAndView
- HandlerAdapter 将 controller 执行结果 ModelAndView 返回给 DispatcherServlet
- DispatcherServlet 将 ModelAndView传给 ViewReslover 视图解析器
- ViewReslover 解析后返回具体 View
- DispatcherServlet 根据 View 进行渲染视图(即将模型数据填充至视图中)
- DispatcherServlet 响应用户
@RequestMapping 注解用来映射一个 URL 到一个类或一个特定的方处理法上。
返回值
- SpringMVC 中函数的返回值可以有很多类型,有 String、ModelAndView、List、Set 等,一般用 String,如果是 AJAX 请求,返回的可以是一个集合
- SpringMVC 根据配置文件中 InternalResourceViewResolver(内部资源视图解析器)的前缀和后缀,用前缀 + 返回值 + 后缀组成完整的返回值
- 转发:在返回值前面加 “forward:”
- 重定向:在返回值前面加 “redirect:”
3 Mybatis
MyBatis 是一个持久层框架,它对 jdbc 的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理 jdbc 繁杂的过程代码。
MyBatis 优点
- 半自动化的 ORM 实现
- 对象关系映射(Object Relational Mapping,ORM),用于实现面向对象编程语言里不同类型系统的数据之间的转换
- 动态 SQL
Mybatis的好处
- 把Sql语句从Java中独立出来。
- 封装了底层的JDBC,API的调用,并且能够将结果集自动转换成JavaBean对象,简化了Java数据库编程的重复工作。
- 自己编写Sql语句,更加的灵活。
- 入参无需用对象封装(或者map封装),使用@Param注解
3.1 sqlSession
Mybatis 的操作都是围绕一个 sqlSessionFactory 实例展开的。Mybatis 通过配置文件关联到各实体类的 Mapper 文件,Mapper 文件中配置了每个类对数据库所需进行的 sql 语句映射。在每次与数据库交互时,通过 sqlSessionFactory 拿到一个 sqlSession,再执行 sql 命令。
Mybatis 在核心处理类:SqlSession。SqlSession 重要的四个对象
Execute
:调度执行 StatementHandler、ParmmeterHandler、ResultHandler 执行相应的SQL语句;StatementHandler
:使用数据库中 Statement(PrepareStatement)执行操作,即底层是封装好了的 prepareStatement;ParammeterHandler
:处理 SQL 参数;ResultHandler
:结果集 ResultSet 封装处理返回。
作用域和生命周期
SqlSessionFactoryBuilder
:这个类可以在任何时候被实例化、使用和销毁。一旦创造了 SqlSessionFactory 就不需要它了。所以SqlSessionFactoryBuilder 实例的最好的作用域是方法体内(即一个本地方法变量)。SqlSessionFactory
:一旦创建,SqlSessionFactory 将会存在于您的应用程序整个运行生命周期中。很少或根本没有理由去销毁它或重新创建它。SqlSessionFactory 最好的作用域范围是一个应用的生命周期范围。SqlSession
:每个线程都有一个 SqlSession 实例,SqlSession 实例是不被共享的,并且不是线程安全的。最好的作用域是 request 或者方法。Mapper 实例
:Mappers 是创建来绑定映射语句的接口,Mapper 实例是从 SqlSession 得到的。因此,所有 mapper 实例的作用域跟创建它的SqlSession 一样。
3.2 Mapper实例
Mybatis 的接口绑定:Mybatis 实现了 DAO 接口与 xml 映射文件的绑定,自动为我们生成接口的具体实现,使用起来变得更加省事和方便。
SqlSession 运行步骤:
- prepare 预编译 SQL;
- parameterize 设置参数;
- doUpdate/doQuery 执行 SQL;
类型处理器 TypeHandler:每当 MyBatis 设置参数到 PreparedStatement 或者从 ResultSet 结果集中取得值时,就会使用 TypeHandler 来处理数据库类型与 Java 类型之间转换。
Mybatis 的逆向工程中会生成实例及实例对应的 example,example 用于添加条件,相当 where 后面的部分。
传参方式
- 传入一个参数
#{参数名}
- 索引方式,传入多个参数
#{0}、#{1}
- 传入多个参数,并且参数用@param注解
#{参数名}
- 传入多个基本类型参数,参数用map封装,通过
#{mapKey}
取值 - 使用map封装实体类,通过通过
#{mapKey.attributeName}
取值 - 直接传入实体参数,通过
#{属性名}
取值
${}
与 #{}
#{}
:预编译处理,sql中的#{}
替换成?
,补全预编译语句,有效的防止 Sql 语句注入,这种取值是编译好 SQL 语句再取值。拿到值之后拼装 sql,会自动对值添加单引号'
。${}
:简单字符串替换,把${}
直接替换成变量的值,不做任何转换,这种是取值以后再去编译 SQL 语句。拿到值之后拼装进 sql,如果需要加单引号'
,必须手动添加。需要添加属性statementType="STATEMENT"
。
3.3 缓存
MyBatis 中的缓存就是说 MyBatis 在执行一次SQL查询或者 SQL 更新之后,这条 SQL 语句并不会消失,而是被 MyBatis 缓存起来,当再次执行相同 SQL 语句的时候,就会直接从缓存中进行提取,而不是再次执行 SQL 命令。
- 一级缓存又称 SqlSession 级别的缓存
- 二级缓存又称表级缓存。
3.4 常用注解
- 增 @Insert
- 删 @Delete
- 改 @Update
- 查 @Select