转载

Spring bean详细介绍

简而言之,Spring bean是 Spring框架在运行时管理对象 。Spring bean是任何Spring应用程序的 基本构建块 。您编写的大多数应用程序逻辑代码都将放在Spring bean中。

Spring bean的管理包括:

  • 创建一个对象
  • 提供依赖项(例如其他bean,配置属性)
  • 拦截对象方法调用以提供额外的框架功能
  • 销毁一个对象

Spring bean是框架的基本概念。作为Spring的用户,您应该对这个核心抽象有深刻的理解。

如何定义Spring bean?

如您所知,Spring负责创建bean对象。但首先,您需要告诉框架它应该创建哪些对象。

你是怎么做到的?

通过提供 bean定义

Bean定义告诉Spring框架应该将哪些类用作bean 。但那还不是全部。Bean定义就像食谱一样。它们还 描述了bean的属性 。我们将在本文后面讨论属性。但在我们进入之前,让我们关注bean的定义。

您可以通过 三种不同的方式 定义Spring bean:

  • 使用 构造@Component 注释(或其衍生物)注释您的类
  • 编写在自定义Java配置类中使用 @Bean 注释的bean工厂方法
  • 在XML配置文件中声明bean定义

在现代项目中,您将仅使用组件注释和bean工厂方法。如果涉及到XML配置,那么Spring现在主要允许它向后兼容。

bean定义方法之间选择 主要取决于对要用作Spring bean的类的源代码的访问。

Spring bean为@Component

如果您拥有源代码,则通常 直接在类上使用 @Component 注释。

@Component
<b>class</b> MySpringBeanClass {
    <font><i>//...</i></font><font>
}
</font>

在运行时,Spring会找到所有使用 @Component 或其派生类进行注释的 ,并将它们用作bean定义。查找带注释的类的过程称为 组件扫描

您可能想知道 @Component的 衍生物是什么。

@Conpontent衍生物是Spring构造型注释,它们本身用@Component注释。这个事实允许我们用它们代替 @Component

@Component 衍生列表包括:

  • @Service
  • @Repository
  • @Controller

注释之间的区别纯粹是信息性的 。它们允许您根据通用职责轻松 对bean进行分类 。您可以使用这些注释将bean类标记为特定应用程序层的成员,Spring框架会将它们全部视为 @Components

使用@Bean作为工厂方法

如果某个类属于某个外部库而您无法使用 @Component进行 注释,您必须在自定义bean的配置类中使用@  Bean 注释创建工厂方法。如果您不想使类依赖于Spring,您也可以将此选项用于您拥有的类。

这是一个带有单个bean工厂方法的示例配置类:

@Configuration
<b>class</b> MyConfigurationClass {
   
   @Bean
   <b>public</b> NotMyClass notMyClass() {
       <b>return</b> <b>new</b> NotMyClass();
   }
   
}

Spring使用工厂方法在运行时创建实际对象。如您所见,该方法只返回一个类的新实例。如果某个类属于某个外部库而您无法使用 @Component进行 注释,则使用 @Bean 创建工厂方法是唯一的选择。

@Configuration 注释也来自Spring。实际上,它是 @Component 的衍生物,但具有特殊用途。注释将类标记为@Bean定义的容器。您可以在单个配置类中编写多个工厂方法。

Spring bean属性

此时,您已经知道如何将类标记为Spring bean。下一步是学习如何自定义bean的功能。

无论您选择哪种bean定义方法,它们都允许描述同一组bean属性。属性提供有关Spring应 如何 创建对象的详细信息。

Spring bean属性列表包括:

  • 名称
  • 依赖
  • 范围
  • 初始化模式
  • 初始化回调
  • 破坏回调

为了简化bean定义,Spring为几乎所有属性提供了默认值。但是,了解如何自定义默认值非常重要。让我们逐个研究Spring bean属性。

1.Bean类

