BeanDefinition概念

BeanDefinition是Spring框架中定义Bean的配置元信息接口, 包含:

  • Bean类名
  • Bean行为配置元素, 如作用域, 自动绑定的模式, 生命周期回调等
  • 其他Bean引用, 又可称作合作者(Collaborators)或者依赖(Dependencies)
  • 配置设置, 比如Bean属性(Properties)

image.png

BeanDefinition构建

  • 通过BeanDefinitionBuilder
  • 通过AbstractBeanDefinition以及派生类 ```java public class BeanDefinitionCreationDemo {

    public static void main(String[] args) {

    1. // 1. 通过BeanDefinitionBuilder构建
    2. BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
    3. // 设置属性
    4. beanDefinitionBuilder.addPropertyValue("age", 18);
    5. beanDefinitionBuilder.addPropertyValue("name", "erha");
    6. // 获取实例, 其中beanDefinition并非终态, 还可以自定义修改
    7. BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
    8. // 2. 通过AbstractBeanDefinition构建
    9. GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
    10. genericBeanDefinition.setBeanClass(User.class);
    11. // 设置属性
    12. MutablePropertyValues propertyValues = new MutablePropertyValues();

    // propertyValues.addPropertyValue(“age”,18); // propertyValues.addPropertyValue(“name”,”erha”);

    1. propertyValues.add("age", 17).add("name", "sansha");
    2. genericBeanDefinition.setPropertyValues(propertyValues);

    }

}

  1. <a name="AuFW3"></a>
  2. ## 命名SpringBean
  3. 每个Bean拥有一个或多个标识符(identifiers), 这些标识符在Bean所在的容器必须是唯一的.<br />通常, 一个Bean仅有一个标识符, 如果需要额外的, 可用别名来扩充.
  4. - 基于xml配置时, 可用id/name属性来规定Bean的标识符. 命名官方推荐驼峰
  5. - 如果未指定, 容器为Bean自动生成一个唯一的名称(BeanNameGenerator)
  6. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/281275/1616937478707-8565ea10-fd07-4bda-aace-bda240e0012f.png#align=left&display=inline&height=147&margin=%5Bobject%20Object%5D&name=image.png&originHeight=147&originWidth=581&size=7067&status=done&style=none&width=581)
  7. **Bean的别名**
  8. - 复用现有的BeanDefinition
  9. - 更具有场景化的命名方法
  10. ```xml
  11. <?xml version="1.0" encoding="UTF-8"?>
  12. <beans
  13. xmlns="http://www.springframework.org/schema/beans"
  14. xmlns:context="http://www.springframework.org/schema/context"
  15. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  16. xsi:schemaLocation="http://www.springframework.org/schema/beans
  17. https://www.springframework.org/schema/beans/spring-beans.xsd
  18. http://www.springframework.org/schema/context
  19. https://www.springframework.org/schema/context/spring-context.xsd">
  20. <import resource="classpath:/META-INF/dependency-lookup-context.xml"/>
  21. <!--建立别名-->
  22. <alias name="user" alias="zhangsan-user"/>
  23. </beans>
  1. public class BeanAliasDemo {
  2. public static void main(String[] args) {
  3. // 配置XML配置文件, 启动Spring应用上下文
  4. BeanFactory beanFactory = new ClassPathXmlApplicationContext(
  5. "classpath:META-INF/bean-definition-context.xml");
  6. User aliaUser = beanFactory.getBean("zhangsan-user", User.class);
  7. User user = beanFactory.getBean("user", User.class);
  8. System.out.println(user == aliaUser);//true
  9. }
  10. }

注册SpringBean

