Java最全后端面试每日一题 聊聊Spring,面试官必问的技术问题之一

Ending

Tip:由于文章篇幅有限制,下面还有20个关于MySQL的问题,我都复盘整理成一份pdf文档了,后面的内容我就把剩下的问题的目录展示给大家看一下

如果觉得有帮助不妨【转发+点赞+关注】支持我,后续会为大家带来更多的技术类文章以及学习类文章!(阿里对MySQL底层实现以及索引实现问的很多)

吃透后这份pdf,你同样可以跟面试官侃侃而谈MySQL。其实像阿里p7岗位的需求也没那么难(但也不简单),扎实的Java基础+无短板知识面+对某几个开源技术有深度学习+阅读过源码+算法刷题,这一套下来p7岗差不多没什么问题,还是希望大家都能拿到高薪offer吧。

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

// 新增 Bean

registry.registerBeanDefinition(“person”, personBean);

}

}

Bean 的作用域

Bean 的作用域一共有 5 个。

  • (1)singleton 作用域:表示在 Spring 容器中只有一个 Bean 实例,以单例的形式存在,是默认的 Bean 作用域。

配置方式,缺省即可,XML 的配置方式如下:

  • (2)prototype 作用域:原型作用域,每次调用 Bean 时都会创建一个新实例,也就是说每次调用 getBean() 方法时,相当于执行了 new Bean()。

XML 的配置方式如下:

  • (3)request 作用域:每次 Http 请求时都会创建一个新的 Bean,该作用域仅适应于 WebApplicationContext 环境。

XML 的配置方式如下:

Java 注解的配置方式如下:

@Scope(WebApplicationContext.SCOPE_REQUEST)

或是:

@RequestScope(WebApplicationContext.SCOPE_REQUEST)

  • (4)session 作用域:同一个 Http Session 共享一个 Bean 对象,不同的 Session 拥有不同的 Bean 对象,仅适用于 WebApplicationContext 环境。

XML 的配置方式如下:

Java 注解的配置方式如下:

@Scope(WebApplicationContext.SCOPE_SESSION)

或是:

@RequestScope(WebApplicationContext.SCOPE_SESSION)

  • (5)application 作用域:全局的 Web 作用域,类似于 Servlet 中的 Application。

XML 的配置方式如下:

Java 注解的配置方式如下:

@Scope(WebApplicationContext.SCOPE_APPLICATION)

或是:

@RequestScope(WebApplicationContext.SCOPE_APPLICATION)

Bean 生命周期

对于 Spring Bean 来说,并不是启动阶段就会触发 Bean 的实例化,只有当客户端通过显式或者隐式的方式调用 BeanFactory 的 getBean() 方法时,它才会触发该类的实例化方法。当然对于 BeanFactory 来说,也不是所有的 getBean() 方法都会实例化 Bean 对象,例如作用域为 singleton 时,只会在第一次,实例化该 Bean 对象,之后会直接返回该对象。但如果使用的是 ApplicationContext 容器,则会在该容器启动的时候,立即调用注册到该容器所有 Bean 的实例化方法。

getBean() 既然是 Bean 对象的入口,我们就先从这个方法说起,getBean() 方法是属于 BeanFactory 接口的,它的真正实现是 AbstractAutowireCapableBeanFactory 的 createBean() 方法,而 createBean() 是通过 doCreateBean() 来实现的,具体源码实现如下:

@Override

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

throws BeanCreationException {

if (logger.isTraceEnabled()) {

logger.trace(“Creating instance of bean '” + beanName + “'”);

}

RootBeanDefinition mbdToUse = mbd;

// 确定并加载 Bean 的 class

Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {

mbdToUse = new RootBeanDefinition(mbd);

mbdToUse.setBeanClass(resolvedClass);

}

// 验证以及准备需要覆盖的方法

try {

mbdToUse.prepareMethodOverrides();

}

catch (BeanDefinitionValidationException ex) {

throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),

beanName, “Validation of method overrides failed”, ex);

}