创建bean定义时,将其与应用程序中的单个 具体类 连接。这个类本身是bean的主要属性。

当Spring查找依赖项时,class属性是bean的默认标识符。这是否意味着您不能为单个类提供多个bean定义?不,这是可能的。但在这种情况下,为避免歧义,您应该使用另一个bean标识符:一个name名称。

2. Bean名称name

Spring bean名称是Spring用于 标识bean 的自定义字符串。与bean类不同,名称在整个应用程序中必须是 唯一 的。您不能定义两个具有相同名称的bean,即使它们的类型不同。

幸运的是,您不必为您创建的每个bean设置名称。Spring在运行时为其内部使用生成名称。除非您想按名称识别bean,否则可以安全地使用默认设置。

您需要使用bean名称的主要情况是为使用 @Bean 批注定义 的同一个类 提供了 几个bean 。在这种情况下, 名称允许您标识 要用作另一个bean的依赖项的 特定实例

3. 如何命名Spring bean?

使用 @Bean 批注的 name 属性。这是两个具有相同类型的bean的示例。

@Configuration
<b>class</b> MyConfigurationClass {
 
   @Bean(name = <font>"myBeanClass"</font><font>)
   MyBeanClass myBeanClass() {
       <b>return</b> <b>new</b> MyBeanClass();
   }
 
   @Bean(name = </font><font>"anotherMyBeanClass"</font><font>)
   MyBeanClass anotherMyBeanClass() {
       <b>return</b> <b>new</b> MyBeanClass();
   }
 
}
</font>

实际上,您不经常定义bean名称。对于单个类具有多个bean是相当罕见的情况。然而,如果能了解命名bean的各种可能性也是不错的。

4. Bean依赖项

用作bean的对象可以使用其他bean来执行其作业。当Spring创建一个定义某些依赖项的对象时,框架需要首先创建这些依赖项。这些依赖项也可以有自己的依赖项。

在面向对象的应用程序中,我们通常使用 相关对象巨大图表 。幸运的是,我们不必考虑如何构建此图。我们不必考虑应该创建对象的顺序。Spring为我们做了所有这些。

Spring对您的唯一期望是特定bean的依赖项列表。

5.如何定义bean依赖?

Bean依赖关系定义是一个复杂的主题,值得单独一篇文章。请考虑以下段落作为该主题的介绍。

当你有一个用 @Component 标记的 并且只有一个构造函数时,Spring使用构造函数参数列表作为必需依赖项列表。默认情况下,框架使用构造函数参数类型来提供适当的对象。

@Component
<b>class</b> BeanWithDependency {
 
   <b>private</b> <b>final</b> MyBeanClass beanClass;
 
   BeanWithDependency(MyBeanClass beanClass) {
       <b>this</b>.beanClass = beanClass;
   }
 
}

过去,我们在构造函数上使用 @Autowired 注释。但是,从Spring 4.3开始,如果只有一个构造函数,则不是强制性的。但是, 如果bean类定义了多个构造函数 ,则应使用 @Autowired 标记一个。这样Spring知道哪个构造函数包含bean依赖项列表。

出于同样的原因,bean工厂方法可以定义其依赖关系。Spring使用适当的对象调用方法。

@Bean
BeanWithDependency beanWithOptionalDependency(MyBeanClass beanClass) {
   <b>return</b> <b>new</b> BeanWithDependency(beanClass);
}

6. Bean作用域

Spring bean的范围定义了框架在运行时创建的特定类的 实例 数。作用域还描述 创建新对象的 条件

Spring为您的bean提供了几个作用域。框架的核心有两个:

  • 单例 - 单个实例
  • 原型 - 多个实例

此外,Spring还附带了专门用于Web应用程序的bean作用域:

  • 请求
  • 会话
  • 全局会话
  • 应用级别Application

所有bean的默认作用域是单例。 当bean具有单例作用域时,Spring只创建一个实例并在整个应用程序中共享它。单例是 无状态对象 的完美选择。如今,我们应用程序中的绝大多数bean都是无状态单例。

