@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);
    }
}
复制代码
  • 启动结果

u()只被调用了一次。

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

  • 如果 Spring 版本在 5.2 以上,需要保证@ConfigurationproxyBeanMethods属性值为 true。

  • @Bean标注的方法是静态的。

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

与@Component使用

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

注意点3

ProductServiceImpl的创建移到 UserServiceImpl中。

@Bean
public static ProductServiceImpl p(){
	return new ProductServiceImpl();
}
复制代码

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: @Bean注解是Java Spring框架中的一个注解,用于在@Configuration类中声明一个方法,该方法将返回一个被Spring容器管理的Bean对象。\[1\]相比于其他注册Bean的注解@Bean注解的灵活性更高。因为它可以用在方法上,而不仅仅是类上,这意味着你可以在方法中使用条件语句或其他逻辑来动态获取Bean对象,使其能够根据环境的变化而变化。\[2\]此外,@Bean注解还可以用来提供Bean的详细描述,通过使用@Description注解来提供Bean的描述信息,使得对Bean的理解更加清晰。\[3\]总之,@Bean注解是Spring框架中用于声明和注册Bean的一种灵活且功能强大的注解。 #### 引用[.reference_title] - *1* [基于Java的容器注解@Bean](https://blog.csdn.net/wu631464569/article/details/51952787)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [对@Bean注解的学习理解(大白话解释)](https://blog.csdn.net/lzhNox/article/details/127780114)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [spring @Bean注解的使用](https://blog.csdn.net/weixin_30273763/article/details/97971121)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值