Spring面试点汇总

我们会在这里介绍我所涉及到的Spring相关的面试点内容,本篇内容持续更新

我们会介绍下述Spring的相关面试点:

  • Spring refresh
  • Spring bean
  • Spring transaction
  • Spring webmvc
  • Spring annotation
  • Spring auto
  • Spring pattern

Spring refresh

ApplicationContent 是 Spring 中的核心容器,而refresh方法是对Application的初始化,我们下面来学习一下

整体流程

我们首先给出整体流程以及相关操作:

/*refresh源码展示*/

// refresh只是一个框架,里面一共包含了十二个方法,我们称为十二个步骤

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) { /* 第一阶段:整体准备 */ // 1.准备刷新上下文
prepareRefresh(); /* 第二阶段:BeanFactory准备 */ // 2.创建并初始化beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3.装配beanFactory
prepareBeanFactory(beanFactory); try {
// 4.在当前上下文环境下对beanFactory进行后置处理操作(子类扩展BeanFactory)
postProcessBeanFactory(beanFactory); // 5.激活各种BeanFactory的处理器(后处理器扩展BeanFactory)
invokeBeanFactoryPostProcessors(beanFactory); // 6.注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor(为Bean准备后处理器)
registerBeanPostProcessors(beanFactory); /* 第三阶段:Applicationcontent准备 */ // 7.为上下文环境初始化MessageSource,即不同语言的消息体,国际化处理操作(为ApplicationContent提供国际化功能)
initMessageSource(); // 8.初始化上下文事件广播器(为ApplicationContent提供事务发布器)
initApplicationEventMulticaster(); // 9.此处是留给子类来初始化其他的bean(留给子类扩展)
onRefresh(); // 10.在所有bean中查找listener bean,然后注册到广播器中(为ApplicationContent提供监听器)
registerListeners(); /* 11 是单独一个阶段:创造单例对象 */ // 11.初始化单例Bean,执行Bean后处理器扩展(第6步创建的Bean后处理器)
finishBeanFactoryInitialization(beanFactory); // 12.完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
} //销毁已经创建的单例bean
destroyBeans(); // Reset 'active' flag.
cancelRefresh(ex); // 抛异常
throw ex;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

PrepareRefresh

该阶段展示图:

该阶段任务:

  • 创建和准备Environment环境
  • 对上下文环境的初始化准备工作,如对系统环境或者系统属性变量的准备验证过程,这个变量的设置可能会影响着系统的正确性

Environment环境变量解释:

  • SystemProperties:系统资源,Java默认编码等信息
  • SystemEnvironment:系统环境配置,JAVA_HOME等信息
  • 自定义PropertySource:配置文件,application.yaml等信息

总体作用:

  • 对当前上下文进行状态的设置.
  • 初始化 context environment 中占位符.
  • 当前环境的一些校验等.
  • 为@Value等值注入时提供键值

ObtainFreshBeanFactory

该阶段展示图:

该阶段任务:

  • 创建或获取BeanFactory

BeanDefinitionMap解释:

  • BeanFactory负责bean的创建,依赖注入和初始化
  • BeanDefinition作为bean的设计蓝图,规定了bean的特征,如单例多例,依赖关系,初始摧毁方法等
  • BeanDefinition的来源具有多样化,包括xml文件获取,配置类获取,组件扫描获取,编程添加等

总体作用:

  • 首先是对当前容器的判断,如果已存在beanFactory则将其移除该beanFactory创建的bean和移除自身
  • 接着是调用#createBeanFactory()方法来创建beanFactory实例
  • 给beanfactory设置序列化id
  • 加载beanDefinition
  • 将创建好的 bean 工厂的引用交给的 context 来管理

PrepareBeanFactory

该阶段展示图:

该阶段任务:

  • 完善BeanFactory,初始化

图中参数解释:

  • StandardBeanExpressionResolver 来解析 SPEL
  • ResourceEditorRegistrar会注释类型解释器,并应用ApplicationContext提供的Environment完成${}解析
  • 特殊bean是指beanFactory以及Applicationcontext,通过registerResolvableDependency来注册他们
  • ApplicationContextAwareProcessor用于解析Aware接口

总体作用:

  • 给beanFactory设置各种各样的功能

PostProcessBeanFactory

该阶段任务:

  • 空实现,留给子类进行扩展
  • 对应模板方法设计模式

总体作用:

  • 一般Web环境的ApplicationContext都要利用它注册新的Scope,完善Web下的BeanFactory

InvokeBeanFactoryPostProcessors

该阶段展示图:

该阶段任务:

  • 激活beanFactory的各种处理器

处理器解析:

  • beanFactory后处理器:充当beanFactory扩展点,可以用来补充和修改BeanDefinition
  • ConfigurationClassPostProcessor:解析@Configuration,@Bean,@Import,@propertySource
  • PropertySourcesPlaceHolderConfigurer:替换BeanDefinition中的${}

RegisterBeanPostProcessor

该阶段展示图:

该阶段任务:

  • 注册所有的BeanPostProcessor
  • 生产Bean后处理器,作为bean扩展点,可以工作在bean的实例化,依赖注入,初始化阶段

后处理器介绍:

  • AutowiredAnnotationBeanPostProcessor:解析@Autowired,@Value注解

  • CommonAnnotationBeanPostProcessor:解析@Resource,@PostConstrut,@preDestroy

  • AnnotationAwareAspectAutoProxyCreator:为符合切点目标bean自动创建代理

InitMessageSource

该阶段展示图:

该阶段任务:

  • 为上下文环境初始化MessageSource,即不同语言的消息体,国际化处理操作,

  • 如果包含messageSource的bean进行相应的处理,没有的使用默认的MessageSource来进行消息的处理

InitApplicationEventMulticaster

该阶段展示图:

该阶段任务:

  • 为当前上下文来初始化一个事件广播器,用于发布事件给监听器
  • 同样优先从容器中查找名为ApplicationEventMulticaster的bean作为事件广播器,若不存在,采用默认事件广播器
  • 采用ApplicationContext.publishEvent(事件对象)来发布事件

OnRefresh

该阶段任务:

  • 空实现,留给子类进行扩展
  • 对应模板方法设计模式

总体作用:

  • SpringBoot中的子类可以在这里准备WebServer,即内嵌Web容器

RegisterListeners

该阶段展示图:

该阶段任务:

  • 为当前上下文注册一个事件监听器
  • 一部分监听器是事先编程添加,另一部分监听器来自容器的bean,还有一部分来自@EventListener的解析
  • 实现ApplicationListener接口,重写其中onApplicationEvent(E e)方法即可

FinishBeanFactoryInitialization

该阶段展示图:

该阶段任务:

  • 初始化剩下的单例Bean(非延迟加载的)

详细解释:

  • ConversionService是一套转换机制,作为对PropertyEditor的补充
  • 内嵌值解析器用来解析@Value中的${},借用的是Environment的功能
  • 单例池用来缓存所有的单例对象,对象的创建都分为三个阶段,每一阶段都有不同的bean后处理器参与进来,扩展功能

FinishRefresh

该阶段展示图:

该阶段任务:

  • 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人

详细解释:

  • 用来控制容器中需要生命周期管理的bean
  • 如果容器中有名为lifecycleProcessor的bean,就直接采用,否则生成默认的生命周期处理器
  • 调用context的start方法,即可触发所有实现LifeCycle接口的bean的start
  • 调用context的stop方法,即可触发所有实现LifeCycle接口的bean的stop

Spring bean

下面我们来具体介绍一下Spring bean的生命周期

整体流程

我们首先给出Springbean生命周期的整体阶段展示:

/*生命周期*/

来自AbstractBeanFactory类的doGetBean方法

/* 第一阶段 */

处理名称,检查缓存

/* 第二阶段 */

检查父工厂

/* 第三阶段 */

检查DependsOn

/* 第四阶段 */

按scope创建bean
- 创建singleton
- 创建prototype
- 创建其他scope /* 第五阶段(重点) */ 创建bean实例:@Autowired,唯一带参构造,默认构造 依赖注入:@Autowired,@Value,@Resource,ByName,ByType,精准指定 初始化:Aware接口处理,@PostConstruct,InitializingBean,InitMethod,创建AOP代理 登记可销毁bean /* 第六阶段 */ 类型转换 /* 第七阶段 */ 销毁bean

第一阶段

第一阶段作用:

  • 将别名解析为实际名称,再进行后续处理

第一阶段注意点:

  • 若要FactoryBean本体,需要采用&名称获取
  • singletonFactories为三级缓存,放单例工厂
  • earlySingletonObjects为二级缓存,放单例工程的产品,可称为提前单例对象
  • singletonObjects为一级缓存,放单例成品对象

第二阶段

第二阶段作用:

  • 采用父容器查找规则

第二阶段注意点:

  • 该情况仅出现SSM框架(WebMvc配置类)

  • 父子容器的bean名称可以重复

  • 优先查找子容器的bean,找到了直接返回,若未找到到父容器中寻找

第三阶段

第三阶段作用:

  • 采用dependsOn初始化

第三阶段注意点:

  • dependsOn用在非显式依赖的bean的创建顺序控制
  • a和b属于并列关系/非显式依赖,a dependsOn b就是b先创建后a再创建

第四阶段

第四阶段作用:

  • 根据Scope创建bean

第四阶段注意点:

  • scope理解为从xxx范围中寻找bean
  • singleton scope 表示从单例池范围内获取bean,如果没有,则创建并放入单例池
  • prototype scope 表示从不缓存bean,每次创建新对象
  • request scope 表示从request对象范围内获取bean,如果没有就创建并放入request
  • 所有的创建bean或获取bean都是直接或间接采用了getBean方法(singleton scope采用refresh方法间接调用getBean方法)

第五阶段

第五阶段作用:

  • 创建bean

第五阶段主要分为四个阶段:

  • 创建bean实例
  • 依赖注入
  • 初始化
  • 注册可销毁bean

创建bean实例

我们介绍创建bean实例的两种方法(还有其他方法,下面不做介绍):

要点 总结
AutowiredAnnotationBeanPostProcessor选择构造 - 优先选择带@Autowired注解的构造
- 若带有唯一的带参构造,也会入选
采用默认构造 如果上述后处理器和BeanDefiniation都没有找到构造,就采用默认构造

依赖注入

我们介绍依赖注入的五种方法:

要点 总结
AutowiredAnnotationBeanPostProcessor(注解匹配) 识别@Autowired和@Value标注的成员
封装为InjectionMetadata进行依赖注入
CommonAnnotationBeanPostProcessor(注解匹配) 识别@Resource注解的成员
封装为InjectionMetadata进行依赖注入
AUTOWIRE_BY_NAME(根据名称匹配) 根据成员名字找bean对象,修改mbd的propertyValues
不考虑简单类型的成员
AUTOWIRE_BY_TYPE(根据类型匹配) 根据成员类型执行resolveDependency找到依赖注入的值
修改mbd的propertyValues
applyPropertyValues(即xml中<proprty name ref>) 根据mbd的propertyValues进行依赖注入

我们需要了解上面五种依赖注入的优先级:

  • applyPropertyvalues > AUTOWIRE > 注解匹配

初始化

我们来介绍初始化的相关操作:

  1. Aware接口操作
Aware接口 总结
内置Aware接口的装配 包括BeanNameAware,BeanFactoryAware等
扩展Aware接口的装配 由ApplicationContextAwareProcessor解析
执行时机在postProcessBeforeInitialization
  1. 初始化操作
初始化 总结
@PostConstruct 由CommonContextAwareProcessor解析
执行时机在postProcessBeforeInitialization
InitializingBean 通过接口回调执行初始化
InitMethod(即<bean init-method>或@Bean(initMethod)) 根据BeanDefinition得到的初始化方法执行初始化
  1. AOP代理
AOP代理 总结
创建AOP代理 由AnnotationAwareAspectJAutoProxyCreator创建
执行时机在postProcessAfterInitialization
  1. 注册可销毁bean

首先我们需要得知可销毁bean的判定条件:

  • 如果实现了DisposableBean或AutoCloseable接口,则为可销毁bean
  • 如果自定义了destroymethod,则为可销毁bean
  • 如果采用了@Bean没有指定destroyMethod,则采用自动推断方式获取销毁方法名(close,shutdown)
  • 如果有@PreDestroy标注的方法

然后我们需要知道可销毁bean的存储位置:

  • singleton scope可销毁bean会储存在beanFactory的成员当中
  • 自定义scope 的可销毁bean会存储在对应的域对象当中
  • prototype scope不会存储,需要自己找到此对象销毁

最后我们需要注意一点:

  • 存储时都会封装为DisposableBeanAdapter类型对销毁方法的调用进行适配

第六阶段

第六阶段作用:

  • 进行类型转换

第六阶段注意点:

  • 如果getBean的requiredType参数与实际得到的对象类型不同,会尝试进行类型转换

第七阶段

第七阶段作用:

  • 销毁可销毁bean

第七阶段注意点:

  • singleton bean的销毁在ApplicationContext容器的close方法时,此时会找到所有DisposableBean的名字,逐一销毁
  • 自定义scope bean的销毁在作用域对象生命周期结束
  • prototype bean的销毁需要手动调用AutowireCapableBeanFatory的destroyBean方法销毁

同时我们还需要注意同一bean不同形态想回方法的调用次序:

  • 优先后处理器销毁,即@PreDestroy
  • 其次DisposableBean接口销毁
  • 最后destoryMethod销毁(包括自定义名称,推断名称,AutoCloseable接口多选一)

Spring transaction

下面我们来介绍Spring 事务失效的多种情况以及解决方法

Spring事务失效及解决方法

下面我们给出Spring事务失效的八种案例及解决方法:

/* 1.事务内部手动抛出异常未回滚 */

// 问题原因
Spring默认只会回滚非检查异常 // 解决方法
配置rollbackFor属性即可(rollbackFor = Exception.class) // 解决方法示例 @Transactional(rollbackFor = Exception.class)
public void transfer(...){} /* 2.事务内部手动trycatch捕捉异常导致无法检测到异常,无法进行回滚 */ // 问题原因
事务通知只有捕捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标处理掉异常,自然不会回滚 // 解决方法
1. 将异常原样抛出
2. 手动设置TransactionStatus.setRollbackonly(),表示修改事务状态将其修改为进行回滚操作 // 解决方法示例 @Transactional(rollbackFor = Exception.class)
public void transfer(...){
try{
...
} catch (Exception e){
e.printStackTrace(); // 下面处理方法选择其一即可 // 1.直接原样抛出(可以包装成正在运行异常抛出)
throw new RuntimeException(e); // 2.修改该事务处理方式
TransactionInterceptor.currentTransactionStatus.setRollbackOnly();
}
} /* 3.aop切面顺序导致事务不能正确回滚*/ // 问题原因
事务切面优先级最低,如果自定义的切面优先级相同,且自定义切面在内层,只是可能就会吞掉异常(当切面存在trycatch方法时) // 解决方法
1. 同情况2
2. 修改切面优先级(不推荐) /* 4.非public方法导致事务失效 */ // 问题原因
Spring未方法创建代理,添加事务通知的前提条件是该方法为public // 解决方法
1. 修改为public方法
2. 修改配置类 // 解决方法 public TransactionAttributeSource transactionAttributeSource(){
// 设置是否当public才可以设置事务
return new AnnotationTransactionAttributeSource(false);
} /* 5.父子容器导致事务失效 */ // 问题原因
子容器扫描范围过大,把未加事务配置的service扫描进来 // 解决方法
1. 修改扫描范围,精确到具体文件夹
2. 不采用父子容器,直接放在同一容器下 /* 6. 调用本类方法导致传播失效 */ // 问题原因
本类方法调用不经过代理,因此无法增强 // 解决方法
1. 依赖注入自己(代理)来调用
2. 通过AopContext拿到代理对象,来调用
3. 通过CTW,LTW实现功能增强 /* 7.@Transactional没有保证原子行为 */ // 问题原因
事物的原子性仅覆盖insert,delete,select...for update语句 // 解决方法
数据库:将select语句修改为select...for update语句 /* 8.@Transactional方法导致的synchronized失效 */ // 问题原因
synchronized保证的仅仅是目标方法的原子性,commit方法并未包括其中,可能方法执行完毕,但并未执行commit就转交权限 // 解决方法
1. 数据库:将select语句修改为select...for update语句
2. Java:将synchronized范围扩大到代理方法调用

