Spring 核心知识要点全解析

111 阅读10分钟

在 Java 开发领域,Spring 框架占据着极为重要的地位。它为开发者提供了强大的功能和便捷的开发方式,广泛应用于各类企业级应用和 Web 项目中。本文将深入探讨 Spring 框架中的一些核心要点,包括 Spring Bean 的生命周期、作用域、基于 XML 的注入方式、所运用的设计模式以及 ApplicationContext 和 BeanFactory 的区别等内容,帮助读者全面理解 Spring 框架的关键特性与机制,从而在实际开发中能够更加熟练地运用 Spring 进行高效的应用程序构建。

1.解释一下spring bean的生命周期

Spring Bean 的生命周期是指一个Bean从创建到销毁所经历的过程。了解这个过程有助于我们更好地管理Bean的行为和状态。以下是Spring Bean生命周期的主要阶段:

实例化 (Instantiation):

  • Spring容器根据配置元数据(XML配置文件、注解或Java配置)创建Bean的实例。

属性赋值 (Populate Properties):

  • 容器将配置中的属性值和依赖注入到新实例中。

设置Bean名称 (Setting Bean Name):

  • 如果Bean实现了BeanNameAware接口,容器会调用setBeanName(String name)方法,传递Bean的ID给它。

设置Bean工厂 (Setting Bean Factory):

  • 如果Bean实现了BeanFactoryAware接口,容器会调用setBeanFactory(BeanFactory beanFactory)方法,将BeanFactory容器实例传入。

预初始化 (Pre-Initialization):

  • 如果有BeanPostProcessor接口的实现,容器会调用postProcessBeforeInitialization(Object obj, String s)方法。

初始化 (Initialization):

  • 如果Bean实现了InitializingBean接口,容器会调用afterPropertiesSet()方法。
  • 如果在配置中有定义init-method,则会调用相应的初始化方法。

使用 (Ready to Use):

  • 此时Bean已经可以被应用程序使用了。

后处理 (Post-Initialization):

  • 如果有BeanPostProcessor接口的实现,容器会调用postProcessAfterInitialization(Object obj, String s)方法。

销毁 (Destruction):

  • 当容器关闭时,如果Bean实现了DisposableBean接口,容器会调用destroy()方法。
  • 如果在配置中有定义destroy-method,则会调用相应的销毁方法。

每个阶段都可以被开发者自定义或者扩展,以满足特定的需求。例如,你可以通过实现特定的接口(如BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean等)来影响Bean的行为,或者通过配置init-method和destroy-method来指定初始化和销毁的方法。此外,还可以通过注册BeanPostProcessor来对所有或特定的Bean进行额外的处理。

2.解释Spring支持的几种bean的作用域?

Spring框架支持多种Bean的作用域(scope),这些作用域能够控制Bean在应用中的生命周期和可见性。以下是Spring中常见的几种Bean作用域:

Singleton (单例):

  • 这是Spring Bean的默认作用域。
  • 在Spring容器中,对于每个被标记为singleton的Bean定义,只会存在一个共享实例。
  • 无论有多少个Bean引用它,都指向同一个对象实例。

Prototype (原型):

  • 每次通过Spring容器获取prototype作用域的Bean时,都会创建一个新的Bean实例。
  • 这意味着即使你注入了prototype Bean到另一个singleton Bean中,每次请求singleton Bean的时候,prototype Bean也会创建新的实例。

Request:

  • 该作用域仅适用于Web-aware Spring ApplicationContext环境。
  • 对于每一次HTTP请求,Spring容器会创建一个新的Bean实例,并且该Bean仅在当前HTTP请求内有效。

Session:

  • 同样只适用于Web-aware Spring ApplicationContext环境。
  • Bean的作用范围是整个HTTP Session期间。也就是说,在同一Session内的所有HTTP请求都将共享同一个Bean实例。

Application:

  • 该作用域也是针对Web-aware Spring ApplicationContext。
  • Bean在整个Servlet上下文(ServletContext)中唯一,所有用户共享同一个Bean实例。

