Spring面试题系列-2

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

ApplicationContext的实现类有哪些?

ApplicationContext 是 Spring 框架中的一个核心接口,它表示 Spring IoC 容器的配置,能够加载配置描述文件。ApplicationContext 的实现类主要有以下几种:

  1. ClassPathXmlApplicationContext:从类路径下的 XML 配置文件中加载 Spring 的配置文件,适用于 classpath 的方式获取配置文件。
  2. FileSystemXmlApplicationContext:从文件系统中的 XML 配置文件中加载 Spring 的配置文件,适用于文件系统的方式获取配置文件。
  3. WebApplicationContext:专门为 Web 应用准备的,它允许从相对于 Web 根目录的路径中加载配置文件。它的一个具体实现是 XmlWebApplicationContext,它会在 Web 应用的 WebContent/WEB-INF 目录下查找配置文件。
  4. AnnotationConfigApplicationContext:基于 Java 注解的方式来配置 Spring,适用于 Java 配置的方式。
  5. GenericXmlApplicationContext:加载 XML 格式的配置文件,并且提供了更加灵活的配置方式。

除了上述常见的实现类,Spring 还提供了其他的 ApplicationContext 实现类,以满足不同的使用场景和需求。在选择使用哪种实现类时,通常需要考虑你的应用类型(例如,Web 应用或桌面应用)、配置文件的存储位置(例如,类路径或文件系统)以及配置方式(例如,XML 或注解)。
注意:在使用 ApplicationContext 时,要确保在不再需要它时正确地关闭它,以释放资源。这通常可以通过调用其 close() 方法来实现。

Bean标签的属性?

Bean标签在Spring框架中用于定义和配置Bean对象。以下是一些常用的Bean标签属性及其作用:

  1. id:指定Bean的唯一标识符。在Spring容器中,每个Bean都必须有一个唯一的id。这个id用于在后续的代码中引用该Bean。
  2. class:指定Bean的类名。通过该属性,Spring将实例化并管理指定类的对象作为Bean。需要注意的是,这里需要指定类的全限定名,即类名加上包名,并使用"."号连接。
  3. name:用于指定Bean的名称,提供额外的别名。除了id属性外,name属性可以接受多个以逗号或空格分隔的名称,这在某些情况下可能更加灵活。
  4. scope:指定Bean的作用域。这决定了Bean的实例化方式和生命周期。例如,可以设置为"singleton"(单例模式,容器中只有一个实例),“prototype”(原型模式,每次请求都会创建新的实例)等。
  5. lazy-init:指定是否延迟初始化Bean。如果设置为true,则Bean将在首次使用时才进行初始化,而不是在容器启动时立即初始化。
  6. autowire:指定自动装配的方式。Spring可以自动装配Bean之间的依赖关系,这通过该属性进行配置。例如,可以设置为"byName"(按名称自动装配)或"byType"(按类型自动装配)。
  7. factory-bean:指定工厂Bean的名称。在某些情况下,你可能希望使用工厂方法来创建Bean实例,这时可以通过该属性指定工厂Bean。
  8. factory-method:指定工厂方法的名称。与factory-bean属性一起使用,用于指定创建Bean实例的工厂方法。
  9. profile:指定在特定的环境配置文件中激活Bean。这允许你根据不同的环境(如开发、测试、生产)加载不同的Bean配置。
  10. parent:指定父级Bean的名称。在某些高级配置中,你可能希望一个Bean继承另一个Bean的属性,这时可以使用该属性进行配置。

这些属性提供了灵活的方式来定义和配置Spring容器中的Bean对象,以满足不同的应用需求。在实际使用中,你可以根据具体的应用场景选择适合的属性进行配置。

Bean的作用范围和生命周期?

Bean在Spring框架中扮演着核心角色,它们代表了应用程序中的对象,并由Spring容器负责其创建、配置和管理。Bean的作用范围和生命周期是Spring框架中两个重要的概念。

Bean的作用范围

Bean的作用范围决定了Bean实例在Spring容器中的可见性和生命周期。Spring提供了几种不同的作用范围,以满足不同场景的需求:

  1. Singleton(单例):这是Spring中Bean的默认作用范围。在整个Spring容器中,无论多少次请求该Bean,都只会返回同一个Bean实例。这意味着Bean实例在容器初始化时创建,并在容器关闭时销毁,期间始终为同一个对象。
  2. Prototype(原型):对于原型作用范围的Bean,每次从容器中请求该Bean时,都会创建一个新的Bean实例。这意味着每次获取到的Bean都是一个新的对象。
  3. Request:这种作用范围的Bean只在一次HTTP请求的生命周期内有效。每次请求都会有一个新的Bean实例,不同请求之间的Bean实例不共享。
  4. Session:这种作用范围的Bean在整个用户会话期间有效。对于同一个用户的多次请求,都会返回同一个Bean实例。
  5. Global Session:这种作用范围通常用于Portlet环境,类似于Session,但在全局范围内有效。
  6. WebSocket:这种作用范围的Bean在WebSocket连接的生命周期内有效,仅适用于WebSocket应用程序。
Bean的生命周期