Spring webmvc

下面我们来介绍Spring WebMvc的执行流程

初始化阶段

首先我们给出Spring WebMvc的第一个阶段操作:

/* 初始化阶段操作 */

1. 在Web容器第一次用到DispatcherServlet的时候,会创建其对象并执行方法

2. init方法内会创建spring Web容器,并调用容器refresh方法

3. refresh过程中会创建并初始化SpringMVC中的重要组件

4. 容器初始化后,会将上一步初始化好的重要组件,赋值给DispatcherServlet的成员变量,留待后用

/* 重要组件展示 */

SpringWeb容器:

1. HandlerMapping:请求映射

2. HandlerAdapter:调用方法响应请求

3. HandlerExceptionResolver:用于异常处理

4. ViewResolver:字符串解析为引用对象

5. MultipartResolver:处理表单数据(非必要)

DispatcherServlet容器:

包含上述组件的数组类型,比如HandlerMappings,HandlerAdapters等用于存储SpringWeb容器的各项组件

匹配阶段

第二阶段是匹配阶段:

/* 匹配阶段 */

1. 用户发送的请求统一到达前端控制器DispatcherServlet

2. DispatcherServlet遍历所有HandlerMapping,找到与路径匹配的处理器

- HandlerMapping有多个,每个HandlerMapping会返回不同的处理器对象,谁先匹配,返回谁的处理器
(其中识别@RequestMapping优先级最高) - 对应@RequestMapping的处理器是HandlerMethod,它包含了控制器对象和控制器方法信息 - 其中路径与处理器的映射关系在Handlermapping初始化时就会建好 3. 将HandlerMethod连同匹配到的拦截器,生成调用链对象HandlerExecutionChain返回 4. 遍历HandlerAdapter处理器适配器,找到能够处理HandlerMethod的适配器对象,开始调用

