系列三、Spring Bean

编程入门 行业动态 更新时间:2024-10-10 08:25:19

<a href=https://www.elefans.com/category/jswz/34/1770787.html style=系列三、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有几种方式 ***

  1. 方式一:构造器方式
  2. 方式二:通过静态工厂方式
  3. 方式三:通过实例工厂方式
  4. 方式四:通过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有哪些生命周期的回调方法和执行顺序 **

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

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

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

十四、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是如何解决循环依赖的

十六、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

本文发布于:2023-12-03 08:06:28,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1653018.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:系列   Spring   Bean

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!