美文网首页
Spring BeanFactory和ApplicationCo

Spring BeanFactory和ApplicationCo

作者: 何德何能者 | 来源:发表于2020-12-12 19:23 被阅读0次

    本篇文章的目的是了解BeanFactory与ApplicationContext的区别以及关系
    带目的学习才使自己不迷失方向,特别是在源码的海洋里

    BeanFactory

    是什么
    根据BeanFactory的源码解析

    • BeanFactory是个接口
    • 是spring bean的容器
    • 接口提供获取bean的功能
    • 更多功能定义在ListabelBeanFactory和ConfigrableBeanFactory
    • 依赖BeanDefinition区分不同的bean
      从接口说明的功能里看BeanFactory能作的事很简单. ListableBeanFactory和ConfigrableBeanFactory增加了几个功能。不过都没有超出工厂的作用范围.

    ApplicationContext

    是什么
    源码没怎么解析ApplicationContext,不过从ApplicationContext接口的继承关系可以看出. ApplicationContext实现了BeanFactory; 包括

    • EnvironmentCapabel 有环境配置的功能,包括系统环境属性和自定义环境配置属性
    • ListableBeanFactory 有枚举所有bean的能力。
    • HierarchicalBeanFactory 有层级能力,可以指定父BeanFactory
    • MessageSource 国际化功能
    • ApplicationEventPublisher 时间发布触发功能
    • ResourcePatternResolver 资源正则匹配/加载功能
      从ApplicationContext接口继承上看出, ApplicationContext组合了许多功能。也可以得出ApplicationContext是BeanFactory的增强
      他们的关系图如下


      ApplicationContext.png

    BeanFactory代码

    定义两个bean, 省略get set
    User

    public class User {
        private String name;
        private int age;
        // 依赖另一个bean
        private UserProfile userProfile;
    
    public class UserProfile {
        private String gender;
    

    可以看出 User 依赖 UserProfile。 那么使用BeanFactory怎么生成两个bean并注入依赖呢

    • 需要声明两个bean的 beanDefinition
    • 在User的beanDefiniton里声明依赖UserProfile
      代码如下
    GenericBeanDefinition userBeanDefinition = new GenericBeanDefinition();
    userBeanDefinition.setBeanClass(User.class);
    // 声明依赖userProfile
    userBeanDefinition.setDependsOn("userProfile");
    GenericBeanDefinition userProfileBeanDefinition = new GenericBeanDefinition();
    userProfileBeanDefinition.setBeanClass(UserProfile.class);
    // 声明为单例, 为的是user bean注入的对象是同一个
    userProfileBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
    

    把beanDefiniton注册到beanFactory

    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    beanFactory.registerBeanDefinition("userBean", userBeanDefinition);
    beanFactory.registerBeanDefinition("userProfile", userProfileBeanDefinition);
    

    接下来就是生成bean了

    // 该方法会合并beanDefinition, 所以可以指定配置; 不过不会完成自动注入
    UserProfile userProfile = beanFactory.getBean(UserProfile.class);
    userProfile.setGender("3333");
    // beanFactory.createBean(class,int, boolean)指定的就是prototype的,无法生产单例; 该方法会完成自动注入依赖
    Object user = beanFactory.createBean(User.class, 2, true);
    System.out.println("user :" + user + " hashCode:" + user.hashCode());
    

    得到输出结构:

    user :User{name='null', age=0, userProfile=UserProfile{gender='3333'}} hashCode:878274034
    

    从以上代码了解到. beanFactory提供多种生成bean的方法. 在没有特别声明BeanDefinition的情况下, bean的作用域都是prototype; 而且不会自动完成依赖注入

    ApplicationContext代码

    GenericApplicationContext applicationContext = new GenericApplicationContext();
    ConfigurableListableBeanFactory configurableListableBeanFactor = applicationContext.getBeanFactory();
     if (configurableListableBeanFactor instanceof DefaultListableBeanFactory) {
         DefaultListableBeanFactory bf = ((DefaultListableBeanFactory)configurableListableBeanFactor);
         userBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
         // 为了防止初始化检查依赖
         userBeanDefinition.setDependsOn(new String[]{});
         bf.registerBeanDefinition("userBeanDefinition",userBeanDefinition);
      }
      User appUser = configurableListableBeanFactor.getBean(User.class);
      System.out.println("app config user:" + appUser + " hashCode:" + appUser.hashCode());
      // 不支持多次刷新
      applicationContext.refresh();
      User appSingleUser =  applicationContext.getBean(User.class);
      System.out.println("app user:" + appSingleUser + " hashCode:" + appSingleUser.hashCode());
      // 未配置beanDefinition,会报异常
      UserProfile appUserProfile =  applicationContext.getBean(UserProfile.class);
      System.out.println("app user profile:" + appSingleUser + " hashCode:" + appUserProfile.hashCode());
    

    输出结果

    app config user:User{name='null', age=0, userProfile=null} hashCode:1858609436
    12月 12, 2020 7:03:39 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh
    信息: Refreshing org.springframework.context.support.GenericApplicationContext@6d7b4f4c: startup date [Sat Dec 12 19:03:39 CST 2020]; root of context hierarchy
    app user:User{name='null', age=0, userProfile=null} hashCode:1858609436
    Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xie.java.beans.UserProfile' available
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:352)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1092)
        at com.xie.java.DefaultListableBeanFactoryTest.main(DefaultListableBeanFactoryTest.java:71)
    

    AnnotationConfigApplicationContext

    注解方式声明beanDefinition

    @Component
    public class UserComponent {
        private String name;
    
        // Autowired 在UserComponent beanFactory.create的时候会进行BeanProcress 处理。 AutowiredAnnotationBeanProcessor,
        // 该BeanProcessor 是实现了PriorityOrdered排序特殊的beanProcessor. 能在其他beanProcessor之前执行
        @Autowired
        private UserProfileComponent userProfileComponent;
    }
    
    @Component
    public class UserProfileComponent {
        @Autowired
        private UserComponent userComponent;
    }
    
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
    annotationConfigApplicationContext.refresh();
    annotationConfigApplicationContext.scan("com.xie.java.beans");
    UserComponent userComponent = annotationConfigApplicationContext.getBean(UserComponent.class);
    UserProfileComponent userProfileComponent = annotationConfigApplicationContext.getBean(UserProfileComponent.class);
    System.out.println("user component :" + userComponent);
    System.out.println("user profile component:" + userProfileComponent);
    System.out.println("user component profile equals " + (userComponent.getUserProfileComponent() == userProfileComponent));
    

    输出结果

    user component :UserComponent{name='null', userProfileComponent=com.xie.java.beans.UserProfileComponent@346d61be}
    user profile component:com.xie.java.beans.UserProfileComponent@346d61be
    user component profile equals true
    

    从代码定义知道,两个bean互相依赖相互注入. 那么这个循环依赖是怎么实例化的呢。其实AnnotationConfigApplicationContext扫描包,扫描出的beanDefinition都是声明为单例的. 在beanFactory.create得到bean(此时没有注入依赖,依赖是null)后会进行beanPostProcessor。 @Autowired会被AutowiredAnnotationBeanProcessor进行处理. 处理过程也是beanFactory.create。这样就完成了注入;当然这里的关键是beanDefiniton都是单例的。如果循环依赖其中一个不是单例的,将无法完成注入,且抛出异常.

    image.png

    相关文章

      网友评论

          本文标题:Spring BeanFactory和ApplicationCo

          本文链接:https://www.haomeiwen.com/subject/pcqygktx.html