控制反转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(依赖注入)是我们在技术上的实现,由对象容器在运行时动态注入对象。
  • 分说
    • DI是我们一种具体的技术实现,它是对IOC思想的一种诠释,在spring中使用的反射+工厂模式来实现了这个DI。

      依赖注入DI

常见的注入方式:
set方法注入/属性注入(常用
构造方法注入
接口注入…

AOP

JDK只可以对实现接口类的进行动态代理,cglib则是都可以
image.png

Bean的实例化过程

image.png

  1. spring在启动时读取Bean的配置信息
  2. 在spring容器中生成一份相对应的Bean配置注册表
  3. 根据Bean注册表去实例化Bean
  4. 将实例化的Bean实例放到Spring容器提供的Bean缓冲池中
  5. 将这些Bean给程序使用

    生命周期的流程

  6. 实例化bena、对象实例化,instantiate bean

  7. 填充属性、封装属性,populate properties
  8. 如果bean实现了BeanNameAware执行setBeanName,这样可以让bean知道我们在配置文件中配置的id名称
  9. 如果bean实现了BeanFactoryAware或者ApplicationContextAware设置工厂setBeanFactory或者上下文对象setApplicationContext,这个可以让bean了解工厂的信息
  10. 如果实现了后处理bean(BeanPostProcessor)执行postProcessBeforInitialization
  11. 如果Bean实现InitializingBean执行afterPropertiesSet
  12. 如果存在则调用init-method指定的初始化方法
  13. 如果实现了后处理bean(BeanPostProcessor),执行postProcessAfterInitialization
  14. 执行业务,调用类中的方法,这个需要对象显示的调用,例如user.getname()
  15. 如果bean实现了DisposableBean执行destory
  16. 如果存在调用执行的销毁方法destory-method

    常见的注解

    Spring的常见

  17. @Component: 将类交给spring管理

  18. @Controller: 对控制层/视图层标注
  19. @Service: 服务层
  20. @Repository: dao层、mapper层

    Spring MVC常用注解

  21. @RequestMapping

  22. @ResponseBody
  23. @RequestParam
  24. @CookicValue
  25. @ModelAttribute
  26. @SessionAttribute

    事务传播级别

  27. never:

    1. 禁止方法声明事务,如果存在事务则抛出异常
  28. not_supported:
    1. 该方法不使用事务的形式执行;
    2. 如果当前有事务,则将该事务挂起,自己不使用事务去运行数据库操作
  29. supports:
    1. 如果当前有事务,则使用事务;
    2. 如果没有事务则不使用事务;多用于查询
  30. required:
    1. 如果当前的方法没有或者不存在事务,会创建一个新的事务;
    2. 如果方法已经存在事务,则加入到原来已经存在的事务中;
    3. 比如方法本身没有事务,但是调用方申明了事务,则事务会传递到被调用方;
    4. 多用于增、删、改
  31. mandatory:
    1. 必须强制有一个事务,理解为调用方必须支持事务,否则抛出异常
  32. requires_new:
    1. 核心是“会产生2个事务各自提交”
    2. 如果当前有事务,则挂起该事务,创建一个新的事务给自己使用
    3. 如果当前没有事务则和required相同
  33. nested:

    1. 如果当前不存在事务则等于require;
    2. 如果当前有事务,会产生一个嵌套的事务,嵌套事务是独立提交或者回滚
    3. 如果主事务提交,会携带子事务一起提交
    4. 如果主事务回滚,会携带子事务一起回滚;子事务异常,主事务可以回滚也可以不回滚
    5. 领导决策不对,小弟跟着受罪;小弟犯错,领导可以推卸责任,也可以拉小弟一把

      Spring MVC的执行流程

      组件说明

  34. DispatchServlet:中央处理器,也称调度服务器,它是整个流程控制的中心,由它调用其它组件处理用户请求,并且极大的降低的组件的耦合性

  35. Handler:处理器,它是后端控制器,可能是一个Controller、intercepter
  36. HandleMapping:处理器映射器,根据用请求找到相对应的handler即Controller,并将Controller与HandlerInterceptor(拦截器)封装到 HandlerExecutionChain (控制器执行链)对象中
  37. HandlerAdapter:处理器适配器,它可以调用controller
  38. ModelAndView:是spring mvc框架的一个底层对象,包括 Modelview
  39. ViewResolver:视图解析器
  40. View:视图,springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。

    整体流程分析

    SSMB面试题 - 图3
    执行步骤

  41. 客户端发起请求到DispatcherServlet

  42. DispatcherServle请求HandlerMapping接口以及它的实现类查找 Handle
    1. 可以根据xml配置、注解进行查找
    2. 这时候只是知道哪个控制器处理,但不会执行Handler,需要处理器适配器HandlerAdapter
  43. HandlerMappingDispatcherServlet返回HandlerExecutionChain对象,也叫执行链
  44. DispatcherServlet调用HandlerAdapter去执行Controller
  45. HandlerAdapter将会根据适配的结果去执行Handler,因为需要判断Handler的类型,这一步关键靠HttpMessageConverter这个类对当前的请求和响应进行处理和设置
  46. Handler执行完成给HandlerAdapter返回ModelAndView
  47. HandlerAdapterDispatcherServlet返回ModelAndView
  48. DispatcherServlet请求ViewResolver去进行视图解析
    1. 根据逻辑视图名,判断你是哪种模板引擎(jsp、freemark...),然后解析成真正的视图
    2. 通过这种策略很容易更换其他视图技术,只需要更改ViewResolver即可
  49. ViewResolverDispatcherServlet返回解析完成的View
  50. DispatcherServlet视图渲染将模型数据,在ModelAndView对象中填充到request
  51. DispatcherServlet向用户响应结果

    执行链

  52. 执行流程的第三步,HandlerMapping返回一个执行链,它是HandlerExecutionChain对象

    1. 包含一个Handle处理器对象
    2. 多个HandlerInterceptor拦截器对象
  53. 所以第五步HandlerAdapter需要判断Hanle类型,才只能执行Handle,执行流程如下图所示
  54. 通过这种策略模式,很容易添加新的映射策略

image.png

不需要视图的情况

在大环境前后端分离的开发情况下,后端只需要返回对应的数据,如果使用@ResponseBody注解之后不会再走试图处理器,而是直接将数据写入到流中,所以上诉流程走到底六步就终止了

拦截器的作用(重点)

  1. 作用:SpringMVC的拦截器作用于控制器方法进行前置,后置处理
  2. 实现技术:拦截底层实现技术是AOP,它必须实现HandlerInterceptor接口
  3. 常见用途:权限控制,登陆拦截,字符集的管理,国际化等等
  4. 拦截器是通过JDK动态代理来实现的,拦截器是对调用方法的拦截