Spring的IOC容器
控制反转即loC(lnversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
Spring IOC负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
Spring IOC控制反转的作用
- 第一管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序猿来维护的话,那是相当头疼的
- 第二解精,由容器去维护具体的对象
- 第三托管了类的产生过程,比如我们需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需去关心类是如何完成代理的。
Spring用到哪些设计模式
- 第一个工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
- .第二个单例模式:Bean默认为单例模式。
- 第三个代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
- 第四个模板方法:用来解决代码重复的问题。如:RestTemplate、JmsTemplate、JpaTemplate
- 第五个观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现-ApplicationListener。
Spring支持的bean作用域
spring框架支持以下五种bean的作用域:
- 第一种singleton:bean在每个Spring ioc容器中只有一个实例。
- 第二种prototype:一个bean的定义可以有多个实例。
- 第三种request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- 第四种session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- 第五种global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
注意:缺省的Spring bean的作用域是Singleton。使用prototype作用域需要慎重的思考,因为频繁创建和销毁bean会带来很大的性能开销。
Spring框架中单例bean是否线程安全的
不是,Spring框架中的单例bean不是线程安全的。
spring 中的bean默认是单例模式,spring框架并没有对单例bean进行多线程的封装处理。
实际上大部分时候 spring bean无状态的(比如dao类),所有某种程度上来说bean也是安全的,但如果bean有状态的话(比如view model对象),那就要开发者自己去保证线程安全了,最简单的就是改变bean的作用域,把"singleton"变更为"prototype",这样请求bean相当于new Bean()了,所以就可以保证线程安全了。
- 有状态就是有数据存储功能。
- 无状态就是不会保存数据。
Spring处理线程并发问题
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
@Component \ @Controller @Service @Repository的区别
- @Component: 这将java类标记为bean。它是任何Spring管理组件的通用构造型。spring的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
- @Controller: 这将一个类标记为Spring Web MVC控制器。标有它的Bean会自动导入到loc容器中。
- @Service: 此注解是组件注解的特化。它不会对@Component注解提供任何其他行为。可以在服务层类中使用@Service而不是@Component,因为它以更好的方式指定了意图。
- @Repository: 这个注解是具有类似用途和功能的@Component注解的特化。它为DAO提供了额外的好处。它将DAO导入loC容器,并使未经检查的异常有资格转换为Spring DataAccessException。
@Autowired和@Resource的异同点
相同点方面如下:
@Resource的作用相当于@Autowired,均可标注在字段或属性的setter方法上。
不同点方面如下:
第一个提供方:@Autowired是由org.springframework.beans.factory.annotation.Autowired提供,换句话说就是由Spring提供;@Resource是由javax.annotation.Resource提供,即J2EE提供,需要JDK1.6及以上。
第二个注入方式:@Autowired只按照byType注入;@Resource默认按byName自动注入,也提供按照byType注入;
第三个属性:@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。如果我们想使用按名称装配,可以结合@Qualifier注解一起使用。
@Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。需要注意的是,@Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时,@Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
Spring事务的传播行为
spring事务的传播行为说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。
- 第一个PROPAGATION_REQUIRED: 如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
- 第二个PROPAGATION_SUPPORTS: 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。
- 第三个PROPAGATION_MANDATORY: 支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
- 第四个PROPAGATION_REQUIRES_NEW: 创建新事务,无论当前存不存在事务,都创建新事务。
- 第五个PROPAGATION_NOT_SUPPORTED: 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- 第六个PROPAGATION_NEVER: 以非事务方式执行,如果当前存在事务,则抛出异常。
- 第七个PROPAGATION_NESTED: 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
Spring的事务隔离
spring 有五大隔离级别,默认值为ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:
-
第一个ISOLATION_DEFAULT: 用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
-
第二个ISOLATION_READ_UNCOMMITTED: 未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
-
第三个ISOLATION_READ_COMMITTED: 提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server的默认级别;
-
第四个ISOLATION_REPEATABLE_READ: 可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL的默认级别;
-
第五个ISOLATION_SERIALIZABLE: 序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
Spring MVC 的工作流程
Spring Profiles
Spring Profiles允许用户根据配置文件(dev,test,prod等)来注册bean。因此,当应用程序在开发中运行时,只有某些bean可以加载,而在PRODUCTION中,某些其他bean可以加载。假设我们的要求是Swagger文档仅适用于QA环境,并且禁用所有其他文档。这可以使用配置文件来完成。Spring Boot使得使用配置文件非常简单。
Springboot 解决跨域
跨域可以在前端通过JSONP来解决,但是JSONP只可以发送GET请求,无法发送其他类型的请求,在RESTful风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过(CORS,Cross-origin resource sharing)来解决跨域问题。这种解决方案并非 Spring Boot特有的,在传统的SSM框架中,就可以通过CORS来解决跨域问题,只不过之前我们是在XML文件中配置CORS,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
评论区