try {

// 给BeanPostProcessors 一个机会来返回代理对象来代替真正的 Bean 实例,在这里实现创建代理对象功能

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

if (bean != null) {

return bean;

}

}

catch (Throwable ex) {

throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,

“BeanPostProcessor before instantiation of bean failed”, ex);

}

try {

// 创建 Bean

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

if (logger.isTraceEnabled()) {

logger.trace(“Finished creating instance of bean '” + beanName + “'”);

}

return beanInstance;

}

catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {

throw ex;

}

catch (Throwable ex) {

throw new BeanCreationException(

mbdToUse.getResourceDescription(), beanName, “Unexpected exception during bean creation”, ex);

}

}

doCreateBean 源码如下:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

throws BeanCreationException {

// 实例化 bean,BeanWrapper 对象提供了设置和获取属性值的功能

BeanWrapper instanceWrapper = null;

// 如果 RootBeanDefinition 是单例,则移除未完成的 FactoryBean 实例的缓存

if (mbd.isSingleton()) {

instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);

}

if (instanceWrapper == null) {

// 创建 bean 实例

instanceWrapper = createBeanInstance(beanName, mbd, args);

}

// 获取 BeanWrapper 中封装的 Object 对象,其实就是 bean 对象的实例

final Object bean = instanceWrapper.getWrappedInstance();

// 获取 BeanWrapper 中封装 bean 的 Class

Class<?> beanType = instanceWrapper.getWrappedClass();

if (beanType != NullBean.class) {

mbd.resolvedTargetType = beanType;

}

// 应用 MergedBeanDefinitionPostProcessor 后处理器,合并 bean 的定义信息

// Autowire 等注解信息就是在这一步完成预解析,并且将注解需要的信息放入缓存

synchronized (mbd.postProcessingLock) {

if (!mbd.postProcessed) {

try {

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

} catch (Throwable ex) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName,

“Post-processing of merged bean definition failed”, ex);

}

mbd.postProcessed = true;

}

}

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

isSingletonCurrentlyInCreation(beanName));

if (earlySingletonExposure) {

if (logger.isTraceEnabled()) {

logger.trace(“Eagerly caching bean '” + beanName +

“’ to allow for resolving potential circular references”);

}

// 为了避免循环依赖,在 bean 初始化完成前,就将创建 bean 实例的 ObjectFactory 放入工厂缓存(singletonFactories)

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

}

// 对 bean 属性进行填充

Object exposedObject = bean;

try {

populateBean(beanName, mbd, instanceWrapper);

// 调用初始化方法,如 init-method 注入 Aware 对象

exposedObject = initializeBean(beanName, exposedObject, mbd);

} catch (Throwable ex) {

if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {

throw (BeanCreationException) ex;

} else {

throw new BeanCreationException(

mbd.getResourceDescription(), beanName, “Initialization of bean failed”, ex);

}

}

if (earlySingletonExposure) {

// 如果存在循环依赖,也就是说该 bean 已经被其他 bean 递归加载过,放入了提早公布的 bean 缓存中

Object earlySingletonReference = getSingleton(beanName, false);

if (earlySingletonReference != null) {

// 如果 exposedObject 没有在 initializeBean 初始化方法中被增强

if (exposedObject == bean) {

exposedObject = earlySingletonReference;

} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {

// 依赖检测

String[] dependentBeans = getDependentBeans(beanName);

Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);

for (String dependentBean : dependentBeans) {

if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

actualDependentBeans.add(dependentBean);

}

}

// 如果 actualDependentBeans 不为空,则表示依赖的 bean 并没有被创建完,即存在循环依赖

if (!actualDependentBeans.isEmpty()) {

throw new BeanCurrentlyInCreationException(beanName,

“Bean with name '” + beanName + “’ has been injected into other beans [” +

StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +

"] in its raw version as part of a circular reference, but has eventually been " +

"wrapped. This means that said other beans do not use the final version of the " +

"bean. This is often the result of over-eager type matching - consider using " +

“‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.”);

}

}

}

}

