本篇文章的目的是了解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
网友评论