Spring
什么是spring
spring是一个轻量级的容器框架,目的是简化企业应用开发,核心有两大功能IOC和AOP,通过IOC可以帮助我们管理项目中对象依赖,通过AOP可以帮助我们动态增强应用的功能性。spring对现有主流框架都有集成的支持,让我们我们很容易的在应用中使用其他框架的功能。
什么是IOC
控制反转,IOC其实就是对象的生命周期交给spring管理,spring本身是一个bean容器,帮助我们创建并且缓存对象引用,当我们需要某个对象的时候,由spring进行创建;过程中需要DI依赖注入,将我们需要的对象引用赋值给变量,降低组件之间耦合性;对象与对象之间复杂的引用关系也由spring帮我们管理;第三方功能需要的对象也由spring帮我们管理,我们只需要拿来即用就好。
什么是AOP
面向切面,切面指不同功能不同业务中相同的一部分逻辑,比如鉴权、日志、事务等模块,aop可以帮助我们轻易的在每个业务中进行这些通用功能的拓展,让我们只专注于实现业务功能即可。
当你需要在很多方法或接口上增加相同或相似的逻辑时,可以考虑使用AOP。
AOP有两种实现方式Spring的实现和AspectJ的实现,AspectJ是早期的aop实现,定义了一些标准的枚举,这些枚举spring也在使用,AspectJ的实现方式是使用静态代理增强,在代码编译期间将切面逻辑织入对象;spring是通过动态代理,JDK或者CGlib,在对象创建期间。
AOP中的概念
连接点(Join point) 被切入的执行中的方法
切点(pointcut) 定义的一组被切入的方法
通知(advice) 在连接点上执行的方法包括Around、Before、After、After returning、After throwing
切面(aspect) 被提取的公共模块 切面就是一个pointcut + 一组advice
目标对象(target) 包含连接点的对象
织入(Weaving) 通过代理等方法,在target的join point中执行advice
AOP实现的方式
spring实现的AOP,动态代理,jdk面向接口、cglib子类继承,对象创建期间、getBean
AspectJ实现的AOP,静态代理增强,代码编译期间将切面逻辑织入对象
什么是spingmvc
springmvc是spring提供的web应用框架,采用mvc模式modile-view-controller,springmvc本身是spring拓展出来的一个模块,spring对他提供很好的继承支持,通过@Controller和@RequestMapping我们可以很简单的创建一个web接口,核心dispatcherservlet拦截所有请求,根据uri找到对应的handler方法并执行,返回对应视图数据。
springmvc组件
- Handler Handler包装了具体的业务逻辑,一个RequestMapping、servlet可以看做一个handler
- HandlerMapping 用来查找Hanlder,每个请求都由对应的handler进行处理,reqeust找到HandlerExecutionChain,HandlerExecutionChain包含了一个Handler和一组Interceptors
- HandlerAdapter Handler适配器,用来适配项目中老的servlet候着controller,适配器模式,
- HandlerExceptionResolver 全局异常解析
- ViewResolver 视图解析器,根据handler返回的ModleAndView找到对应的页面进行渲染,可以是jsp、html或者直接输出
- MultipartResolver 处理上传文件的请求,普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File
springmvc运行原理
springmvc启动的时候会创建自己的上下文applicationcontext对象,将所有controller信息载入上下文,一个reqeustmapping就是一个contoller
- 客户端请求提交到DispatcherServlet
- 由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller
- DispatcherServlet将请求提交到Controller
- Controller调用业务逻辑处理后,返回ModelAndView
- DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
- 视图负责将结果显示到客户端
springmvc中拦截器和过滤器的区别
过滤器是Servlet定义的规范、由servlet容器进行实现,拦截器是由springmvc定义并且实现的
过滤器在servlet之前调用,拦截器存储在HandlerExecutionChain中,在DispatcherServlet中调用
过滤器拦截所有请求,拦截器只能拦截定义的handler
过滤器是责任链模式,拦截器是代理模式(静态代理的)
什么是springboot
本质上springboot还是spring,在spirng的基础上做了一些更方便我们搭建项目的功能,让我们在编码、配置、部署、监控等方面变的更简单了。
基于约定大于配置的自动装配,我们减少了很多配置项,starter帮助我们更简单的管理依赖,内置servlet容器,让我们更快的启动部署一个应用。
什么是springcloud
springcloud是spring提出的一套关于微服务架构的组件,包含网关、注册中心、配置中心、RPC、熔断降级、负载均衡、mq、分布式事务等组件
spring启动过程
spring的启动过程在AbstractApplicationContext.refresh()方法中执行
- prepareRefresh(); 准备上下文刷新 准备一些集合容器
- *创建Bean工厂ConfigurableListableBeanFactory
- 在使用之前准备一下BeanFactory内部的一些信息 环境参数等
- *postProcessBeanFactory 允许子类对BeanFactory做一些后置处理,模板方法
- *invokeBeanFactoryPostProcessors 执行Bean工厂后置处理器 会加载BeanDefinition
- *registerBeanPostProcessors 注册Bean后置处理器
- initMessageSource 初始化消息源
- initApplicationEventMulticaster 初始化应用事件广播器
- *onRefresh 正在refresh,模板方法,交由子类实现,ServletWebServerApplicationContext会在此处创建web服务器
- registerListeners 注册观察者们
- *finishBeanFactoryInitialization 根据BeanDefinition实例化所有Bean对象
- *finishRefresh 完成刷新 推送event消息,ServletWebServerApplicationContext重写此方法,增加了启动web服务器的逻辑
beandefinition作用
beandefinition是Bean定义信息,spring依靠beandefinition进行实例化,在spring容器启动执行invokeBeanFactoryPostProcessors方法时会扫描路径上的所有Bean对象,加载他们的BeanDefinition信息到BeanFactory中,后面会根据这些信息进行Bean的实例化
springboot启动过程
- 实例化部分 new SpringApplication
从spring.factories文件中加载一些ApplicationContextInitializer、ApplicationListener;根据是否引用了某些class推测应用类型;设置一下运行主类 - 启动部分
从spring.factories文件中加载SpringApplicationRunListener,这个监听器是springboot启动过程的一些事件推送
创建ConfigurableApplicationContext上下文 这里会根据推测的应用类型选择创建对应的子类实现
准备上下文 加载一些环境信息、启动参数信息等
执行上下文刷新启动spring
执行结束
spring中bean加载过程
实例化Bean 通过反射调用class的构造方法或者通过@Bean设置的实例化方法 此时Bean对象所有属性都是默认值
为Bean对象进行属性填充 这个阶段会遇到循环依赖问题 注入自定义对象
为Bean对象填充awera信息 注入上下文对象
执行BeanPostProcessor前置方法
执行init方法
执行BeanPostProcessor后置方法
将Bean放入BeanFactory
所有BeanPostProcessor都会在aware之后执行么
有一些BeanPostProcessor会提前到populateBean阶段执行
AOP、Autowaire、dubbo的Refrence
InstantiationAwareBeanPostProcessor
DestructionAwareBeanPostProcessor
MergedBeanDefinitionPostProcessor
spring解决循环依赖
spring循环依赖问题:spring中交由BeanFactory创建Bean对象,而创建Bean对象过程中有可能依赖了其他对象也需要创建,如果两个对象互相依赖那么创建过程就会进入一个死循环;单缓存无法解决,是因为对象没有创建完毕就放入缓存是不安全的;双缓存可以解决,但是对于aop无法处理,spring实现aop是在BeanPostProcessor阶段,如果强行处理就需要把aop提前到Bean实例化阶段,侵入了标准Bean的创建;三级缓存解决aop动态代理问题
解决方法:
A对象实例化之后创建一个ObjectFactory放入三级缓存,ObjectFactory是一段lambda表达式,执行了获取A对象最终引用的代码,过程中执行一些BeanPostProcessor处理包括AOP;
A对象属性填充阶段加载B对象,实例化B对象之后也放入三级缓存,进入B的属性填充,B的属性填充阶段需要加载A对象,从三级缓存取出对象引用放入二级缓存,并执行属性填充;
B属性填充等一些列代码执行完毕后,将B对象的从三级缓存取出放入一级缓存;
A对象拿到B的引用,进行属性填充完毕,从二级缓存出去放入一级缓存
springmvc父子容器
springmvc启动的时候,加载DispatcherServlet的时候会再创建一个ApplictionContext,并将Spring已经创建的向下文设置为父级,形成父子容器
父子容器的存在主要是为了划分边界,service层我们使用spring框架,对象功能由spring帮我们管理,而在web层可能存在多实现,比如springmvc struts2,父子容器可以帮助我们很容易的替换web层,只需要将spring-servlet.xml替换成Struts的配置文件struts.xml,service层都不用动。
控制扫描路径,来规避父子容器扫描的Bean对象
SpringBoot中使用的是同一个容器,将DispatcherServlet作为一个Bean对象交由Spring启动了,以前是交由tomcat启动。
springmvc常用注解
@Controller 标记是一个contoller
@RequestMapping 标记资源路径
@RequestParam 标记参数名称,必填
@RequestAttribute 标记属性名称,必填
@RequestBody 标记参数是Json体
@ResponseBody 标记返回时Json体
@RestController 标记controller内部全是json方法
@WebFilter 过滤器
@CrossOrigin 标记请求与
spring加载bean的几种方式
@Component
@Configuration
<bean/>
@Bean
<import/>
@Import
ImportSelector接口
ImportBeanDefinitionRegistrar接口
springboot自动装配原理
springboot自动为我们创建一些Bean对象,基于约定大于配置的原则,按照默认值去创建。
@SpringBootApplication修饰了启动类,@SpringBootApplication包含@EnableAutoConfiguration
@EnableAutoConfiguration包含@Import(AutoConfigurationImportSelector.class)
所有需要自动装配的类是依靠AutoConfigurationImportSelector,从spring.factories文件中加载所有配置为EnableAutoConfiguration的类
装配时机是在启动时,context.refresh()中,执行BeanFacotoryPostProcessor阶段,通过ConfigurationClassPostProcessor加载
springboot内嵌tomcat原理
- SpringApplication在实例化阶段会根据路径上引用的一些class推测当前应用的类型,如果存在Servlet或者ConfigurableWebApplicationContext会被推测为是一个web服务器;
- SpringApplication.run阶段创建上下文时,会根据上面推测的应用类型创建具体的上下文,这里会创建AnnotationConfigServletWebServerApplicationContext
- 这个context在refresh阶段的onRefresh中会创建webServer,默认是tomcat,加载的ServletWebServerFactory默认是tomcat的,根据是否引用了内置tomcat其他的还有jetty、Undertow
TomcatServletWebServerFactory是通过ServletWebServerFactoryAutoConfiguration自动装配的,条件是路径上有Tomcat、Servlet - 在refresh阶段的finishRefresh中会启动webServer
spring和springboot中提供了哪些扩展点
BeanFactoryPostProcessor Bean工厂后置处理器 可以通过ApplicationContextInitializer加载,或者只要在refresh方法之前通过listener加载
BeanPostProcessor Bean后置处理器
ApplicationRunListener 广播springboot启动事件
ApplicationListener 广播spring启动事件
ApplicationContextInitializer在什么时机执行
SpringApplication.run.prepareContext;
springboot的starter原理
管理依赖,省去了以前引入一大堆依赖,还要梳理版本,弄不好就会冲突,
自动装配组件,省去了一大堆配置
统一配置文件,将所有配置统一到spring的配置文件中,便于管理
手写starter
一般分为两个包 一个starter包负责引入依赖,一个autoconfiguration包负责自动装配组件
starter包不需要任何代码,只引入依赖
autoconfiguration包定义配置类,定义组件Bean,自动装配
配置文件类:使用@ConfigurationProperties(prefix = "demo")修饰的Java类,属性名就是配置名
自动配置类:@EnableConfigurationProperties(DemoProperties.class)修饰的Java类,会自动读取spring配置文件中对应配置信息
定义组件:完成核心业务,并用@Bean等方式定义为一个Bean对象
自动装配:在META-INF目录下添加spring.factories,并配置org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx.DemoAutoConfiguration
BeanFactory和ApplicationContext
BeanFactory是bean工厂,ApplicationContext是应用上下文
ApplicationContext实现了BeanFactory通过门面模式支持了BeanFactory中的方法,内部引用了一个DefaultListabledBeanFactory
ApplicationContext还负责整个应用的生命周期,BeanFactory只管Bean对象
BeanFactory和FactoryBean
BeanFactory是bean工厂,简单工厂模式;
FactoryBean是一个Bean,工厂方法模式,getBean方法中对其特殊处理,如果是FactoryBean实现类并且非急切加载的话,会后置处理,当获取FactoryBean时会自动调用getOBject方法,如果需要FactoryBean对象,需要getBean("&"+name),用于懒加载对象,或加载复杂对象实现,比如
spring中的设计模式
Listener 观察者模式
HandlerAdapter 适配器模式
AOP 代理模式
ApplicationContext 门面模式
AbstractApplicationContext.refresh() 模板方法
BeanFactory 简单工厂
FactoryBean和ObjectBean 工厂方法
Waraper 装饰模式
springcloud有哪些组件
网关 配置中心 注册中心 服务调用RPC 负载均衡 熔断降级 限流 路由 分布式消息 分布式事务
spring中的事务
基于AOP + Threadlocal实现
spring中的事务传播
required 如果存在就加入,如果没有就创建
supports 如果存在就加入,如果没有就非事务执行
not_supports 如果存在就挂起,非事务执行
required_new 如果存在就挂起,开启一个新事物执行
mandatory 如果不存在事务,抛异常
never 如果存在事务,抛异常
nested 嵌套事物,子事务不影响父,父回滚,子回滚
spring中事务失效的场景
私有方法、final方法、多线程调用、非spring管理对象、直接调用、吞异常、数据库不支持事务、
@Resouce和@Autowire的区别
resouce getBeanByName J2ee注解
autowire getBeanByType spring注解 配合@Qualifier根据name加载;可以装配多个实例到集合或者map