执行阶段

最后一个阶段是执行阶段:

/* 执行阶段 */

1. 执行拦截器preHandle

2. 由HandlerAdapter调用HandlerMethod
- 调用前处理不同类型的参数
- 调用后处理不同类型的返回值 3-1. 若第二步没有异常:
- 返回ModeAndView
- 执行拦截器postHandler方法
- 解析视图,得到View对象,进行视图渲染 3-2. 若第二步出现异常:
- 进入HandlerExceptionResolver异常处理流程 4. 最后执行拦截器的HandlerExceptionResolver 注意点:
- 如果控制器方法标注了@ResponseBody注解,则第二步就会生成json数据,并标记ModelAndview已处理,不需要执行3-1最后一步 /* 问题补充 */ 拦截器分为三个部分:
- preHandler:方法开始前拦截器,若通过就执行
- postHandler:方法开始时拦截器,中间操作
- afterHandler:方法结束后拦截器,必定执行 HandlerMethod: 对应@RequestMapping的处理器是HandlerMethod,它包含了控制器对象和控制器方法信息,用于处理请求

Spring annotation

下面我们来介绍我们SSM框架中的常用注解

Spring常用注解

下面我们来介绍Spring的常用注解类型:

/* 事务 */

@EnableTransactionManagement:开始事务支持注解

