@Bean 注解

简介: @Bean 注解
日积月累,水滴石穿 😄

前言

@Bean 是一个应用在方法(还可以用在注解上)上的注解,被 @Bean标注的方法会生成一个由 Spring 容器管理的 bean。

@Bean 与 xml 文件中的 <bean/> 标签等同,@Bean需要和@Component或者 @Configuration一同使用,通常是和 @Configuration(可以想一想),如下:

@Configuration
public class BeanConfig {
    @Bean
    public UserServiceImpl u(){
        return new UserServiceImpl();
    }
}

源码定义

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {

    // name的别名,在无其他属性的情况下,可以如下写法指定 beanName
    // @Bean("u")
    @AliasFor("name")
    String[] value() default {};

    //指定 beanName,如果不指定时,采用方法名称为 beanName
    //如果指定多个,第一个名称为 beanName,其余为 别名
    @AliasFor("value")
    String[] name() default {};

    /**
     * 装配的方式,有三个选项
     * Autowire.NO (默认设置)
     * Autowire.BY_NAME:根据 beanName
     * Autowire.BY_TYPE:根据Class类型
     * 一般不设置,采用默认即可,而且该属性已经被放弃,不介意使用
     */
    @Deprecated
    Autowire autowire() default Autowire.NO;

    //该 bean 是否可以自动装配到其他 bean 中,默认为 true
    // 如果为 false,代表其他 bean,不能进行注入该bean
    boolean autowireCandidate() default true;

    // bean 的初始化方法, 直接指定方法名称,不用带括号
    // 默认值为 "",表示不调用初始化方法
    String initMethod() default "";

    //指定销毁方法
    String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;

}

举例

value

public class UserServiceImpl {
}

@Bean({"u1","u2"})  // beanName 为 u1,别名为u2
public UserServiceImpl u(){
    return new UserServiceImpl();
}

autowireCandidate

autowireCandidate属性设置为 false,在 ProductServiceImpl类中使用 @Autowired进行注入,这时会报错。

@Bean(name = {"u1","u2"},autowireCandidate = false)
public UserServiceImpl u(){
    return new UserServiceImpl();
}

@Component
public class ProductServiceImpl {

    @Autowired
    private UserServiceImpl userService;
}

initMethod

指定初始化方法,initMethod2

@Bean(name = {"u1","u2"},initMethod = "initMethod2")
public UserServiceImpl u(){
    return new UserServiceImpl();
}

UserServiceImpl类中添加 initMethod2方法。

public void initMethod2(){
    System.out.println("UserServiceImpl = initMethod2");
}

destroyMethod

指定销毁方法,destroyMethod2

@Bean(name = {"u1","u2"},initMethod = "initMethod2",destroyMethod = "destroyMethod2")

UserServiceImpl类中添加 destroyMethod2方法。

public void destroyMethod2(){
    System.out.println("UserServiceImpl = destroyMethod2");
}

在容器停止时,会调用 destroyMethod2方法。不过,只是有单例 bean 才会调用该方法,如果是其他作用域,不会调用该方法。如果你在 UserServiceImpl中添加了名为“close”或“shutdown”的公共、无参数方法,即使你不指定 destroyMethod属性,也会被调用,如果想禁用,请将destroyMethod 属性值设置为 ""。

@ComponentScan(basePackages = "com.cxyxj.beandemo")
public class AppMain {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppMain.class);

        // 打印 bean 名称
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String name : beanDefinitionNames){
            System.out.println(name);
        }
        //根据 beanName 获得别名
        String[] u1s = context.getAliases("u1");
        System.out.println("别名" + Arrays.asList(u1s));
        // 关闭容器
        context.close();
    }
}

注意点

注意点 1

发现@Bean的源码定义中并没有环境激活、懒加载、作用域、是否首选Bean、依赖的设置,它应该和@Profile@Lazy @Scope@DependsOn@Primary 一起使用来声明。

  • @Profile:指定Bean在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个Bean。
  • @Scope将 bean 的范围从单例更改为指定范围。
  • @Lazy只有在默认单例范围的情况下才有实际效果。
  • @DependsOn强制在创建此 bean 之前创建特定的其他 bean。
  • @Primary指示当多个候选者有资格自动装配依赖项时,应优先考虑该bean

注意点2

开篇讲到@Bean需要和@Component或者 @Configuration一同使用,通常使用 @Configuration。这两者之间有什么区别呢?

与@Configuration使用

@Configuration
public class BeanConfig {

    @Bean(name = {"u1","u2"})
    public UserServiceImpl u(){
        UserServiceImpl userService = new UserServiceImpl();
        System.out.println("userService = " + userService);
        return userService;
    }

    @Bean
    public ProductServiceImpl p(){
        u();
        return new ProductServiceImpl();
    }
}
  • 启动类
@ComponentScan(basePackages = "com.cxyxj.beandemo")
public class AppMain {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppMain.class);
    }
}
  • 启动结果

image.png

u()只被调用了一次。

那什么情况下会被都用两次呢?

  • 如果 Spring 版本在 5.2 以上,需要保证@ConfigurationproxyBeanMethods属性值为 true。
  • @Bean标注的方法是静态的。

结果如下,每调用一次 u() 方法都会产生新的实例。

image.png

与@Component使用

image.png
不允许直接调用带有 @Bean 注解的方法。 需要使用依赖注入的方式。

注意点3

ProductServiceImpl的创建移到 UserServiceImpl中。

@Bean
public static ProductServiceImpl p(){
    return new ProductServiceImpl();
}

这时候 ProductServiceImpl不能注入到容器中。这是因为 Spring 做了限制,被 @Bean 注入的Bean,不能在内部使用创建Bean的功能。 比如:@Bean、@Import。


  • 如你对本文有疑问或本文有错误之处,欢迎评论留言指出。如觉得本文对你有所帮助,欢迎点赞和关注。
相关文章
|
XML Java 数据格式
基于注解管理bean~
基于注解管理bean~
|
6月前
|
Java 数据库连接 数据库
什么时候用@MapperScan 注解?
什么时候用@MapperScan 注解?
198 0
|
6月前
|
安全 前端开发 Java
注解的使用
注解的使用
64 0
|
XML 设计模式 Java
什么是bean
什么是bean
451 0
|
XML Java 测试技术
Bean的自动装配
- 自动装配Spring满足bean依赖一种方式! - Spring会在上下文中自动寻找,并自动给Bean装配属性
|
Java 编译器
关于@FunctionalInterface注解
FunctionalInterface
460 0
关于@FunctionalInterface注解
|
开发框架 Java Spring
Spring - 属性注入之注解(@Autowired、@Qualifier、@Resource)
Spring - 属性注入之注解(@Autowired、@Qualifier、@Resource)
259 0
Spring - 属性注入之注解(@Autowired、@Qualifier、@Resource)
|
XML Dubbo Java
duboo注解使用详解
当越来越的的接口与实现类的增加后,duboo的xml配置会越来越多,为了防止几百几千行的代码,减少开发人员配置xml的工作量,使用duboo的注解模式,减少配置多出问题多的可能性!
170 0
duboo注解使用详解
|
Java 程序员 开发工具
扒一扒@Retryable注解,很优雅,有点意思! (1)
扒一扒@Retryable注解,很优雅,有点意思! (1)
374 0
扒一扒@Retryable注解,很优雅,有点意思! (1)