try {

// 注册 DisposableBean 以便在销毁时调用

registerDisposableBeanIfNecessary(beanName, bean, mbd);

} catch (BeanDefinitionValidationException ex) {

throw new BeanCreationException(

mbd.getResourceDescription(), beanName, “Invalid destruction signature”, ex);

}

return exposedObject;

}

从上述源码中可以看出,在 doCreateBean() 方法中,首先对 Bean 进行了实例化工作,它是通过调用 createBeanInstance() 方法来实现的,该方法返回一个 BeanWrapper 对象。BeanWrapper 对象是 Spring 中一个基础的 Bean 结构接口,说它是基础接口是因为它连基本的属性都没有。

BeanWrapper 接口有一个默认实现类 BeanWrapperImpl,其主要作用是对 Bean 进行填充,比如填充和注入 Bean 的属性等。

当 Spring 完成 Bean 对象实例化并且设置完相关属性和依赖后,则会调用 Bean 的初始化方法 initializeBean(),初始化第一个阶段是检查当前 Bean 对象是否实现了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 等接口,源码如下:

private void invokeAwareMethods(final String beanName, final Object bean) {

if (bean instanceof Aware) {

if (bean instanceof BeanNameAware) {

((BeanNameAware) bean).setBeanName(beanName);

}

if (bean instanceof BeanClassLoaderAware) {

ClassLoader bcl = getBeanClassLoader();

if (bcl != null) {

((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);

}

}

if (bean instanceof BeanFactoryAware) {

((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);

}

}

}

其中,BeanNameAware 是把 Bean 对象定义的 beanName 设置到当前对象实例中;BeanClassLoaderAware 是将当前 Bean 对象相应的 ClassLoader 注入到当前对象实例中;BeanFactoryAware 是 BeanFactory 容器会将自身注入到当前对象实例中,这样当前对象就会拥有一个 BeanFactory 容器的引用。

初始化第二个阶段则是 BeanPostProcessor 增强处理,它主要是对 Spring 容器提供的 Bean 实例对象进行有效的扩展,允许 Spring 在初始化 Bean 阶段对其进行定制化修改,比如处理标记接口或者为其提供代理实现。

在初始化的前置处理完成之后就会检查和执行 InitializingBean 和 init-method 方法。

InitializingBean 是一个接口,它有一个 afterPropertiesSet() 方法,在 Bean 初始化时会判断当前 Bean 是否实现了 InitializingBean,如果实现了则调用 afterPropertiesSet() 方法,进行初始化工作;然后再检查是否也指定了 init-method,如果指定了则通过反射机制调用指定的 init-method 方法,它的实现源码如下:

最后

分享一些系统的面试题,大家可以拿去刷一刷,准备面试涨薪。

这些面试题相对应的技术点:

  • JVM
  • MySQL
  • Mybatis
  • MongoDB
  • Redis
  • Spring
  • Spring boot
  • Spring cloud
  • Kafka
  • RabbitMQ
  • Nginx

大类就是:

  • Java基础
  • 数据结构与算法
  • 并发编程
  • 数据库
  • 设计模式
  • 微服务
  • 消息中间件

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

程序员,每个月给你发多少工资,你才会想老板想的事?

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

设计模式

  • 微服务
  • 消息中间件

[外链图片转存中…(img-JsyTdKfS-1715341186520)]

[外链图片转存中…(img-0kU1cyNp-1715341186521)]

[外链图片转存中…(img-3YQvgjBM-1715341186522)]

[外链图片转存中…(img-e98qzhPC-1715341186522)]

[外链图片转存中…(img-UOfreTfJ-1715341186522)]

[外链图片转存中…(img-IYKT6hIY-1715341186523)]

[外链图片转存中…(img-jPf1BPaX-1715341186523)]

[外链图片转存中…(img-2CgKmetO-1715341186524)]

[外链图片转存中…(img-zffeaIXV-1715341186524)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值