@Transactional:开启方法事务

/* 核心 */

@order:定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序(数字越小,优先级越高)

/* 切面 */

@EnableAspectJAutoProxy:Spring AOP开启的标志,在启动类标记此注解,即可加载对应的切面类逻辑

/* 组件扫描和配置类 */

@Component:用于组件扫描类修饰

@Controller:用于服务层组件扫描类修饰

@Service:用于业务层组件扫描类修饰

@Repository:用于数据层组件扫描类修饰

@ComponentScan:用于启动类扫描指定包中使用组件扫描修饰的类

@Conditional:条件装配,首先需要判断是否符合条件,若符合再进行装配

@Configuration:配置类修饰

@Bean:设置为Bean

@Import:导入指定配置类

@Lazy:标记在类上,表示延迟实例初始化

@PropertySource:读取外部property文件

/* 依赖注入 */

@Autowired:自动装配

@Qualifer:自动装配出现相同类型的bean时,采用@Qualifer来采用名字查找对应bean

@Value:用@Value表示赋值,可以赋值property中的数据

Spring WebMvc常用注解

下面我们来介绍Spring WebMvc的常用注解:

/* mapping */

@Mapping:用于标识数据层,用于代替数据层映射

@RequestMapping:设置映射URL,可以作用与类或方法上

