一、什么是Spring bean *
一句话,被Spring容器管理的bean就是Spring bean。
二、Java bean和Spring bean对象之间的区别
Java bean的实例化对象是自己创建出来的,Spring的bean是IOC容器创建出来的。
三、配置bean有哪几种方式 *
答:有四种方式,分别如下:
# 第一种:xml方式
<bean id="userService" class="org.star.UserService"></bean>
# 第二种:注解方式
@Component、@Controller、@Service、@Repostory
前提:需要配置扫描包
# 第三种:JavaConfig方式
@Bean
# 第四种:@Import方式
3.1、@Component和@Bean的区别
@Component是通过Spring的反射机制调用构造方法实例化的,@Bean通常和@Configuration注解搭配使用,通过方法返回,自己可以控制实例化过程。
四、Spring中bean的作用域有哪几种 *
- singleton 单例(默认)
- prototype 多例
- request web应用,一个请求创建一个bean
- session web应用,一个会话创建一个bean
- application web应用,一个应用共享一个bean
五、单例bean的优势 **
- 减少了新生成实例的消耗。新生成实例消耗包括两个方面
(1)Spring底层会通过工厂模式+反射的方式实例化bean,这些都是消耗性能的操作;
(2)给对象分配内存也会涉及到复杂的算法; - 减少JVM垃圾回收,不会给每个请求都生成新的实例bean,所以回收的对象变少了;
- 可以快速地获取到bean,因为单实例的bean除了第一次getBean之外,其余都是直接从缓存中获取的,所以很快;
六、Spring的bean是线程安全的吗 ***
单例bean的情况下,如果在类中声明了成员变量,并且有读写操作,那么这个bean就存在线程安全问题,但是如果把成员变量声明在方法中,那么此时这个单例bean就是线程安全的。
七、Spring如何处理线程并发问题 ***
- 将bean设置为多例(在类中声明了成员变量,并且有读写操作);
- 将成员变量放到ThreadLocal中;
- 使用同步锁(会影响服务器的吞吐量)(在类中声明了成员变量,并且有读写操作)
八、Spring实例化bean有几种方式 ***
- 方式一:构造器方式
- 方式二:通过静态工厂方式
- 方式三:通过实例工厂方式
- 方式四:通过FactoryBean
# 源码链接
https://gitee.com/augenstemn/spring-interview-parent.git
8.1、这几种创建bean的方式,有何不同
方式一由Spring控制bean的实例过程,方式二、三、四由程序员自己控制,更加灵活。
九、什么是bean的装配?什么是bean的自动装配 *
Spring容器创建bean后,这一个个的bean如果不为其装配(又称注入)属性,那么这些bean直接是没有任何联系的,可以手动的在xml中通过property+ref的方式手动维护bean和bean之间的关系,这种方式称为手动注入,也可以通过@Autowired的方式进行自动注入。
十、自动注入的注意事项 *
- 一定要声明set方法
- 覆盖:当配置了自动注入后,仍然可以使用<constructor-arg>和<property>配置来定义依赖,这些配置将覆盖自动注入
十一、自动装配的方式有几种 *
在Spring中,对象无需自己查找或者创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,可以使用@Autowired或者@Resource注解来配置自动装配模式,在Spring框架的xml配置中共有5种自动装配:
- no:默认的方式是不自动进行装配的,需要手动设置ref属性来进行装配bean;
- byName:通过bean的名称来进行自动装配,如果一个bean的属性和另一个bean的name相同,就会进行自动装配;
- byType:通过参数的数据类型进行自动装配;
- constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配;
- autodetect:自动探测,如果有构造方法,通过构造方法自动装配,否则使用byType方式进行自动装配(在Spring3.0+中弃用);
十二、bean有哪些生命周期的回调方法和执行顺序 **
答:生命周期的回调方法主要分两种,一种是初始化的时候进行调用的,另外一种是销毁的时候进行调用的,不管是初始化调用还是销毁时调用,都有对应的三种方式。
- 方式一:通过注解 @PostConstruct + @PreDestroy的方式,实现回调(优先级最高)
- 方式二:通过实现接口 InitializingBean, DisposableBean的方式,实现回调(优先级其次)
- 方式三:通过 @Bean(initMethod = "init",destroyMethod = "destroy")的方式,实现回调(优先级最低)
十三、Spring在加载过程中,bean有哪几种形态 ***
十四、bean的生命周期
bean的生命周期是指bean从创建到销毁的整个过程,分为如下四个大的过程,即:
- 实例化
(1)构造器方式实例化
(2)静态工厂实例化
(3)实例工厂实例化
(4)FactoryBean实例化 - 属性赋值
(1)解析自动装配(byName、byType、Constructor、@Autowired) ===> DI的体现
(2)可能会出现循环依赖问题 - 初始化
(1)调用xxxAware回调方法
(2)调用初始化生命周期回调(三种)
(3)如果bean实现了aop,创建动态代理 - 销毁
(1)在Spring容器关闭的时候进行调用
(2)调用销毁生命周期进行回调
十五、Spring是如何解决循环依赖的
十六、Spring如何避免在并发情况下获取到不完整的bean
16.1、不完整的bean
实例化后,属性填充及初始化之前的bean即为不完整的bean。
16.2、如何避免获取到不完整的bean
双重检查锁机制。
16.3、为什么一级缓存不加到锁里面
主要出于性能的考虑,避免已创建好的bean阻塞等待。
十七、BeanDefinition的加载过程 ****
BeanDefinition用来描述bean的生产信息,决定bean如何生产,是一个定义态的bean。我们在创建Spring容器的时候,首先会去读取配置,然后解析配置,将符合条件的bean注册成BeanDefinitionMap,然后工厂根据这些描述信息去生产bean。
十八、如何在Spring中所有的bean创建完成后做扩展 ****
18.1、哪个地方标识着所有的bean创建完成了
循环完所有的DeanDefinition后,bean就创建完了。
# 1
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
# 2、AbstractApplicationContext 550行
finishBeanFactoryInitialization(beanFactory);
# 3、AbstractApplicationContext 878行
beanFactory.preInstantiateSingletons();
# 4、DefaultListableBeanFactory #preInstantiateSingletons 849~903行
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
}
}
}
18.2、两种方式
创建监听器、实现接口
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/10/25 10:58
* @Description:
*/
@Component
public class MyContextRefreshedEventExtend {
@EventListener(ContextRefreshedEvent.class)
public void onContextRefreshedEvent(ContextRefreshedEvent event) {
System.out.println(event);
System.out.println("all singleton beans loaded,onContextRefreshedEvent execute success!");
}
}
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/10/25 11:03
* @Description:
*/
@Component
public class MySmartInitializingSingletonExtend implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("all singleton beans loaded,afterSingletonsInstantiated execute success!");
}
}
十九、如何在所有的BeanDefinition注册完成后做扩展 ***
实现BeanFactoryPostProcessor接口,做扩展。
/**
* @Author : 一叶浮萍归大海
* @Date: 2023/10/25 11:45
* @Description: bean工厂的后置处理器,用于在所有的BeanDefinition注册完成后做扩展
*/
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String definitionName : beanFactory.getBeanDefinitionNames()) {
System.out.println("definitionName = " + definitionName);
}
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");
beanDefinition.setScope("prototype");
}
}
二十、bean的创建顺序是由什么决定的
bean的创建顺序是由BeanDefinition的注册顺序来决定的,当存在依赖关系时,会影响bean的创建顺序。
20.1、BeanDefinition的注册顺序是由什么决定的