image.png

  1. @Import(AnnotationBeanDefinitionDemo.Config.class) // 3. 通过 @Import进行导入
  2. public class AnnotationBeanDefinitionDemo {
  3. public static void main(String[] args) {
  4. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  5. // 1. 通过 @Bean方式定义, 注意, 注解尽管多种方式, 但是不会重复注册, API会多次注册
  6. applicationContext.register(Config.class);
  7. applicationContext.refresh();
  8. registerUserBeanDefinition(applicationContext,"erHuUser");
  9. registerUserBeanDefinition(applicationContext);
  10. Map<String, Config> configMap = applicationContext.getBeansOfType(Config.class);
  11. Map<String, User> userMap = applicationContext.getBeansOfType(User.class);
  12. System.out.println(
  13. configMap);// {annotationBeanDefinitionDemo.Config=top.xinzhang0618.spring.bean.AnnotationBeanDefinitionDemo$Config@2c039ac6}
  14. System.out.println(userMap);// {user=User{id=1, name='一旦'}, erHuUser=User{id=2, name='二虎'}, top.xinzhang0618.ioc.overview.domain.User#0=User{id=2, name='二虎'}}
  15. applicationContext.close();
  16. }
  17. @Component //2. 通过 @Component方式
  18. public static class Config {
  19. // 1. 通过 @Bean方式定义
  20. @Bean(name = {"user", "yiDanUser"})
  21. public User user() {
  22. User user = new User();
  23. user.setId(1L);
  24. user.setName("一旦");
  25. return user;
  26. }
  27. }
  28. /**
  29. * 通过API注册Bean
  30. */
  31. public static void registerUserBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
  32. BeanDefinitionBuilder beanDefinitionBuilder = genericBeanDefinition(User.class);
  33. beanDefinitionBuilder.addPropertyValue("id", 2L).addPropertyValue("name", "二虎");
  34. if (StringUtils.hasText(beanName)) {
  35. // 命名Bean的注册方式
  36. registry.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
  37. } else {
  38. // 非命名Bean的注册方式
  39. BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinitionBuilder.getBeanDefinition(), registry);
  40. }
  41. }
  42. public static void registerUserBeanDefinition(BeanDefinitionRegistry registry) {
  43. registerUserBeanDefinition(registry, null);
  44. }
  45. }

实例化SpringBean

  1. 常规方式
  • 通过构造器(配置元信息: XML. Java注解和API)
  • 通过静态工厂方法
  • 通过Bean工厂方法
  • 通过FactoryBean

以下代码通过XML配置的方式演示了三种情况

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. https://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/context
  9. https://www.springframework.org/schema/context/spring-context.xsd">
  10. <!--静态方法实例化Bean-->
  11. <bean id="user-by-static-method" class="top.xinzhang0618.ioc.overview.domain.User"
  12. factory-method="createUser"/>
  13. <!--实例方法实例化Bean-->
  14. <bean id="user-by-instance-method" factory-bean="userFactory" factory-method="createUser"/>
  15. <!--通过FactoryBean实例化Bean-->
  16. <bean id="user-by-factory-bean" class="top.xinzhang0618.spring.bean.factory.UserFactoryBean"/>
  17. <bean id="userFactory" class="top.xinzhang0618.spring.bean.factory.DefaultUserFactory"/>
  18. </beans>
  1. public class User {
  2. private Long id;
  3. private String name;
  4. ...
  5. /**
  6. * 通过静态方法构建user
  7. * @return
  8. */
  9. public static User createUser() {
  10. User user = new User();
  11. user.setId(1L);
  12. user.setName("lisi");
  13. return user;
  14. }
  15. }
  16. ------------------
  17. public interface UserFactory {
  18. default User createUser() {
  19. return User.createUser();
  20. }
  21. }
  22. ----------------------
  23. public class DefaultUserFactory implements UserFactory {
  24. }
  25. -----------------------
  26. public class UserFactoryBean implements FactoryBean {
  27. @Override
  28. public Object getObject() throws Exception {
  29. return User.createUser();
  30. }
  31. @Override
  32. public Class<?> getObjectType() {
  33. return User.class;
  34. }
  35. }
  1. public static void main(String[] args) {
  2. BeanFactory beanFactory = new ClassPathXmlApplicationContext(
  3. "classpath:/META-INF/bean-instantiation-context.xml");
  4. User user = beanFactory.getBean("user-by-static-method", User.class);
  5. User userByInstanceMethod = beanFactory.getBean("user-by-instance-method", User.class);
  6. User userByFactoryBean = beanFactory.getBean("user-by-factory-bean", User.class);
  7. System.out.println(user);
  8. System.out.println(userByInstanceMethod);
  9. System.out.println(userByFactoryBean);
  10. System.out.println(user == userByInstanceMethod);//false
  11. System.out.println(userByInstanceMethod == userByFactoryBean);//false
  12. }
  1. 特殊方式
  • 通过ServiceLoaderFactoryBean
  • 通过AutowireCapableBeanFactory#createBean(java.lang.Class, int, boolean)
  • 通过BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)

