@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名
1 基于xml方式bean使用回顾
2 注解@Bean详细使用说明
3 注解@Bean的源码解析
1,基于xml方式bean使用回顾
新建一个maven项目增加spring-context的jar包如下:
定义一个user用户bean对象如下:
/**
* 定义一个用户对象bean
*
* @date 2018年4月30日
*/
public class User {
/**
* 用户名
*/
private String userName;
/**
* 年龄
*/
private Integer age;
/**
* 省略 get set方法
*/
}
在src\main\resources目录下边新建一个beans.xml文件如下:
编写一个测试类如下:
/**
* 测试类
* @date 2018年4月30日
*/
public class ApplicationTest {
@SuppressWarnings("resource")
public static void main(String[] args) {
// 使用ClassPathXmlApplicationContext获取spring容器ApplicationContext
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// 根据bean id获取bean对象
User bean = (User) applicationContext.getBean("user");
System.out.println(bean);
}
}
运行结果如下:
User [userName=zhangsan, age=26]
2,注解@Bean详细使用说明
以上的例子这边再用注解来实现一次,首先定义一个注解配置文件如下:
/**
* 定义一个注解配置文件 必须要加上@Configuration注解
*
* @author zhangqh
* @date 2018年4月30日
*/
@Configuration
public class MainConfig {
/**
* 定义一个bean对象
* @return
*/
@Bean
public User getUser(){
return new User("zhangsan",26);
}
}
在以上测试类中增加注解的测试代码如下:
// 使用AnnotationConfigApplicationContext获取spring容器ApplicationContext2
ApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
User bean2 = applicationContext2.getBean(User.class);
System.out.println(bean2);
运行结果如下:
User [userName=zhangsan, age=26]
到此我们用注解@Bean也同样实现了和xml一样bean的注册
首先我们看一下@Bean注解的源代码如下:
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
Autowire autowire() default Autowire.NO;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
我们发现@baen注解的@Target是ElementType.METHOD,ElementType.ANNOTATION_TYPE也就说@Bean注解可以在使用在方法上,以及一个注释类型声明,具体注解详细说明可以查看之前写的一篇文章深入理解java注解的实现原理
具体参数如下:
value -- bean别名和name是相互依赖关联的,value,name如果都使用的话值必须要一致
name -- bean名称,如果不写会默认为注解的方法名称
autowire -- 自定装配默认是不开启的,建议尽量不要开启,因为自动装配不能装配基本数据类型、字符串、数组等,这是自动装配设计的局限性,以及自动装配不如显示依赖注入精确
initMethod -- bean的初始化之前的执行方法,该参数一般不怎么用,因为可以完全可以在代码中实现
destroyMethod -- bean销毁执行的方法
下面来演示几个配置:为user用户bean增加注解名称如下:
@Bean(value="user0",name="user0")
打印所有的bean名称如下:
String[] namesForType = applicationContext.getBeanNamesForType(Person.class);
for (String name : namesForType) {
System.out.println("bean名称为==="+name);
}
bean名称为===mainConfig
bean名称为===user0
如果value和name内容不一样如:
@Bean(value="user0",name="user1")
Exception in thread "main" org.springframework.core.annotation.AnnotationConfigurationException: In AnnotationAttributes for annotation [org.springframework.context.annotation.Bean] declared on public com.zhang.bean.User com.zhang.config.MainConfig.getUser(), attribute 'name' and its alias 'value' are declared with values of [{user1}] and [{user0}], but only one is permitted.
at org.springframework.core.annotation.AnnotationUtils.postProcessAnnotationAttributes(AnnotationUtils.java:1301)
at org.springframework.core.annotation.AnnotatedElementUtils.getMergedAnnotationAttributes(AnnotatedElementUtils.java:394)
at org.springframework.core.type.StandardMethodMetadata.getAnnotationAttributes(StandardMethodMetadata.java:124)
at org.springframework.context.annotation.AnnotationConfigUtils.attributesFor(AnnotationConfigUtils.java:280)
at org.springframework.context.annotation.AnnotationConfigUtils.attributesFor(AnnotationConfigUtils.java:276)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:187)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:140)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:116)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:320)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:228)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:272)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:92)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:687)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:525)
at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84)
at com.zhang.ApplicationTest.main(ApplicationTest.java:26)
报错如上
在用户bean中增加初始化和销毁的方法如下:
public void initUser(){
System.out.println("初始化用户bean之前执行");
}
public void destroyUser(){
System.out.println("bean销毁之后执行");
}
注解如下:
@Bean(value="user0",name="user0",initMethod="initUser",destroyMethod="destroyUser")
运行如下:
初始化用户bean之前执行
User [userName=张三, age=26]
发现销毁方法没有执行,原因是bean销魂之前程序已经结束了,可以手动close下如下:
AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainConfig.class);
User bean2 = applicationContext2.getBean(User.class);
System.out.println(bean2);
// 手动执行close方法
applicationContext2.close();
运行结果如下:
初始化用户bean之前执行
User [userName=张三, age=26]
bean销毁之后执行