深入理解spring注解之@Bean注解

本文主要从以下几个方面来学习一下spring的注解@Bean:

  • 基于xml方式bean使用回顾

  • 注解@Bean详细使用说明

  • 注解@Bean的源码解析

     

1,基于xml方式bean使用回顾

 

新建一个maven项目增加spring-context的jar包如下:

 

 


        org.springframework
        spring-context
        4.3.16.RELEASE

 

 

定义一个user用户bean对象如下:

 

 

/**
 * 定义一个用户对象bean
 *
 * @author zhangqh
 * @date 2018年4月30日
 */
public class User {
    /**
     * 用户名
     */
    private String userName;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 省略 get set方法
     */
}

 

 

在src\main\resources目录下边新建一个beans.xml文件如下:

 

 



    
    
        
        
    

 

 

编写一个测试类如下:

 

 

/**
 * 测试类
 * @author zhangqh
 * @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的注册

 

3,注解@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销毁之后执行

 

 

说明已经成功了,over

 

原文地址:http://blog.51cto.com/4247649/2118356

 

你可能感兴趣的:(Spring,Boot,Spring/Spring,MVC)