Spring BeanFactory和ApplicationCo

2020-12-12  本文已影响0人  何德何能者

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

BeanFactory

是什么
根据BeanFactory的源码解析

ApplicationContext

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

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并注入依赖呢

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
上一篇 下一篇

猜你喜欢

热点阅读