在Spring框架中,有一个注解与众不同。
同样是声明bean实例,@Component、@Controller等注解是用在类上的,在Spring容器里完成实例化的。
而这个注解是用在方法上,在方法里由用户完成对象的实例化,最后交给Spring容器管理。而且这个注解还不能单独使用,和@Configuration搭配使用频率最高,它就是@Bean注解。
一、@Bean简介
@Bean是Spring框架 3.0 版本的一个注解,用于标识一个方法,该方法将返回一个由 Spring 管理的 Bean 对象。同时,被@Bean注解的方法只会被Spring容器识别一次。
在配置类中,通过在方法上标注 @Bean 注解,Spring 容器会在运行时调用该方法,并将方法返回的对象注册为一个 Bean。
通过 @Bean 注解,可以将自定义的对象纳入到 Spring 容器的管理范围内,从而可以享受 Spring 提供的依赖注入、AOP 等功能。
一般情况下,@Bean 注解可以与 @Configuration 注解一起使用,将一个类标识为配置类,并在该类中声明需要被 Spring 管理的 Bean 对象的创建方法。这些方法可以包含业务逻辑来创建 Bean 实例,并可以设置其属性、依赖关系等。
例如:
@Configurationpublic class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } // 其他@Bean方法...}
在上面的示例中,myService() 方法使用 @Bean 注解标注,Spring 容器会调用该方法并将其返回的 MyService 对象注册为一个 Bean。
二、@Bean的源码解读
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Bean {
/** * bean的名称,可以指定多个别名,默认为被注解的方法名(方法名首字母小写) */ @AliasFor("name") String[] value() default {};
/** * 同name */ @AliasFor("value") String[] name() default {};
/** * 是否自动装配,默认false,从5.1版本这个字段就作废 * @deprecated as of 5.1 */ @Deprecated Autowire autowire() default Autowire.NO;
/** * * @since 5.1 */ boolean autowireCandidate() default true;
/** * 初始化方法 * @see org.springframework.beans.factory.InitializingBean * @see org.springframework.context.ConfigurableApplicationContext#refresh() */ String initMethod() default "";
/** * 销毁方法 * @see org.springframework.beans.factory.DisposableBean * @see org.springframework.context.ConfigurableApplicationContext#close() */ String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
value:bean名称,可以指定多个,默认为注解的方法名称;
name:bean名称,同value;
autowire:自定装配默认不开启,在5.1版本作废;
initMethod:bean的初始化方法;作用同InitializingBean接口的afterPropertiesSet 方法。
destroyMethod:默认使用 javaConfig 配置的bean,如果存在 close 或者 shutdown 方法,则在 bean 销毁时会自动执行该方法,如果不想执行该方法,则不要在对象中定义close 或者 shutdown 方法,或者将该值设置为空。
@Bean注解可以注解在方法上,也可以注解在其他注解上,其他注解也必须在方法上。
三、@Bean注解的应用
1、创建一个对象MyBean备用
2、在配置文件中配置bean,3种方式
/** * 在配置文件中配置bean,3种方式 * @author * @date 2024年4月19日 * @Description * */@Configurationclass MyConfig{ // 1、创建一个以方法命令的bean @Bean public MyBean myBean() { return new MyBean(); } // 2、创建一个有别名的bean @Bean(name={"b1","b2"},autowireCandidate=false) public MyBean myBean1() { return new MyBean(); } // 3、bean注解的完整使用 @Bean(value={"b3","b4"},autowireCandidate=false,initMethod="init",destroyMethod="close") public MyBean myBean2() { return new MyBean(); }}
3、测试代码
import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @Bean使用测试代码*/public class SpringApp2 { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); // 1、通过class获取bean实例 MyBean myBean = context.getBean(MyBean.class); System.out.println("myBean:" + myBean); // 2、通过别名获取bean实例 myBean = (MyBean) context.getBean("b1"); System.out.println("b1:" + myBean); myBean = (MyBean) context.getBean("b2"); System.out.println("b2:" + myBean); // 3、完整@Bean注解的应用 myBean = (MyBean) context.getBean("b3"); System.out.println("b3:" + myBean); myBean = (MyBean) context.getBean("b4"); System.out.println("b4:" + myBean); myBean.fun(); // 关闭上下文,调用销毁方法 context.close(); }}
在上面的示例中,我们使用三种方式创建同一个对象的bean。
第一种bean的名称默认,也就是使用方法名作为bean的名称。
第二种,给bean起两个别名b1,b2。
第三种,给bean起两个别名b3,b4,并且把bean中的属性都设置了一遍。
4、运行结果
执行结果,和网上有些文章里写的不一样。
也就是第二种方式中,很多文章里都说这个bean有三个名称:b1、b2和方法名,但实际上只有两个指定的bean名称,两个名称指向同一个实例。因此只要设置了name或value,就会覆盖默认的方法名作为bean的名称。
最后容器关闭时,销毁方法被调用了三次,因为前面配置了三个bean。
当然除此之外,@Bean还可以和Scope、DependsOn、Lazy、Primary等搭配使用,这里就不演示了。
领取专属 10元无门槛券
私享最新 技术干货