WebSocket:

  • 自Spring 4.0起引入,此作用域与WebSocket交互有关。
  • Bean的作用范围是WebSocket连接期间,即在每个WebSocket连接中,Bean将具有独立的实例。

选择合适的Bean作用域非常重要,因为它直接影响到Bean的生命周期管理和线程安全性。例如,对于无状态的服务组件,使用singleton作用域通常是安全且高效的;而对于有状态的组件,如用户会话相关的数据处理,则可能更适合使用prototype、request或session作用域。

3.Spring基于xml注入bean的几种方式?

在Spring中,基于XML配置文件注入Bean的几种方式主要包括构造器注入、设值注入(也称为setter注入)、属性注入和集合注入。下面详细解释这些注入方式:

构造器注入 (Constructor Injection):

构造器注入是通过调用类的构造函数来设置依赖关系。这种方式可以确保对象创建时所有必需的依赖都被提供。

<bean id="exampleBean" class="com.example.ExampleBean">
    <constructor-arg value="value"/>
    <!-- 如果构造器有多个参数 -->
    <constructor-arg>
        <ref bean="anotherBean"/>
    </constructor-arg>
</bean>

设值注入 (Setter Injection):

设值注入是通过调用类的setter方法来设置依赖关系。这是最常用的方式,因为它提供了更大的灵活性,允许在创建后修改Bean的属性。

<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="propertyOne" value="value"/>
    <property name="propertyTwo" ref="anotherBean"/>
</bean>

属性注入 (Property Injection):

属性注入指的是直接为Bean的属性赋值,而不需要通过构造器或setter方法。这通常用于简单的值类型注入,如字符串、整数等。实际上,属性注入就是设值注入的一部分,因为它是通过setter方法完成的。

集合注入 (Collection Injection):

集合注入用来为Bean的集合类型的属性赋值,包括列表(List)、集合(Set)、映射(Map)和属性(Properties)。这对于需要管理一组相关对象的情况非常有用。

<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="someList">
        <list>
            <value>item1</value>
            <value>item2</value>
        </list>
    </property>
    <property name="someSet">
        <set>
            <value>itemA</value>
            <value>itemB</value>
        </set>
    </property>
    <property name="someMap">
        <map>
            <entry key="key1" value="value1"/>
            <entry key="key2" value="value2"/>
        </map>
    </property>
    <property name="someProps">
        <props>
            <prop key="name">value</prop>
        </props>
    </property>
</bean>

p命名空间注入:

从Spring 2.0开始,可以使用p命名空间简化设值注入的语法。这种方式下,你不再需要写标签,而是直接在bean标签中指定属性名和值。

<bean id="exampleBean" class="com.example.ExampleBean"
      p:propertyOne="value" p:propertyTwo-ref="anotherBean"/>

c命名空间注入:

类似于p命名空间,c命名空间用于简化构造器注入的语法。它允许你在bean标签中直接指定构造器参数。

<bean id="exampleBean" class="com.example.ExampleBean"
      c:_0="value" c:_1-ref="anotherBean"/>

请注意,虽然XML配置是早期版本的Spring中定义Bean的主要方式,但在现代的Spring应用中,更推荐使用注解配置或Java配置(如@Configuration和@Bean注解)来定义和注入Bean。XML配置仍然支持,并且在某些情况下可能更适合,但它不再是首选方法。

4.Spring框架中都用到了哪些设计模式?

Spring框架广泛使用了多种设计模式来实现其核心功能和特性。以下是Spring中应用到的一些主要设计模式:

单例模式 (Singleton Pattern):

  • Spring容器中的Bean默认是单例模式。这意味着在Spring IoC容器中,对于每个被定义为singleton的Bean,仅会创建一个实例。

工厂模式 (Factory Pattern):

  • Spring的BeanFactory接口提供了工厂模式的实现,它负责创建和管理Bean的生命周期。通过BeanFactory或更高级的ApplicationContext,可以获取应用程序上下文中配置的Bean实例。

