@Bean注解详解

Posted zensezz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@Bean注解详解相关的知识,希望对你有一定的参考价值。

@Bean注解详解

Bean 用法

@Bean表示方法产生一个由Spring管理的bean,属性的名称语义与Spring XML中的<bean> 标签配置的一样

 public MyBean myBean() {
        // instantiate and configure MyBean obj
        return obj;
      }

当使用name属性可用时,用于确定bean名称的默认策略是使用方法的名称。
这是方便和直观的,但是如果需要显式命名,则可以在注解上使用 name 属性(或其别名{value})。

另请注意 name接受一个字符串数组,允许为单个bean使用多个名称(即主bean名称加上一个或多个别名)。

      @Bean({"b1", "b2"}) // bean available as \'b1\' and \'b2\', but not \'myBean\'
     public MyBean myBean() {
        // instantiate and configure MyBean obj
         return obj;
     }
Bean 增强

@Bean注释不提供Profile, Scope, Lazy, DependsOn, Primary, Order功能

意思是,如果要在bean上配置Profile, Scope, Lazy, DependsOn, Primary, Order这些的时候,不再是用属性了,而是在该bean上使用它们对应的注解

@Bean
@Profile("production")
@Scope("prototype")
@Order(-100)
public MyBean myBean() {
    // instantiate and configure MyBean obj
    return obj;
}

上述注释的语义与它们在组件类级别的用法相匹配:

  1. @Profile 允许选择性地包含某些bean。
  2. @Scope 将bean的范围从单例更改为指定的范围。
  3. @Lazy 仅在默认单例作用域的情况下才具有实际效果。
  4. @DependsOn 会在创建此bean之前强制创建特定的其他bean,以及该bean通过直接引用表示的任何依赖关系,这通常对单例启动很有帮助。
  5. @Primary 是一种在注入点级别解决歧义的机制如果需要注入单个目标组件,但多个bean按类型匹配,
    如果需要注入单个目标组件,但多个Bean按类型匹配
    • @Order;@Bean 方法还可以声明限定符批注和 @Order,在注入点解析期间要像相应的那样考虑相应组件类上的注释,但每个bean定义可能非常个别(在具有相同 bean类的多个定义的情况下)。在初始类型匹配之后,order的值会缩小候选集的范围;order值确定在收集情况下解析元素的顺序注入点(通过类型和限定符匹配多个目标bean。
    • @Order 值可能会影响注入点的优先级,但请注意,它们不会影响单例启动顺序,这是依赖关系和 @DependsOn 声明,另外,javax.annotation.Priority 在此级别上不可用,因为它不能在方法上声明。它的语义可以通过 @Order 值与 @Primary 结合使用,以对每种类型的单个bean进行调整。
@Bean使用场景

通常, @Bean方法在@Configuration 类中声明。因此,在此模式下,不能将 @Configuration类及其工厂方法标记为final或private。在这种情况下,bean方法可以直接调用来引用同一类中的其他 @Bean方法。
这样可以确保bean 之间的引用是强类型的且可传导的。保证了这样的bean间引用 像getBean()查找一样,加强作用域和AOP语义。这些是从原始 “ Spring JavaConfig”项目中所知道的语义,这些语义要求在运行时将每个此类配置类的CGLIB子类化。

@Configuration
public class AppConfig {
   @Bean
    public FooService fooService() {
        return new FooService(fooRepository());
    }
    @Bean
    public FooRepository fooRepository() {
        return new JdbcFooRepository(dataSource());
    }
    // ...
}

注意:

  • @Bean 方法也可以在用 @Configuration注释的类中声明。
    例如,可以在 @Component 类中甚至在其他类中将bean方法声明为。
    在这种情况下, @Bean方法将以所谓的lite模式进行处理。
  • bean 容器中将 lite模式下的 Bean方法视为普通的工厂方法(类似于XML中的 factory-method声明),适当地应用范围和生命周期回调。在这种情况下,包含的类保持不变,并且对于包含类或工厂方法没有异常约束。
  • 与 @Configuration类中bean方法的语义相反,在lite模式下不支持 bean间引用 。相反,当一个 @Bean方法以lite模式调用另一个@Bean方法时,该调用是标准的Java方法调用;Spring不会通过CGLIB代理拦截调用。这类似于内部 @Transactional方法调用,然而在代理模式下,Spring不会拦截调用;但是仅在AspectJ模式下,Spring会拦截调用。如下
@Component
public class Calculator {
    public int sum(int a, int b) {
        return a+b;
    }
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}
@Bean 与 BeanFactoryPostProcessor(BFPP)

对于返回Spring org.springframework.beans.factory.config.BeanFactoryPostProcessor.BeanFactoryPostProcessor()类型的 @Bean方法,必须特别注意。由于BFPP对象必须在容器生命周期的早期进行实例化,因此它们可能会干扰内部的 @Autowired,@Value和 @PostConstruct 等批注的处理。@Configuration 类。为了避免这些生命周期问题,请将BFPP-返回的 @Bean方法标记为static。例如:

 @Bean
 public static PropertySourcesPlaceholderConfigurer pspc() {
     // instantiate, configure and return pspc ...
 }

BeanFactoryPostProcessor.通过将此方法标记为static,可以在不引发其声明 @Configuration类的实例的情况下调用该方法,从而避免了上述生命周期冲突。但是请注意,如上所述,对于范围界定和AOP语义,static 下的@Bean方法不会得到增强。 BFPP情况下可行,因为其他@Bean方法通常不引用它们,将为具有返回类型可分配给 BeanFactoryPostProcessor的任何非静态 @Bean方法发出WARN级别的日志消息

@Bean的方法
  • value()
/**
 * Alias for {@link #name}.
 * <p>Intended to be used when no other attributes are needed, for example:
 * {@code @Bean("customBeanName")}.
 * @since 4.3.3
 * @see #name
 */
@AliasFor("name")
String[] value() default {};
  • name()

Bean的名称,如果有多个名称,则为主Bean名称加别名。如果未指定,则Bean的名称为带注释的方法的名称。如果指定方法名称将被忽略。 如果未声明其他属性,也可以通过value属性配置bean名称和别名

/**
 * The name of this bean, or if several names, a primary bean name plus aliases.
 * <p>If left unspecified, the name of the bean is the name of the annotated method.
 * If specified, the method name is ignored.
 * <p>The bean name and aliases may also be configured via the {@link #value}
 * attribute if no other attributes are declared.
 * @see #value
 */
@AliasFor("value")
String[] name() default {};
  • autowire()

是否通过名称或类型通过基于约定的自动装配来注入依赖项? 注意,这种自动装配模式只是基于约定的基于bean属性设置器方法的外部驱动自动装配,类似于XML bean定义。默认模式确实允许注释驱动的自动装配。 “ no”仅指外部驱动的自动装配,不影响bean类本身通过注释表示的任何自动装配要求。Spring5.1弃用,因为 @Bean工厂方法参数解析和 @Autowired处理取代了基于名称/类型的bean属性注入

/**
 * Are dependencies to be injected via convention-based autowiring by name or type?
 * <p>Note that this autowire mode is just about externally driven autowiring based
 * on bean property setter methods by convention, analogous to XML bean definitions.
 * <p>The default mode does allow for annotation-driven autowiring. "no" refers to
 * externally driven autowiring only, not affecting any autowiring demands that the
 * bean class itself expresses through annotations.
 * @see Autowire#BY_NAME
 * @see Autowire#BY_TYPE
 * @deprecated as of 5.1, since {@code @Bean} factory method argument resolution and
 * {@code @Autowired} processing supersede name/type-based bean property injection
 */
@Deprecated
Autowire autowire() default Autowire.NO;
  • autowireCandidate()

此bean是否适合自动连接到其他bean? 默认为true;对于内部代理,请将其设置为false,而不是要在其他地方出现相同类型的Bean。

/**
 * Is this bean a candidate for getting autowired into some other bean?
 * <p>Default is {@code true}; set this to {@code false} for internal delegates
 * that are not meant to get in the way of beans of the same type in other places.
 * @since 5.1
 */
boolean autowireCandidate() default true;
  • initMethod()

    初始化期间要在Bean实例上调用的方法的可选名称。鉴于可以在Bean注释方法的主体内直接以编程方式调用该方法,因此不常用。默认值为“”(空字符串),表示没有要调用的初始化方法。

/**
 * The optional name of a method to call on the bean instance during initialization.
 * Not commonly used, given that the method may be called programmatically directly
 * within the body of a Bean-annotated method.
 * <p>The default value is {@code ""}, indicating no init method to be called.
 * @see org.springframework.beans.factory.InitializingBean
 * @see org.springframework.context.ConfigurableApplicationContext#refresh()
 * 初始化期间要在Bean实例上调用的方法的可选名称。
 * 鉴于可以在Bean注释方法的主体内直接以编程方式调用该方法,因此不常用。
 * 默认值为“”(空字符串),表示没有要调用的初始化方法。
 */
String initMethod() default "";
  • destroyMethod

    关闭应用程序上下文时要在Bean实例上调用的方法的可选名称,例如JDBC DataSource实现上的 close()方法或Hibernate SessionFactory对象。该方法必须没有参数,但可以引发任何异常。为方便用户,容器将尝试针对 @Bean方法返回的对象推断一个destroy方法。例如,给定一个 @Bean方法返回一个Apache Commons DBCP 的 BasicDataSource,则容器将注意到该对象上的 close()方法可用,并自动将其注册为 destroyMethod 。目前,这种“销毁方法推断”仅限于检测名为“ close”或“ shutdown”的公共无参数方法。可以在继承层次结构的任何级别上声明该方法,并且无论 @Bean方法的返回类型如何,都将检测该方法(即,检测是在创建时针对bean实例自身进行反射性发生的)。要为特定的 @Bean禁用destroy方法推断,请指定一个空字符串作为值,例如 @Bean(destroyMethod =“”)。注意, org.springframework.beans.factory.DisposableBean回调接口仍然会被检测到,并调用相应的destroy方法:换句话说,code destroyMethod =“”仅影响自定义关闭/关闭方法,而 java.io.Closeable/ java.lang.AutoCloseable声明了close方法。
    注意:仅在生命周期在工厂的完全控制下的bean上调用,对于单例来说总是这样,但对于任何其他范围都不能保证。

/**
 * The optional name of a method to call on the bean instance upon closing the
 * application context, for example a {@code close()} method on a JDBC
 * {@code DataSource} implementation, or a Hibernate {@code SessionFactory} object.
 * The method must have no arguments but may throw any exception.
 * <p>As a convenience to the user, the container will attempt to infer a destroy
 * method against an object returned from the {@code @Bean} method. For example, given
 * an {@code @Bean} method returning an Apache Commons DBCP {@code BasicDataSource},
 * the container will notice the {@code close()} method available on that object and
 * automatically register it as the {@code destroyMethod}. This \'destroy method
 * inference\' is currently limited to detecting only public, no-arg methods named
 * \'close\' or \'shutdown\'. The method may be declared at any level of the inheritance
 * hierarchy and will be detected regardless of the return type of the {@code @Bean}
 * method (i.e., detection occurs reflectively against the bean instance itself at
 * creation time).
 * <p>To disable destroy method inference for a particular {@code @Bean}, specify an
 * empty string as the value, e.g. {@code @Bean(destroyMethod="")}. Note that the
 * {@link org.springframework.beans.factory.DisposableBean} callback interface will
 * nevertheless get detected and the corresponding destroy method invoked: In other
 * words, {@code destroyMethod=""} only affects custom close/shutdown methods and
 * {@link java.io.Closeable}/{@link java.lang.AutoCloseable} declared close methods.
 * <p>Note: Only invoked on beans whose lifecycle is under the full control of the
 * factory, which is always the case for singletons but not guaranteed for any
 * other scope.
 * @see org.springframework.beans.factory.DisposableBean
 * @see org.springframework.context.ConfigurableApplicationContext#close()
 */
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;

以上是关于@Bean注解详解的主要内容,如果未能解决你的问题,请参考以下文章

2) SpringBootApplication注解详解

Spring之@Bean注解详解

Java开发Spring之IOC详解第二篇(注解开发JdbcTemplatem模板Junit整合)

(转)java之Spring(IOC)注解装配Bean详解

SpringBoot - @Bean注解详解

被各种注解搞晕了?那快来看看Spring Bean注解详解!