@GetMapping:请求方式为Get的@RequestMapping

@PostMapping:请求方式为Post的@RequestMapping

@PutMapping:请求方式为Put的@RequestMapping

@DeleteMapping:请求方式为Delete的@RequestMapping

/* rest */

@RequestBody:请求体设置为Json数据

@ResponseBody:响应体设置为Json数据

@ResonseStatus:响应体状态设置为Json数据

/* 异常统一处理 */

@ControllerAdvice:
- ControllerAdvice本质上是一个Component,因此也会被当成组建扫描
- ControllerAdvice具有拦截功能,提供了多种指定Advice规则的定义方式,默认什么都不写,则是Advice所有Controller
- 搭配@ExceptionHandler使用可以变为异常处理器 @ExceptionHandler:在方法上使用,后面跟异常.class,用于处理对应异常 @RestControllerAdvice:用于处理所有使用REST风格的Controller的异常处理 /* 参数 */ @PathVariable:用于取请求路径上的数据 @RequestParm:用于匹配名称对应的数据,正常情况下省略 /* Ajax */ @CrossOrigin:用于开启Ajax跨域

Spring Boot常用注解

下面我们来介绍SpringBoot常用注解:

/* properties */

@EnableConfigurationProperties:让使用@ConfigurationProperties 注解的类生效,并且将该类注入到 IOC 容器中一同管理

