IOC,也叫控制反转,是Spring用来解耦的一种设计思想,它的做法就是将对象的控制权由程序员手中反转到Spring手中。具体来说呢就是,在没有IOC之前,对象都是程序员在类中主动去创建,需要哪个创建哪个;有了IOC之后,对象会交给Spring容器创建和管理,如果哪个对象中需要其它对象属性,Spring也会自动完成依赖注入。
总之一句话,IOC可以将对象的创建和对象之间依赖关系的维护交给Spring自动完成。
依赖注入指的是Spring给对象中属性进行赋值的过程,主要包括两种方式:
构造器依赖注入:构造器注入是指容器调用一个类的构造器创建对象时,直接传入给属性赋值
Setter方法注入:Setter方法注入是指容器在创建对象完成后,通过调用属性的Setter 方法,可以属性赋值
我们常用的Spring注解主要分类下面几大类:
1、创建对象:@Component、@Controller、@Service、@Repository
它们都可以标注在自己开发的类上,Spring会使用注解标注的类创建出对象,然后放入容器
2、依赖注入:@Autowired
标注在属性或者属性对应的set方法上,Spring会根据被标注属性的类型自动对属性进行赋值
3、依赖注入:@Qualifier
和@Autowired一块使用,在同一类型的bean有多个的情况下Spring会根据name进行选择注入
4、配置类:@Configuration、@Bean
主要标注在配置类中,用于声明配置类和向Spring容器中放入一些配置有关的对象
5、当然还有一些平时用的不是特别多的
比如:声明注解扫描的@ComponentScan,声明Bean的作用域的@Scope,用于切面编程的@Around,@Pointcut等等
在Spring中作用域是用来对象的存活范围的,它支持5种作用域
第一种是单例,配置为单例的对象会跟随Spring容器创建而创建,跟随Spring容器销毁而销毁,在Spring容器中无论获取多少次单例对象,得到的都是同一个,这也是Spring中的对象的默认作用域
第二种是多例,配置为多例的对象在每次获取的时候才会创建,而且每次获取到的都不一样
还有三种分别是request、session和application,目前已经基本不再使用
其实,在我们平时的开发过程中,对象基本上都是配为单例的,这样可以有效的节省资源,只有单例对象存在线程安全问题时,才考虑调整为多例。
Spring中的Bean主要分为单例和多例
所以,最终我们得出结论,在Spring中,只有有状态的单例Bean才会存在线程安全问题
处理有状态单例Bean的线程安全问题有以下两种方法:
AOP,又叫面向切面编程,核心思想是将那些与业务无关,却为业务模块所共同调用的逻辑(例如事务处理、日志管理)封装起来,然后再动态插入到业务中的功能
使用AOP可以减少系统的重复代码,降低模块间的耦合度,并有利于扩展和维护,Spring AOP是基于动态代理的,它底层同时支持JDK和CGLIB的代理方式,并且会根据被代理类是否有接口自动选择最合适的代理方式
我们在开发中用到AOP的主要使用场景有:事务管理、日志、性能监视、安全检查
AOP思想的实现一般都是基于代理模式,在Java中一般采用JDK动态代理模式和CGLIB动态代理模式
因此在进行代理时,如果被代理类有接口,就用JDK;如果没有接口,就用CGLIB
使用Spring的AOP,底层会自动按照这个规则进行选择,开发者也无需关心
通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码段。
Spring切面可以应用五种类型的通知:
嗯,了解的,Spring支持编程式事务和声明式事务
第一种是编程式事务指的是在代码中使用try-catch捕获异常,然后配合事务的api来手动处理事务问题
这种方式的缺点是代码耦合,复用性低,优点是可以精确控制要增强的代码(不仅仅限于方法粒度)
第二种是声明式事务,声明式事务是AOP思想的一种应用,它的核心思想是将业务方法作为切点,
将事务处理方法作为增强,通过动态代理实现事务的管理,它的优点是降低代码耦合,提供复用
目前在企业中基本上都是采用声明式事务的。
事务传播行为是为了解决业务层方法之间互相调用的事务问题。
当事务方法被另一事务方法调用时,必须指定事务应该如何传播。
例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。
Spring支持7个种事务传播行为的:
必须事务:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务
必须新事务:创建一个新的事务,如果当前存在事务,则把当前事务挂起
强制事务:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
支持事务:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
不支持事务:以非事务方式运行,如果当前存在事务,则把当前事务挂起
强制无事务:以非事务方式运行,如果当前存在事务,则抛出异常
嵌套事务:如果当前存在事务,则创建一个当前事务的嵌套事务来运行;如果当前没有事务,则创建一个事务
嵌套事务是已存在事务的一个子事务,嵌套事务开始执行时,将取得一个保存点,
如果这个嵌套事务失败,将回滚到此保存点
嵌套事务是外部事务的一部分,只有外部事务结束后它才会被提交
Spring事务底层是基于数据库事务和AOP机制的
首先Spring会为使用了@Transactional注解的Bean代理对象,当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解。如果加了,那么则利用事务管理器创建一个数据库连接,并且禁止此连接的自动提交事务
然后执行当前方法,方法中会执行sql ,执行完当前方法后,如果没有出现异常就直接提交事务;如果出现了异常,并且这个异常是需要回滚的就会回滚事务,否则仍然提交事务。
Spring事务的隔离级别对应的就是数据库的隔离级别 ,Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为 需要新开一个事务,那么实际上就是重新建立一个数据库连接,在此新数据库连接上执⾏sql
整个IOC容器解决循环依赖,用到的几个重要成员:
singletonObjects:一级缓存,存放完全初始化好的 Bean 的集合,从这个集合中取出来的 Bean 可以立马返回 earlySingletonObjects:二级缓存,存放创建好但没有初始化属性的 Bean 的集合,它用来解决循环依赖 singletonFactories:三级缓存,存放单实例 Bean 工厂的集合 singletonsCurrentlyInCreation:存放正在被创建的 Bean 的集合
IOC 容器解决循环依赖的思路:
初始化 Bean 之前,将这个 BeanName 放入三级缓存
创建 Bean 将准备创建的 Bean 放入 singletonsCurrentlyInCreation (正在创建的 Bean)
createNewInstance 方法执行完后执行 addSingletonFactory,将这个实例化但没有属性赋值的 Bean 放入二级缓存,并从三级缓存中移除
属性赋值&自动注入时,引发关联创建
关联创建时,检查“正在被创建的 Bean”中是否有即将注入的 Bean。如果有,检查二级缓存中是否有当前创建好但没有赋值初始化的 Bean。如果没有,检查三级缓存中是否有!正在创建中的 Bean。至此一般会有,将这个 Bean 放入二级缓存,并从三级缓存中移除
之后 Bean 被成功注入,最后执行 addSingleton,将这个完全创建好的 Bean 放入一级缓存,从二级缓存和三级缓存移除,并记录已经创建了的单实例 Bean
总结以上步骤,核心主干主要就是五部分构成:
MVC 是 Model — View — Controler 的简称,它是一种架构模式,它分离了表现与交互。它被分为三个核心部件:模型、视图、控制器。
具体流程如下所示:
1、用户发送出请求到前端控制器DispatcherServlet。
2、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。
3、HandlerMapping找到具体的处理器(可查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
4、DispatcherServlet调用HandlerAdapter(处理器适配器)。
5、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。
6、Controller执行完成返回ModelAndView对象。
7、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。
8、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。
9、ViewReslover解析后返回具体View(视图)。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。
我们常用的Springmvc注解主要分类下面几大类:
1、用于声明Bean到Springmvc容器:@Controller、@RestController
区别在于后者还可以将返回的集合或对象转换为JSON直接返回
2、设置请求路径:@RequestMapping、@GetMapping、@PostMapping 、@PutMapping、@DeleteMapping
第一个是通用的,可以接收各种类型的请求;后面四个只能直接对应类型的请求
3、接收请求参数:
@RequestBody: 接收请求体中的json数据
@PathViriable:接收请求路径中的参数
@RequestHeader:接收请求头中的参数
@RequestParam:一般用于给参数设置默认值或者完成请求参数和controller方法参数的映射
SpringMVC的异常处理底层是通过AOP实现的,它的核心思想是将异常处理的代码和业务逻辑代码分离开来
使用它之后,我们在自己的业务代码中不需要在处理异常,有异常直接就上抛到框架中
框架就会将异常交给自定义的全局异常处理器中统一处理
自定义全局异常处理器,会用到两个注解: