系列三、Spring Bean"/>
系列三、Spring Bean
一、什么是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
# 源码链接
.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 {@Overridepublic 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 {@Overridepublic 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 Bean
发布评论