控制反转IOC
权利的角度
- 不管我们是传统的new一个对象还是,使用设计模式,比如工厂模式来创建一个对象,它始终是一个正向的运行模式。例如:对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上
- 软件系统在引入IOC容器之后,这种情形就完全改变了,如图3所示,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。
系统稳定的角度
- 为什么在一个类中实例化一个别的对象是不稳定的例如Student s = new Student,因为Student是可以随意变化的,这是具体的对象,所以我们是面向具体编程
- 但是依赖注入我们依赖的的是接口,接口就是抽象,抽象的是不变的,这样就保证A是稳定的,所以我们是面向对象开发······
依赖倒置:他一来
有意义的一句话
- 对象A依赖于对象B,当对象 A需要用到对象B的时候,IOC容器就会立即创建一个对象B送给对象A
- IOC容器就是一个对象制造工厂,你需要什么,它会给你送去,你直接使用就行了, 而再也不用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切全部由IOC容器包办
最后聊到这种解耦、独立自然而然的想到分布式、微服务的架构好处
- IOC(Inverse of control)就是将原本在程序中手动创建对象的控制权,交给Spring框架管理,简单说就是创建对象的权力由程序员反转到spring中
- DI(dependency injection)就是spring在创建这个对象的过程中,将这个对象所依赖的属性全部注入进去
- 面试题: 说说什么是IOC
- 先总体说明
- IOC控制反转,它是一种程序设计的思想。高层模块不该依赖于底层模块,指由第三方来管理和控制对象。
- 举例解释说明:
- 例如我们在学习java之初使用最原始的new创建对象的方式。这种在实际开发中是存在巨大的隐患,在工作中我们需要的类是很多的,当我们需要改变需求的时候,这时候我们的工作量是庞大的。因为我们这种传统使用new的方式在编译时候已经确定了我们的类。这时候Spring变应运而生了,我们将确定类的时间滞后,在运行时确定。当我们的程序在运行时由applicationContext对象容器动态的实例化类,这样对程序整个的依赖进行有效的解耦。
- 概述性结尾:
- 总的来说就是指在原始的情况下我们使用new关键字进行正向控制,控制反转就是将我们对象的控制权交给第三方的对象容器,在程序运行时动态的创建对应的对象,再赋给对应的变量。
- 面试题: 说说什么是DI
- 总说
- 都说IOC是宏观上一种程序的设计思想,DI(依赖注入)是我们在技术上的实现,由对象容器在运行时动态注入对象。
- 分说
常见的注入方式:
set方法注入/属性注入(常用
构造方法注入
接口注入…
AOP
JDK只可以对实现接口类的进行动态代理,cglib则是都可以
Bean的实例化过程
- spring在启动时读取Bean的配置信息
- 在spring容器中生成一份相对应的Bean配置注册表
- 根据Bean注册表去实例化Bean
- 将实例化的Bean实例放到Spring容器提供的Bean缓冲池中
-
生命周期的流程
实例化
bena
、对象实例化,instantiate bean
- 填充属性、封装属性,
populate properties
- 如果
bean
实现了BeanNameAware
执行setBeanName
,这样可以让bean
知道我们在配置文件中配置的id
名称 - 如果
bean
实现了BeanFactoryAware
或者ApplicationContextAware
设置工厂setBeanFactory
或者上下文对象setApplicationContext
,这个可以让bean了解工厂的信息 - 如果实现了后处理bean
(BeanPostProcessor)
执行postProcessBeforInitialization
- 如果
Bean
实现InitializingBean
执行afterPropertiesSet
- 如果存在则调用init-
method
指定的初始化方法 - 如果实现了后处理bean
(BeanPostProcessor)
,执行postProcessAfterInitialization
- 执行业务,调用类中的方法,这个需要对象显示的调用,例如
user.getname()
- 如果
bean
实现了DisposableBean
执行destory
-
常见的注解
Spring的常见
@Component
: 将类交给spring管理@Controller
: 对控制层/视图层标注@Service
: 服务层-
Spring MVC常用注解
@RequestMapping
@ResponseBody
@RequestParam
@CookicValue
@ModelAttribute
-
事务传播级别
never:
- 禁止方法声明事务,如果存在事务则抛出异常
- not_supported:
- 该方法不使用事务的形式执行;
- 如果当前有事务,则将该事务挂起,自己不使用事务去运行数据库操作
- supports:
- 如果当前有事务,则使用事务;
- 如果没有事务则不使用事务;多用于查询
- required:
- 如果当前的方法没有或者不存在事务,会创建一个新的事务;
- 如果方法已经存在事务,则加入到原来已经存在的事务中;
- 比如方法本身没有事务,但是调用方申明了事务,则事务会传递到被调用方;
- 多用于增、删、改
- mandatory:
- 必须强制有一个事务,理解为调用方必须支持事务,否则抛出异常
- requires_new:
- 核心是“会产生2个事务各自提交”
- 如果当前有事务,则挂起该事务,创建一个新的事务给自己使用
- 如果当前没有事务则和required相同
nested:
DispatchServlet
:中央处理器,也称调度服务器,它是整个流程控制的中心,由它调用其它组件处理用户请求,并且极大的降低的组件的耦合性Handler
:处理器,它是后端控制器,可能是一个Controller、intercepter
HandleMapping
:处理器映射器,根据用请求找到相对应的handler即Controller,并将Controller与HandlerInterceptor(拦截器)封装到 HandlerExecutionChain (控制器执行链)对象中HandlerAdapter
:处理器适配器,它可以调用controllerModelAndView
:是spring mvc
框架的一个底层对象,包括Model
和view
ViewResolver
:视图解析器View
:视图,springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。整体流程分析
执行步骤客户端发起请求到
DispatcherServlet
DispatcherServle
请求HandlerMapping
接口以及它的实现类查找Handle
- 可以根据
xml
配置、注解进行查找 - 这时候只是知道哪个控制器处理,但不会执行
Handler
,需要处理器适配器HandlerAdapter
- 可以根据
HandlerMapping
向DispatcherServlet
返回HandlerExecutionChain
对象,也叫执行链DispatcherServlet
调用HandlerAdapter
去执行Controller
HandlerAdapter
将会根据适配的结果去执行Handler
,因为需要判断Handler
的类型,这一步关键靠HttpMessageConverter
这个类对当前的请求和响应进行处理和设置Handler
执行完成给HandlerAdapter
返回ModelAndView
HandlerAdapter
向DispatcherServlet
返回ModelAndView
DispatcherServlet
请求ViewResolver
去进行视图解析- 根据逻辑视图名,判断你是哪种模板引擎
(jsp、freemark...)
,然后解析成真正的视图 - 通过这种策略很容易更换其他视图技术,只需要更改
ViewResolver
即可
- 根据逻辑视图名,判断你是哪种模板引擎
ViewResolver
向DispatcherServlet
返回解析完成的View
DispatcherServlet
视图渲染将模型数据,在ModelAndView
对象中填充到request
域-
执行链
执行流程的第三步,HandlerMapping返回一个执行链,它是
HandlerExecutionChain
对象- 包含一个
Handle
处理器对象 - 多个
HandlerInterceptor
拦截器对象
- 包含一个
- 所以第五步
HandlerAdapter
需要判断Hanle
类型,才只能执行Handle
,执行流程如下图所示 - 通过这种策略模式,很容易添加新的映射策略
不需要视图的情况
在大环境前后端分离的开发情况下,后端只需要返回对应的数据,如果使用@ResponseBody
注解之后不会再走试图处理器,而是直接将数据写入到流中,所以上诉流程走到底六步就终止了
拦截器的作用(重点)
- 作用:SpringMVC的拦截器作用于控制器方法进行前置,后置处理
- 实现技术:拦截底层实现技术是AOP,它必须实现HandlerInterceptor接口
- 常见用途:权限控制,登陆拦截,字符集的管理,国际化等等
- 拦截器是通过JDK动态代理来实现的,拦截器是对调用方法的拦截