@ConfigurationProperties:标注在Class上,这样SpringBoot就会从Environment中获取属性对应的属性值将其注入

/* Condition */

ConditionOnClass:需要该类路径下包含某个类才能满足条件

ConditionOnMissingBean:只有缺失某个Bean才能满足条件(用于默认属性设置,当不存在手动输入属性,将其设置为默认属性)

ConditionOnProperty:保证符合某Property才能满足条件

/* Auto */

@SpringBootApplication:
- 用于SpringBoot的启动类,其中包含三个注解:@EnableAutoConfiguration,@SpringBootConfiguration,@componentscan @EnableAutoConfiguration:
- 帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot
- 并创建对应配置类的Bean,并把该Bean实体交给IoC容器进行管理 @SpringBootConfiguration:
- 允许在 Spring 上下文中注册额外的 bean 或导入其他配置类(表示配置类,基于@Configuration)

@Configuration注解

下面我们介绍@Configuration注解的注意点:

/* 注意点1 */

@Configuration标注的配置类相当于一个工厂,标注@Bean注解的方法相当于工厂方法

/* 注意点2 */

@Bean不支持方法重载,若含有多个重载方法,会选择参数最多的一个作为工厂方法

/* 注意点3 */

@Configuration默认为标记的类生成代理,当多次创建时,还是会出现默认的Bean,保证@Bean方法互相调用时,保持其单例

/* 问题与解决方法 */

// 问题
若我们在配置类中使用了@Value标注一个值,并将其作用于一个@Bean方法里面,若我们在里面设置一个后处理器,会导致@Value无法显示? // 问题原因
因为我们该配置类中含有后处理器,后处理器在refresh的第五步进行,这时就需要创建类,但@Value的赋值在refresh的第十一步,就会导致无法赋值,也就导致@Value的值无法显示 // 解决方法
1. 将后处理器设置为static类型,让他自动默认生成,这样第五步时就不会生成类而是直接调用类中默认方法(推荐!!!)
2. 直接在方法中使用@Value标注值

@Import注解

下面我们介绍Import的机制:

/* 类名 */

@Import(类名.class)加载单个Bean

/* 配置类名 */

@Import(配置类名.class)联通配置类和内部Bean加载

/* Selector名 */

@Import(Selector.class)通过Selector引入多个类

/* beanDefinition注册器 */

@Import(beanDefinition.class)通过beanDefinition引入多个类

Spring auto

下面我们来介绍SpringBoot的自动装配机制

Springboot自动装配机制

SpringBoot自动装配机制主要依赖于@SpringBootApplication:

/* SpringBootApplication组成 */

@SpringBootConfiguration

@ComponentScan

@EnableAutoConfiguration

/* @SpringBootConfiguration */

基于Configuration注解形成,用于表示配置类

有且仅有一个,表示启动类唯一标识

/* @ComponentScan */

用于扫描组件

内置excludeFilter过滤器,用于排除所不需要的类

内置Filter过滤器,用于排除Springboot默认配置类(会在其他地方添加)

/* @EnableAutoConfiguration */

分为@AutoConfigurationPackage和@Import注解两大块

@AutoConfigurationPackage:记录标注的类的所在包,采用AutoConfigurationPackages类的get方法获得包

@Import:用于导入类,实现主从配置分离,实现优先级降低(优先自己配置类,若没有配置类,再使用默认配置类)

Spring pattern

下面我们介绍Spring所使用的设计模式

Singleton

单例模式Singleton:

/* Spring中的Singleton Bean是否为单例模式??? */

不是!

/* 解释 */

Spring中的Singleton bean并非实现了单例模式,singleton bean仅仅保证每个容器里面相同id的bean的单例

/* 具体体现 */

org.springframework.aop.TruePointcut#INSTANCE

Builder

建造者模式Builder:

/* 定义 */

将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示

/* 使用场景 */

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式

/* 主要亮点 */

1. 较为灵活的构建产品对象
2. 在不执行最后build方法之前,产品对象均不可用
3. 构造过程采用链式调用 /* 具体体现 */ org.springframework.beans.factory.support.BeanDefinitionBuilder

