系列三、Spring Bean

一、什么是Spring bean *

一句话,被Spring容器管理的bean就是Spring bean。

二、Java bean和Spring bean对象之间的区别 

Java bean的实例化对象是自己创建出来的,Spring的bean是IOC容器创建出来的。

三、配置bean有哪几种方式 *

答:有四种方式,分别如下:

# 第一种:xml方式


# 第二种:注解方式
@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有几种方式 ***

  1. 方式一:构造器方式
  2. 方式二:通过静态工厂方式
  3. 方式三:通过实例工厂方式
  4. 方式四:通过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方法
  • 覆盖:当配置了自动注入后,仍然可以使用配置来定义依赖,这些配置将覆盖自动注入

十一、自动装配的方式有几种 *

系列三、Spring Bean_第1张图片

        在Spring中,对象无需自己查找或者创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,可以使用@Autowired或者@Resource注解来配置自动装配模式,在Spring框架的xml配置中共有5种自动装配:

  • no:默认的方式是不自动进行装配的,需要手动设置ref属性来进行装配bean;
  • byName:通过bean的名称来进行自动装配,如果一个bean的属性和另一个bean的name相同,就会进行自动装配;
  • byType:通过参数的数据类型进行自动装配;
  • constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配;
  • autodetect:自动探测,如果有构造方法,通过构造方法自动装配,否则使用byType方式进行自动装配(在Spring3.0+中弃用);

十二、bean有哪些生命周期的回调方法和执行顺序 **

答:生命周期的回调方法主要分两种,一种是初始化的时候进行调用的,另外一种是销毁的时候进行调用的,不管是初始化调用还是销毁时调用,都有对应的三种方式。

  1. 方式一:通过注解 @PostConstruct + @PreDestroy的方式,实现回调(优先级最高)
  2. 方式二:通过实现接口 InitializingBean, DisposableBean的方式,实现回调(优先级其次)
  3. 方式三:通过 @Bean(initMethod = "init",destroyMethod = "destroy")的方式,实现回调(优先级最低)

系列三、Spring Bean_第2张图片

十三、Spring在加载过程中,bean有哪几种形态 ***

系列三、Spring Bean_第3张图片

十四、bean的生命周期

bean的生命周期是指bean从创建到销毁的整个过程,分为如下四个大的过程,即:

  1. 实例化
    (1)构造器方式实例化
    (2)静态工厂实例化
    (3)实例工厂实例化
    (4)FactoryBean实例化
  2. 属性赋值
    (1)解析自动装配(byName、byType、Constructor、@Autowired) ===> DI的体现
    (2)可能会出现循环依赖问题
  3. 初始化
    (1)调用xxxAware回调方法
    (2)调用初始化生命周期回调(三种)
    (3)如果bean实现了aop,创建动态代理
  4. 销毁
    (1)在Spring容器关闭的时候进行调用
    (2)调用销毁生命周期进行回调

系列三、Spring Bean_第4张图片

十五、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 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)
										((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) () -> {
					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的注册顺序是由什么决定的

 

你可能感兴趣的:(Spring全家桶面试系列,1024程序员节)