初始化SpringBean

执行顺序如下:

  1. @PostConstruct标注方法
  2. 实现InitializingBean接口的afterPropertiesSet()方法
  3. 自定义初始化方法
    • XML配置:
    • Java注解: @Bean(initMethod=”init”)
    • Java API: AbstractBeanDefinition#setInitMethosName(String)

示例代码如下:

  1. @Configuration
  2. public class BeanInitializationDemo {
  3. public static void main(String[] args) {
  4. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  5. applicationContext.register(BeanInitializationDemo.class);
  6. applicationContext.refresh();
  7. // 非延迟初始化 在Spring应用启动上下文完成后, 被初始化
  8. System.out.println("Spring应用上下文已启动...");
  9. UserFactory userFactory = applicationContext.getBean(UserFactory.class);
  10. System.out.println(userFactory);
  11. applicationContext.close();
  12. }
  13. @Bean(initMethod = "initUserFactory", destroyMethod = "doDestroy")
  14. // @Lazy
  15. public UserFactory userFactory() {
  16. return new DefaultUserFactory();
  17. }
  18. }
  1. public class DefaultUserFactory implements UserFactory , InitializingBean, DisposableBean {
  2. // 1. 基于 @PostConstruct 注解实现
  3. @PostConstruct
  4. public void init(){
  5. System.out.println("userFactory的@PostConstruct初始化");
  6. }
  7. public void initUserFactory(){
  8. System.out.println("@Bean自定义初始化方法");
  9. }
  10. @Override
  11. public void afterPropertiesSet() throws Exception {
  12. System.out.println("InitializingBean#afterPropertiesSet初始化方法");
  13. }
  14. @PreDestroy
  15. public void preDestroy(){
  16. System.out.println("userFactory的@PreDestroy销毁方法");
  17. }
  18. @Override
  19. public void destroy() throws Exception {
  20. System.out.println("DisposableBean#destroy销毁方法");
  21. }
  22. public void doDestroy(){
  23. System.out.println("@Bean自定义销毁方法");
  24. }
  25. }
  1. userFactory@PostConstruct初始化
  2. InitializingBean#afterPropertiesSet初始化方法
  3. @Bean自定义初始化方法
  4. Spring应用上下文已启动...
  5. top.xinzhang0618.spring.bean.factory.DefaultUserFactory@19dc67c2
  6. userFactory@PreDestroy销毁方法
  7. DisposableBean#destroy销毁方法
  8. @Bean自定义销毁方法

注: spring的启动初始化是单线程的

延迟初始化Bean

常用来解决循环依赖问题

  1. XML配置:
  2. java注解: @Lazy(true)

非延迟初始化: 先初始化Bean后再启动Spring上下文
延迟初始化: 先启动Spring上下文, 首次调用方法或者字段时, 才进行初始化

销毁SpringBean

执行顺序如下:

  1. @PreDestroy标注方法
  2. 实现DisposableBean接口的destory()方法
  3. 自定义销毁方法
    1. XML配置:
    2. Java注解: @Bean(destroy=”destroy”)
    3. Java API : AbstractBeanDefiniton#setDestroyMethosName(String)

回收SpringBean

Bean垃圾回收(GC)

  1. 关闭Spring容器应用上下文
  2. 执行GC
  3. SpringBean覆盖的finalize()方法被回调