代理模式 (Proxy Pattern):

  • Spring AOP(面向切面编程)使用Java动态代理或CGLIB库创建目标对象的代理,以便于在方法调用前后插入额外的行为(如事务管理、日志记录等)。

模板方法模式 (Template Method Pattern):

  • JdbcTemplate, JmsTemplate, RestTemplate等都是模板方法模式的例子。这些模板类提供了一组预定义的方法来执行常见的操作,同时允许子类重写某些步骤以适应特定需求。

适配器模式 (Adapter Pattern):

  • 例如,Spring MVC中的HandlerAdapter将请求分发给适当的控制器处理方法。还有事件监听器适配器,用于简化事件监听器的实现。

观察者模式 (Observer Pattern):

  • Spring事件驱动模型使用了观察者模式。开发者可以通过发布/订阅机制来解耦事件的发布者和监听者。比如ApplicationEventPublisher和ApplicationListener。

策略模式 (Strategy Pattern):

  • 在Spring中,许多地方都体现了策略模式的应用,比如ViewResolver用来解析逻辑视图名到实际视图的技术;TransactionManager定义了事务管理策略。

依赖注入 (Dependency Injection, DI):

  • 虽然DI不是严格意义上的设计模式,但它确实是Spring框架的核心概念之一。通过依赖注入,Spring实现了控制反转(IoC),使得组件之间的依赖关系由容器来管理而不是硬编码在组件内部。

责任链模式 (Chain of Responsibility Pattern):

  • 在Spring Security中,过滤器链就是一个责任链模式的应用实例,其中多个过滤器按顺序处理请求。

装饰器模式 (Decorator Pattern):

  • 在AOP中,当对方法进行增强时,实际上是创建了原始对象的一个装饰版本,添加新的行为而不改变原有对象的功能。

通过运用这些设计模式,Spring不仅提高了代码的灵活性、可维护性和可扩展性,同时也促进了良好的软件工程实践。

5.说说Spring 中 ApplicationContext 和 BeanFactory 的区别

ApplicationContext 和 BeanFactory 都是Spring框架中的核心接口,用于管理Bean的创建和生命周期。尽管它们提供了相似的功能,但在功能丰富性和应用场景上存在一些关键区别:

BeanFactory

  • 简单容器:BeanFactory 是一个基础的IoC容器,提供基本的依赖注入支持。
  • 懒加载:默认情况下,BeanFactory 按需实例化Bean,即只有在获取Bean时才进行实例化。
  • 资源消耗低:由于它不预加载所有Bean,因此启动速度较快,占用的内存也较少。
  • 功能有限:相比ApplicationContext,BeanFactory 提供的功能较为有限,主要用于简单的应用或嵌入式系统。

ApplicationContext

  • 高级容器:ApplicationContext 继承自BeanFactory,除了包含其所有功能外,还提供了更多企业级特性。
  • 自动加载:默认情况下,ApplicationContext 会在启动时预先实例化所有的单例Bean(可以通过设置来改变这一行为)。
  • 事件传播机制:实现了应用事件机制,允许监听器注册,并对发布的事件作出响应。
  • 国际化支持:支持国际化的MessageSource接口,可以用来解析用户界面使用的文本消息。
  • AOP支持:提供了对面向切面编程的支持,如通过代理实现声明式事务管理等功能。
  • 资源访问:简化了从各种资源位置(如文件系统、类路径等)读取资源的过程。
  • 更丰富的API:提供了更加丰富的API集,包括但不限于对注解的支持、环境抽象等。

使用场景

  • 如果你构建的是一个小型应用程序或者需要高度控制Bean实例化的时间点,那么BeanFactory可能是更好的选择。
  • 对于大多数Web应用和其他复杂的企业级应用来说,ApplicationContext 是更常见的选择,因为它提供了更多的功能和服务,有助于简化开发过程并提高生产力。

总的来说,ApplicationContext 更适合大多数现代Java应用程序的需求,因为它不仅包含了BeanFactory的所有功能,而且还增加了许多额外的功能以支持复杂的业务需求。