另一方面,如果对象包含状态,则应考虑其他作用域。要选择正确的一个,您应该问自己框架应该将该状态保留在内存中多长时间。但这是另一篇文章。

7. 如何设置作用域?

无论是使用 @Component 直接注释 还是使用 @Bean 创建工厂方法,该方法都是相同的。使用 @Scope 批注及其字符串属性选择范围。

@Component
@Scope(<font>"prototype"</font><font>)
<b>class</b> MyPrototypeClass {
    </font><font><i>//...</i></font><font>
}

@Bean
@Scope(</font><font>"prototype"</font><font>)
MyPrototypeClass myPrototypeClass() {
   <b>return</b> <b>new</b> MyPrototypeClass();
}
</font>

更重要的是,对于Web作用域,Spring附带了额外的别名注释。您可以使用这些注释代替 @Scope

  • @RequestScope
  • @SessionScope
  • @ApplicationScope

Bean初始化模式

当您的应用程序启动时,Spring会在启动时会立即创建所有单例bean。此默认行为允许我们快速检测bean定义中的错误。另一方面,立即性 eager bean初始化会使应用程序的启动变慢

幸运的是,您可以将bean的创建延迟到实际需要的时刻。您可以使用 @Lazy 注释执行此操作。

@Component
@Lazy
<b>class</b> MyLazyClass {
    <font><i>//...</i></font><font>
}
</font>

Bean初始化回调

一旦Spring根据bean定义创建新实例,您可能希望运行一些对象初始化逻辑。

如果此逻辑不依赖于框架,则可以在对象的构造函数中运行它。但是,为了确保在Spring初始化对象之后运行逻辑(例如,在可选的依赖注入之后),您应该使用初始化回调。

如何设置bean初始化回调?

如果使用 @Component 定义bean ,则有两个选项:

  • 使bean类实现 InitializingBean 。接口将强制您实现初始化方法。
  • 编写自定义初始化方法并使用 javax @PostContruct注释进行 标记。

在这两种情况下,Spring都会为您运行初始化回调。

用工厂方法定义的bean怎么样?

您可以使用 @Bean 及其名为 initMethod的 属性设置初始化回调。该属性需要一个具有初始化方法名称的字符串。

@Bean(initMethod = <font>"someInitMethodName"</font><font>)
MySpringBeanClass meBeanClass() {
   <b>return</b> <b>new</b> MySpringBeanClass();
}
</font>

有趣的是,用作 初始化回调 的方法 可以具有私有访问控制 。Spring使用反射机制来调用该方法。

Bean销毁回调

与初始化回调类似,您可以定义Spring销毁bean时应调用的方法。Predestroy回调的使用要少得多,但要注意它们的存在是很好的。

如何设置bean销毁回调?

同样,如果您可以访问bean类的源代码,则可以使用以下两个选项之一:

  • 实现 DisposableBean 接口。Spring使用其唯一的方法进行销毁回调。
  • 编写自定义方法并使用Javax API中的 @PreDestroy 注释它。

对于工厂方法,使用 @Bean 批注及其 destroyMethod 属性。

@Bean(name = <font>"myBeanClass"</font><font>, destroyMethod = </font><font>"cleanUpMethod"</font><font>)
MySpringBeanClass meBeanClass() {
   <b>return</b> <b>new</b> MySpringBeanClass();
}
</font>

Spring如何从bean定义创建对象?

当您启动Spring应用程序时,框架首先会创建一个名为ApplicationContext的特殊对象。ApplicationContext,也称为控制反转(IoC)容器,是 框架的核心

ApplicationContext是存在bean对象的容器。

上下文负责检测和读取Spring bean定义。一旦ApplicationContext加载了bean定义,它就可以根据提供的bean属性及其依赖关系开始为应用程序创建bean对象。

原文  https://www.jdon.com/51937
正文到此结束
Loading...