Spring Bean基础
1.定义Spring Bean
BeanDefinition是Spring Framework中定义Bean配置的元信息接口,包含:
- Bean的类名
 - Bean的行为配置,如作用域、自动绑定的模式、生命周期回调等
 - 其他Bean的引用,又可称为合作者(Colloborators)或者依赖(Dependency)
 - 配置设置,比如Bean属性(Properties)
2.BeanDefinition元信息
 
| BeanDefinition元信息 | |
|---|---|
| 属性 | 说明 | 
| Class | Bean全类名,必须是具体类,不能使用抽象类或接口 | 
| Name | Bean的名称或ID | 
| Scope | Bean的作用域(如Sigleton、Prototype) | 
| Constructor arguments | Bean构造器参数(用于依赖注入) | 
| Properties | Bean的属性设置(用于依赖注入) | 
| Autowiring mode | Bean自动绑定模式(如:通过名称 ByName) | 
| Lazy initislization mode | Bean延迟初始化模式(延迟和非延迟) | 
| Initialization method | Bean 初始化回调方法名称 | 
| Destruction method | Bean销毁回调方法名称 | 
BeanDefinition构建:
- 通过BeanDefinitionBuilder
 - 通过AbstractBeanDefinition以及派生类
| BeanDefinition接口及其实现类 |
| —- |
| 
 | 
public class BeanDefinitionDemo {public static void main(String[] args) {//1、通过 BeanDefinitionBuilder 构建 BeanDefinitionBeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);beanDefinitionBuilder.setScope("singleton").addPropertyValue("id", 1).addPropertyValue("name", "黑岩射手");AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();//2、通过AbstractBeanDefinition以及派生类AbstractBeanDefinition abstractBeanDefinition = new GenericBeanDefinition();abstractBeanDefinition.setBeanClass(User.class);abstractBeanDefinition.setScope("singleton");abstractBeanDefinition.setPropertyValues(new MutablePropertyValues().add("id", 2).add("name", "Dead Master"));}}
3.命名Spring Bean
Bean的名称
- 每个Bean拥有一个或多个标识符(identifiers),这些标识符在Bean所在的容器必须是唯一的。通常,一个Bean仅有一个标识符,如果需要额外的,可考虑使用别名(Alias)来扩充。
 - 在基于XML的配置元信息中,开发人员可用id或者name属性来规定Bean的标识符。通常Bean的标识符由字母组成,允许出现特殊字符。如果要想引入Bean的别名的话,可在name属性使用半角逗号(“,”)或分号(“;”)来间隔。
 - Bean的id或name属性并非必须制定,如果留空的话,容器会为Bean自动生成一个唯一的名称。Bean的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合Java的命名约定。
 
Bean的名称命名底层实现
Bean名称生成器(BeanNameGenerator)由Spring Framework 2.0.3引入,框架內建两种实现:
- DefaultBeanNameGenerator:默认通用BeanNameGenerator实现
 - AnnotationBeanNameGenerator:基于注解扫描的BeanNameGenerator实现,起始于Spring
| BeanNameGenerater接口及其实现 |
| —- |
| 
 | 
4.SpringBean的别名
Bean别名(Alias)的价值
- 复用现有的BeanDefinition
 - 更具有场景化的命名方法,比如:
```xml 
 
```javapublic class BeanAliasDemo {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:META-INF/spring-bean-definition.xml");// 根据Bean别名查找BeanUser blackRockShooter = (User) applicationContext.getBean("blackRockShooter");// 根据Bean名称查找BeanUser user = (User) applicationContext.getBean("user");System.out.println(blackRockShooter==user); //true}}
5.注册Spring Bean
BeanDefinition注册
- XML配置元信息
 - Java注解配置元信息
- @Bean
 - @Component
 - @Import
 
 - Java API配置元信息
- 命名方式:BeanDefinitionRegistry#registerBeanDefinition(String,BeanDefinition)
 - 非命名方式:
- BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDe
finitionRegistry) 
 - BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition,BeanDe
 - 配置类方式:AnnotatedBeanDefinitionReader#register(Class…) ```java /**
 
 
{@link Import}注解注册Bean */ @Import(AnnotationBeanDefinitionDemo.Config.class) public class AnnotationBeanDefinitionDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.register(Config.class);
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(User.class)
            .addPropertyValue("id", 1)
            .addPropertyValue("name", "逢坂大河")
            .getBeanDefinition();
    // java API 方式注册Bean —— 命名方式
    applicationContext.registerBeanDefinition("tiger", beanDefinition);
    // java API 方式注册Bean —— 非命名方式
    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, applicationContext);
    // 配置类方式 AnnotatedBeanDefinitionReader#registerBean
    AnnotatedBeanDefinitionReader annotatedBeanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
    annotatedBeanDefinitionReader.registerBean(Config.class);
    // 启动容器
    applicationContext.refresh();
    applicationContext.getBeansOfType(User.class).forEach((beanName, user) -> System.out.println(beanName + " : " + user));
    System.out.println(applicationContext.getBean(Config.class).getUser(3, "魔法小樱"));
}
/**
 * {@link Component} 注解注册Bean
 */