Factory Method

工厂方法FactoryMethod:

/* 定义 */

定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method 使得一个类的实例化延迟(目的:解耦,手段:虚函数)到子类

/* 应用场景 */

通过“对象创建” 模式绕开 new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定

在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化

/* 具体使用 */

Spring中的ApplicationContext与BeanFactory的getBean方法都可以视为工厂方法

Adapter

适配器模式Adapter:

/* 定义 */

如何组合类与对象,以获得更大的结构

/* 应用场景 */

将一个类的接口转换成客户希望的另一个接口。

Adapter 模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。

/* 具体使用 */

org.springframework.web.servlet.HandlerAdapter:
- @RequestMapping标注的控制器实现
- 传统的Controller接口
- 较新的RoyteFunction接口
- 由于处理方法不同,我们采用适配器Adapter来统一接口 我们之前学习的DisposableBeanAdapter,用于bean的销毁,由于具有不同的销毁方法,我们采用DisposableBean统一调用销毁方法

Composite

组合模式Composite:

/* 定义 */

用于创造容器结构,大容器可以存放小容器和物品,小容器可以存放更小的容器

将分散的调用集合起来,统一调用入口

与具体干活的实现实现同一个接口,当调用Composite对象的接口方法时,其实是委托具体干活的实现来完成

/* 应用场景 */

文件和文件夹

/* 具体使用 */

org.springframework.web.servlet.view.ViewResolverComposite

Decorator

装饰器Decorator:

/* 定义 */

动态地给一个对象添加一些额外的职责。

就增加功能来说,Decorator 模式相比生成子类更为灵活。

注重功能增强!!!!!

/* 应用场景 */

为父类设计子类,且子类不用继承父类繁杂的方法

/* 具体使用 */

org.springframework.web.util.ContentCachingRequestWrapper

Proxy

代理模式Proxy:

/* 定义 */

Proxy代理设计模式是一种控制对象访问的设计模式,类似于网络代理

注重控制目标访问!!!!!

/* 应用场景 */

远程代理

虚拟代理

安全代理

/* 具体使用 */

org.springframework.aop.framework.jdkDynamicAopProxy

Responsibility

责任链模式Responsibility:

/* 定义 */

通过一条长链,将多个请求对象连接起来,将请求沿链传递,不断判断该请求对象是否满足该请求,若满足交付

/* 应用场景 */

拦截器等

/* 具体使用 */

org.springframework.web.servlet.handlerInterceptor

Observer

观察者模式Observer:

/* 定义 */

Observer设计模式是为了定义对象间的一种一对多的依赖关系

以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。

Observer模式是一种松耦合的设计模式

/* 具体使用 */

org.springframework.context.ApplicationListener

Strategy

策略模式Strategy:

/* 定义 */

定义一系列算法,并把它们独立封装到类中,使它们可以相互替换,独立于使用它们的客户而变化。

/* 应用场景 */

我们在JVM所学习的线程池的应对方案,针对超出线程池限制的线程我们根据用户和当前情况选择不同的处理方案

/* 具体使用 */

org.springframework.beans.factory.support.InstantiationStraregy

Template Method

模板方法Template Method:

/* 定义 */

定义一个操作算法中的框架,而将这些步骤延迟加载到子类中。

它的本质就是固定算法框架。

/* 应用场景 */

让父类控制子类方法的调用顺序

模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。

各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

/* 具体使用 */

大部分以Template命名的类

大部分以Abstract命名的类

结束语

目前关于Spring的面试点就总结到这里,该篇文章后续会持续更新~

附录

参考资料:

  1. 黑马Java八股文面试题视频教程:框架篇-01-spring_refresh_概述_哔哩哔哩_bilibili

