AOP和IOC的理解
IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。不过, IoC 并非 Spring 特有,在其他语言中也有应用。
为什么叫控制反转?
控制 :指的是对象创建(实例化、管理)的权力
反转 :控制权交给外部环境(Spring 框架、IoC 容器)
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
bean 的生命周期和作用域
singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
application/global-session (仅 Web 应用可用): 每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
单例 Bean 存在线程安全问题吗?
单例 Bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候是存在资源竞争的。
常见的有两种解决办法:
在 Bean 中尽量避免定义可变的成员变量。
在类中定义一个 ThreadLocal 成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。
不过,大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
IOC容器初始化过程,循环依赖问题如何解决?
SpringIOC解决循环依赖的思路就是依靠缓存,同时还得引出个概念即早期暴露引用。我们知道在IOC容器里bean的初始化的过程分为三个步骤:创建实例、属性注入实例、回调实例实现的接口方法。解决思路就在这:当我们创建实例与属性注入实例这俩个步骤之间的时候,我们引入缓存,将这些已经创建好但是并没有注入属性的实例放到缓存里,而这些放在缓存里但是没有被注入属性的实例对象,就是解决循环依赖的方法,打个比方:A对象的创建需要引用到B对象,而B对象的创建也需要A对象,而此时当B对象创建的时候直接从缓存里引用A对象(虽然不是完全体A对象,毕竟没有赋值处理),当B对象完成创建以后再被A对象引用进去,则A对象也完成了创建。
这就是SpringIOC解决bean直接循环依赖的思路当然有一个小问题,IOC能够解决的只能是属性之间的循环依赖,如果有bean之间的构造器相互依赖则就解决不了只能报错了。
在 Spring 中, IoC 容器是 Spring 用来实现 IoC 的载体, IoC 容器实际上就是个 Map(key,value),Map 中存放的是各种对象
BeanFactory和FactoryBean的区别?
BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
BeanFactory和FactoryBean都可以用来创建对象,只不过创建的流程和方式不同
当使用BeanFactory的时候,必须要严格的遵守bean的生命周期,经过一系列繁杂的步骤之后可以创建出单例对象,是流水线式的创建过程,
而FactoryBean是用户可以自定义bean对象的创建流程,不需要按照bean的生命周期来创建
Spring Boot 的自动配置是如何实现的?
我们知道 @SpringBootApplication看作是 @Configuration、@EnableAutoConfiguration、@ComponentScan 注解的集合。
@EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
@ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
@Configuration:允许在上下文中注册额外的 bean 或导入其他配置类
@EnableAutoConfiguration 注解通过 Spring 提供的 @Import 注解导入了AutoConfigurationImportSelector类(@Import 注解可以导入配置类或者 Bean 到当前类中)。
AutoConfigurationImportSelector类中getCandidateConfigurations方法会将所有自动配置类的信息以 List 的形式返回。这些配置信息会被 Spring 容器作 bean 来管理
自动配置信息有了,那么自动配置还差什么呢?
@Conditional 注解。@ConditionalOnClass(指定的类必须存在于类路径下),@ConditionalOnBean(容器中是否有指定的 Bean)等等都是对@Conditional注解的扩展
BeanFactory与ApplicationContext的区别
BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext 来说会占用更少的内存,程序启动速度更快。
ApplicationContext :容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。
Spring 中用到的设计模式。
控制反转(IoC)和依赖注入(DI),IoC 是一个原则,而不是一个模式,Spring IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。DI(Dependecy Inject,依赖注入)是实现控制反转的一种设计模式,依赖注入就是将实例变量传入到一个对象中去
工厂设计模式
Spring 使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。
单例设计模式
Spring 中 bean 的默认作用域就是 singleton(单例)的。
使用单例模式的好处 :
对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
代理设计模式
Spring AOP 就是基于动态代理的
SpringMvc工作流程。
客户端(浏览器)发送请求, DispatcherServlet拦截请求。
DispatcherServlet 根据请求信息调用 HandlerMapping 。HandlerMapping 根据 uri 去匹配查找能处理的 Handler(也就是我们平常说的 Controller 控制器) ,并会将请求涉及到的拦截器和 Handler 一起封装。
DispatcherServlet 调用 HandlerAdapter适配执行 Handler 。
Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给DispatcherServlet,ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。Model 是返回的数据对象,View 是个逻辑上的 View。
ViewResolver 会根据逻辑 View 查找实际的 View。
DispaterServlet 把返回的 Model 传给 View(视图渲染)。
把 View 返回给请求者(浏览器)
Spring 和 SpringBoot 的区别?
Spring 包含了多个功能模块(上面刚刚提到过),其中最重要的是 Spring-Core(主要提供 IoC 依赖注入功能的支持) 模块, Spring 中的其他模块(比如 Spring MVC)的功能实现基本都需要依赖于该模块。
使用 Spring 进行开发各种配置过于麻烦比如开启某些 Spring 特性时,需要用 XML 或 Java 进行显式配置。于是,Spring Boot 诞生了!
Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot 旨在简化 Spring 开发(减少配置文件,开箱即用!)
Mybatis 的缓存
MyBatis包含了一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
(1)、默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
(2)、二级缓存需要手动开启和配置,它是基于namespace级别的缓存。
Mybatis 的执行流程
1.首先mybatis中xml解析是通过SqlSessionFactoryBuilder.build()方法。
-
初始化mybatis(解析xml文件构建成Configuration对象)并初始化SqlSessionFactory对象
-
通过SqlSesssionFactory.openSession()方法打开一个SqlSession对象
-
通过SqlSession.getMapper()根据传入的Mapper对象类型动态代理并返回一个动态代理后的Mapper对象
-
Executor执行Query/queryFromDatabase,在前面经过参数名封装和缓存查询之后(缓存为空),会调用queryFromDatabase方法去数据库当中查