@Component
public static class Config {
    /**
     * {@link Bean} 注解方式注册Bean
     */
    @Bean
    public User user() {
        return new User(2, "black-rock-shooter");
    }
    public User getUser(int id, String name) {
        return new User(id, name);
    }
}
} ``` 外部单例对象注册
Java API配置元信息
常规方式
- 通过构造器(配置元信息:XML、Java注解和Java API)
 - 通过静态工厂方法(配置元信息:XML和Java API)
 - 通过Bean工厂方法(配置元信息:XML和Java API)
 - 通过FactoryBean(配置元信息:XML、Java注解和Java API)
 
特殊方式
@PostConstruct标注方法
- 实现InitializingBean接口的afterPropertiesSet()方法
 - 自定义初始化方法
- XML配置:
 - Java注解:@Bean(initMethod=”init”)
 - Java API:AbstractBeanDefinition#setInitMethodName(String)
 
 - XML配置:
 
初始化回调方法执行顺序:
- 调用@PostConstruct注释的方法
 - 调用实现InitializingBean回调接口定义的afterPropertiesSet()方法
 - 调用一个自定义配置的init()方法
8.延迟初始化Spring Bean
Bean延迟初始化(Lazy Initialization) 
- XML配置:
 - Java注解:@Lazy(true
 
9.销毁Spring Bean
Bean销毁(Destroy)
- @PreDestroy标注方法
 - 实现DisposableBean接口的destroy()方法
 - 自定义销毁方法
- XML配置:
 - Java注解:@Bean(destroy=”destroy”)
 - Java API:AbstractBeanDefinition#setDestroyMethodName(String
 
 - XML配置:
 
销毁回调方法执行顺序:
- 调用@PreDestroy注释的方法
 - 调用实现DisposableBean回调接口的destroy()方法
 - 
10.垃圾回收Spring Bean
Bean垃圾回收(GC)
 关闭Spring容器(应用上下文)
- 执行GC
 - Spring Bean覆盖的finalize()方法被回调
11.面试题精选
 
- 如何注册一个Spring Bean?
 
答:通过BeanDefinition和外部单体对象来注册
- 什么是Spring BeanDefinition?
 
BeanDefinition是Spring Framework中定义Bean配置的元信息接口,包含:
- Bean的类名
 - Bean的行为配置,如作用域、自动绑定的模式、生命周期回调等
 - 其他Bean的引用,又可称为合作者(Colloborators)或者依赖(Dependency)
 - 配置设置,比如Bean属性(Properties)
- Spring容器是怎样管理注册Bean
 
 
IoC配置元信息读取和解析、依赖查找和注入以及Bean生命周期等。