Spring面试点汇总的更多相关文章

  1. 2016年Web前端面试题目汇总

    转载: 2016年Web前端面试题目汇总 以下是收集一些面试中经常会遇到的经典面试题以及自己面试过程中未解决的问题,通过对知识的整理以及经验的总结,重新巩固自身的前端基础知识,如有错误或更好的答案,欢 ...

  2. 前端面试题目汇总摘录(JS 基础篇)

    JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...

  3. spring面试问题与答案集锦

    我收集了一些spring面试的问题,这些问题可能会在下一次技术面试中遇到.对于其他spring模块,我将单独分享面试问题和答案. 如果你能将在以前面试中碰到的,且你认为这些应该是一个有spring经验 ...

  4. Spring 面试问题 TOP 50

    Spring 面试问题 TOP 50 Spring Framework 现在几乎已成为 Java Web 开发的标配框架.那么,作为 Java 程序员,你对 Spring 的主要技术点又掌握了多少呢? ...

  5. Spring面试总结

    Spring面试总结 文件夹(?)[+] 1.什么是spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合.广泛的基础性支持的Java平台.Spr ...

  6. Java面试知识点汇总

    Java面试知识点汇总 置顶 2019年05月07日 15:36:18 温柔的谢世杰 阅读数 21623 文章标签: 面经java 更多 分类专栏: java 面试 Java面试知识汇总   版权声明 ...

  7. 超详细的阿里字节Spring面试技术点总结(建议收藏)

    前言 Spring作为现在最流行Java开发技术,其内部源码设计非常优秀. Spring这个词对于Java开发者想必不会陌生,可能你每天都在使用Spring,享受着Spring生态提供的服务.现在很多 ...

  8. java web轻量级开发面试教程摘录,java web面试技巧汇总,如何准备Spring MVC方面的面试

    本内容摘自 java web轻量级开发面试教程 https://baike.baidu.com/item/Java%20Web%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%BC%80% ...

  9. Spring常用注解汇总

    本文汇总了Spring的常用注解,以方便大家查询和使用,具体如下: 使用注解之前要开启自动扫描功能 其中base-package为需要扫描的包(含子包). <context:component- ...

  10. Spring面试问答Top 25

    欢迎大家向我推荐你在面试过程中遇到关于Spring的问题. 我会把大家推荐的问题加入到以下的Spring经常使用面试题清单中供大家參考. 问题清单: 什么是Spring框架?Spring框架有哪些主要 ...

随机推荐

  1. .Net下的分布式唯一ID

    分布式唯一ID,顾名思义,是指在全世界任何一台计算机上都不会重复的唯一Id. 在单机/单服务器/单数据库的小型应用中,不需要用到这类东西.但在高并发.海量数据.大型分布式应用中,这类却是构建整个系统的 ...

  2. 如何通过 Java 代码隐藏 Word 文档中的指定段落

    在编辑Word文档时,我们有时需要将一些重要信息保密. 因此,可以隐藏它们以确保机密性. 在本文中,将向您介绍如何通过 Java 程序中的代码隐藏 Word 文档中的特定段落.下面是我整理的具体步骤, ...

  3. JSP实现登录功能(页面带样式)

    功能要求 1.完成两个页面 2.第一个登陆页面login. jsp 3.第二个用户管理页面useManage. jsp 4.有登录功能(能进行用户名密码的校验,用户名若为自己的学号密码为班级号,允许登 ...

  4. LOJ2325「清华集训 2017」小Y和恐怖的奴隶主

    题目链接 首先dp很显然,\(f(i,s)\)表示到了第i轮,各种血量人数的情况为s今后的期望攻击boss次数.那么有\(f(i,s)=\frac{1}{num+1}*\sum_{s->s'}( ...

  5. 3.httprunner-extract/.env/Testcase

    参数关联-extract 场景:上一个接口的返回值,传给下一个接口当请求参数 extract:提取变量 $变量名 :引用变量 假设我们有如下场景 用户A登录之后,返回值返回用户UID,我们需要查询该用 ...

  6. C#--对上传的Excel文档的处理

    注:ToString对数值字符串的处理 string nID=555; nID.ToString("00000000");   ---00000555 var oFile = Re ...

  7. Three.js中加载外部fbx格式的模型素材

    index.html部分: index.js部分: Scene.js部分:

  8. 题解 SP10500 HAYBALE - Haybale stacking

    前言 想了好久树状数组啥的,后来想想写打个差分再说,结果写完一遍AC了-- 强烈安利 题意 一个由 \(n\) 个元素组成的序列,给出 \(k\) 个操作,每次将 \(a\sim b\) 加上 \(1 ...

  9. 支持JDK19虚拟线程的web框架之四:看源码,了解quarkus如何支持虚拟线程

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 前文链接 支持JDK19虚拟线程的web框架,之一:体 ...

  10. 洛谷 P4135 作诗 题解

    题面. 之前做过一道很类似的题目 洛谷P4168蒲公英 ,然后看到这题很快就想到了解法,做完这题可以对比一下,真的很像. 题目要求区间内出现次数为正偶数的数字的数量. 数据范围1e5,可以分块. 我们 ...