Bean的生命周期描述了Bean从创建到销毁的整个过程。Spring Bean的生命周期大致可以分为以下几个阶段:

  1. 实例化:Spring容器通过反射机制创建Bean的实例。
  2. 属性注入:Spring容器将配置文件中定义的属性值注入到Bean的相应字段或方法中。
  3. 初始化:如果Bean实现了InitializingBean接口,Spring会调用其afterPropertiesSet()方法进行初始化。此外,还可以通过配置<bean>标签的init-method属性来指定一个自定义的初始化方法。
  4. 使用:Bean在应用程序中被使用,执行其业务逻辑。
  5. 销毁:当Spring容器关闭时,如果Bean实现了DisposableBean接口,Spring会调用其destroy()方法进行销毁。同样,也可以通过配置<bean>标签的destroy-method属性来指定一个自定义的销毁方法。

此外,Spring还提供了BeanPostProcessor接口,允许开发者在Bean的生命周期中的特定点执行自定义逻辑,如在Bean初始化前后进行处理。
理解Bean的作用范围和生命周期对于正确使用和管理Spring容器中的Bean至关重要,它有助于开发者更好地控制Bean的行为和性能。

Spring循环依赖是如何解决的?

Spring框架通过几种不同的机制来解决循环依赖问题。循环依赖通常发生在两个或多个Bean相互依赖对方的情况下,即Bean A依赖于Bean B,而Bean B又依赖于Bean A。Spring主要关注单例作用域的Bean的循环依赖问题,因为原型作用域的Bean每次请求都会创建新的实例,所以不存在循环依赖的问题。
Spring主要通过三级缓存来解决单例作用域的Bean的循环依赖问题。以下是Spring解决循环依赖的主要步骤:

  1. 一级缓存(Singleton Cache):这是Spring容器中的单例缓存,用于存储已经实例化、配置完成并且完全初始化的Bean。一旦Bean被完全初始化并放入这个缓存中,它就可以被其他Bean引用。
  2. 二级缓存(Early Singleton Cache):当Bean实例化后,但还未进行属性注入和初始化方法调用之前,Spring会将这个Bean的原始对象(即尚未填充属性的对象)放入二级缓存中。这样做是为了解决循环依赖问题,因为即使Bean的某些属性还未被注入,也可以先将其引用暴露给其他Bean。
  3. 三级缓存(Singleton Factory Cache):这个缓存中存储的是ObjectFactory对象,这个对象用于生成Bean的实例。当Spring发现循环依赖时,会创建一个ObjectFactory并将其放入三级缓存中。这个ObjectFactory会在需要时创建并返回Bean的实例。

解决循环依赖的详细过程如下:

  1. 当Spring容器创建Bean A时,首先会实例化Bean A,并将其原始对象放入二级缓存。
  2. 如果Bean A需要注入Bean B,Spring会尝试从一级缓存中获取Bean B。如果找不到,就会尝试创建Bean B。
  3. 在创建Bean B的过程中,Spring同样会将其原始对象放入二级缓存。如果Bean B也需要注入Bean A,Spring会尝试从二级缓存中获取Bean A的原始对象(此时Bean A的原始对象已经存在于二级缓存中)。
  4. 获取到Bean A的原始对象后,Spring可以继续Bean B的创建过程,包括属性注入和初始化方法调用。
  5. 当Bean B创建完成后,Spring会将其放入一级缓存,并通知所有等待Bean B的Bean(在这个例子中就是Bean A)可以继续它们的创建过程。
  6. 对于Bean A,现在它可以获取到完全初始化的Bean B,并完成自己的创建过程。

通过这种方式,Spring能够解决单例作用域的Bean之间的循环依赖问题。需要注意的是,这种解决方案只适用于构造器注入和字段注入,对于setter方法注入,Spring则无法处理循环依赖,因为setter方法注入是在Bean实例化之后进行的。因此,在可能存在循环依赖的情况下,推荐使用构造器注入或字段注入。

Spring实例化bean有哪些方式?

在Spring框架中,实例化Bean主要有以下几种方式:

  1. 构造器实例化:这是最常用的方式之一。Spring容器通过调用Bean对应的类中的默认构造器函数来实例化Bean。这意味着你需要在Bean类中定义一个无参的构造器,Spring将使用这个构造器来创建Bean的实例。
  2. 静态工厂实例化:当Bean的创建过程较为复杂,不适合直接通过构造器创建时,你可以使用静态工厂方法。这需要在你的工厂类中定义一个静态方法,该方法返回需要创建的Bean的实例。然后,在Spring配置文件中,你可以通过指定factory-method属性来告诉Spring调用哪个静态方法来获取Bean。
  3. 实例工厂实例化:与静态工厂方法类似,实例工厂方法也是用来创建Bean的。但是,与静态工厂方法不同,实例工厂方法不是静态的,因此需要一个工厂Bean的实例来调用它。在Spring配置文件中,你需要使用factory-bean属性来指定工厂Bean,然后使用factory-method属性来指定实例化Bean的方法。
  4. FactoryBean实例化:FactoryBean是Spring框架中提供的一个接口,允许你自定义Bean的创建过程。实现FactoryBean接口的类需要重写getObject()方法,该方法返回的就是需要创建的Bean的实例。当Spring需要获取FactoryBean的实例时,实际上返回的是FactoryBean的getObject()方法返回的对象,而不是FactoryBean本身。

以上就是Spring实例化Bean的几种主要方式。每种方式都有其特定的使用场景,你可以根据具体的需求选择合适的方式来实例化你的Bean。

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

随缘而愈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值