IoC Beans部分
核心需求 :依据配置信息创建对象和将对象连接起来。
核心类
Ioc 容器类定义.png各个类职责:
BeanFactory:获取bean,是bean 容器,接口
ListableBeanFactory: 查询beanFactory 注册的bean信息,接口
AbstractBeanFactory:依据bean 注册信息,创建bean 和完成bean 依赖关系组装。核心实现
ListableBeanFactoryImpl: 完成bean 配置信息注册的具体实现
XmlBeanFactory : 从配置文件中完成bean配置(定义)信息的注册,还包括xml 文件具体解析
使用
配置xml 文件并从容器中获取bean。
BeanFactory factory =new XMLBeanFactory(xmlfile)
Object bean =factory.getBean(“beanName”)
实现
1、new XMLBeanFactory(xmlfile) 流程
public XmlBeanFactory(Document doc, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
loadBeanDefinitions(doc);
}
loadBeanDefinitions :
1、完成xml 文件解析
2、将xml 配置文件解析成AbstractBeanDefinition 对象
3、将AbstractBeanDefinition 注册到容器中
XMLBeanFactory 职责是比较单一的,完成xml文件读取,然后将xml 文件转换成AbstractBeanDefinition 对象,并且将对象注册到容器中。注册的具体实现由父类完成。
2、factory.getBean(“beanName”) 实现在AbstractBeanFactory 中
getBeanInternal
private Object getBeanInternal(String name, Map newlyCreatedBeans) {
AbstractBeanDefinition bd = getBeanDefinition(transformedBeanName(name));
return bd.isSingleton() ?
getSharedInstance(name, newlyCreatedBeans) :
createBean(name, newlyCreatedBeans);
}
getSharedInstance:
如果bean实现FactoryBean 接口,生成bean使用自定义工厂方法创建。会创建二次bean,1次创建FactoryBean ,2 次依据FactoryBean 在创建自定bean,这是后续集成AOP 的一个基础
createBean(name, newlyCreatedBeans);
if (beanInstance instanceof FactoryBean) {
FactoryBean factory = (FactoryBean) beanInstance;
beanInstance = factory.getObject();
// 设置bean 的属性值,可能是配置的静态值,有可能是引用值
if (factory.getPropertyValues() != null) {
logger.debug("Applying pass-through properties to bean with name '" + name + "'");
new BeanWrapperImpl(beanInstance).setPropertyValues(factory.getPropertyValues());
}
}
核心逻辑createBean
private Object createBean(String name, Map newlyCreatedBeans) throws BeansException {
if (newlyCreatedBeans == null) {
newlyCreatedBeans = new HashMap();
}
Object bean = getBeanWrapperForNewInstance(name, newlyCreatedBeans).getWrappedInstance();
callLifecycleMethodsIfNecessary(bean, name);
return bean;
}
private void callLifecycleMethodsIfNecessary(Object bean, String name) throws BeansException {
if (bean instanceof InitializingBean) {
((InitializingBean) bean).afterPropertiesSet();
}
if (bean instanceof Lifecycle) {
((Lifecycle) bean).setBeanFactory(this);
}
}
1、创建bean 并且给设置属性值
2、callLifecycleMethodsIfNecessary 扩展点。bean 实现了xxx 接口,会在bean 创建好后调用 bean 的扩展接口。
private BeanWrapper getBeanWrapperForNewInstance(String name, Map newlyCreatedBeans) throws BeansException {
// 获取bean 定义
AbstractBeanDefinition bd = getBeanDefinition(name);
BeanWrapper instanceWrapper = null;
if (bd instanceof RootBeanDefinition) {
RootBeanDefinition rbd = (RootBeanDefinition) bd; instanceWrapper=rbd.getBeanWrapperForNewInstance();
}
else if (bd instanceof ChildBeanDefinition) {
ChildBeanDefinition ibd = (ChildBeanDefinition) bd;
instanceWrapper = getBeanWrapperForNewInstance(ibd.getParentName(), newlyCreatedBeans);
}
newlyCreatedBeans.put(name, instanceWrapper.getWrappedInstance());
PropertyValues pvs = bd.getPropertyValues();
// 设置bean 的属性以及依赖值,引用值处理resolveValueIfNecessary()
applyPropertyValues(instanceWrapper, pvs, name, newlyCreatedBeans);
return instanceWrapper;
}
小结:
可以看到第一版的bean 容器实现还是很简单的,但是实现和核心的功能,后续的版本都是以此为基础。类结构和名称(BeanFactory)很多一直延续至今。也可以看到最初的设计是非常稳定的。
IoC Context 部分
beans 实现了核心的需求,从配置到获取bean。但是我们作为应用开发,还需要集成应用程序部分。用 Context 来装饰BeanFactory ,对BeanFactroy 的功能加强 。从这个设计思路,我们还可以看到后续的Spring boot 项目也是类似的实现方式。用Application 来装饰 Context,加强Context 的功能。
核心类
Context 类.png1、AbstractApplicationContext 是连接应用与bean 的核心实现类,并且设计了很多抽象方法供子类自定义实现。比如如何获取是创建BeanFactroy 留给子类实现。
2、AbstractXmlApplicationContext :负责创建XMLFactroy
3、FileSystemXmlApplicationContext :主要负责配置文件位置定义。
使用
自动完成bean 的创建工作,不用beanFactory.get()
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlfile)
源码
new ClassPathXmlApplicationContext(xmlfile)
1、指定配置文件在classpath 下面。按照输入流读取到xml 配置文件
protected InputStream getResourceByPath(String path) throws IOException {
if (!path.startsWith("/")) {
// always use root,
// as loading relative to this class' package doesn't make sense
path = "/" + path;
}
return getClass().getResourceAsStream(path);
}
2、创建context ,调用 核心 refresh() 方法
public FileSystemXmlApplicationContext(String[] locations)
throws ApplicationContextException, IOException {
ApplicationContext parent=createParentContext(parentLocations);
setParent(parent);
// initialize this context
refresh();
}
3、AbstractApplicationContext#refresh
public final void refresh() throws ApplicationContextException {
refreshBeanFactory();
configureAllManagedObjects();
refreshListeners();
loadOptions();
onRefresh();
publishEvent(new ContextRefreshedEvent(this));
}
refreshBeanFactory : 留给子类实现,AbstractXmlApplicationContext 默认实现为创建XMLBeanFactory。
configureAllManagedObjects :默认创建所容器中所有bean,所以客户端在使用前,bean 都已经创建好了。
private void configureAllManagedObjects() throws ApplicationContextException {
String[] beanNames = getBeanDefinitionNames();
for (int i = 0; i < beanNames.length; i++) {
String beanName = beanNames[i];
if (isSingleton(beanName)) {
try {
Object bean = getBeanFactory().getBean(beanName);
configureManagedObject(bean);
}
}
}
bean 扩展点,如果实现了ApplicationContextAware 接口,创建bean 完成后,会调用该方法
protected void configureManagedObject(Object o) throws ApplicationContextException {
if (o instanceof ApplicationContextAware) {
aca.setApplicationContext(this);
}
}
refreshListeners :bean 如果实现了ApplicationListener 接口,将是一个特殊的bean,会接受到ApplicationEvent 事件,也就是最后一步
publishEvent(ContextRefreshedEvent)
private void refreshListeners() throws ApplicationContextException {
String[] listenerNames = getBeanDefinitionNames(ApplicationListener.class);
for (int i = 0; i < listenerNames.length; i++) {
String beanName = listenerNames[i];
try {
Object bean = getBeanFactory().getBean(beanName);
ApplicationListener l = (ApplicationListener) bean;
addListener(l);
}
}
onRefresh : 留给子类实现,比如在后续版本中,onRefresh 改方法实现了启动tomcat 服务器。
publishEvent: 给实现ApplicationListener 接口的bean 发布广播通知。
小结:
Context 集成 BeanFactory ,并且默认完成所有bean 的创建工作 ,还提供了应用的一些扩展点 比如 ApplicationListener,ApplicationContextAware。Spring 的扩展方式1:通过实现父类预留的接口,2、通过实现预定的接口。这两种方式都有代码入侵性,不是很友好。但是这种扩展方式的思想一种沿用至今,虽然目前的spring 版本代码有较大的改动,但是核心的部分还是未改变。通过最基础的版本代码阅读,更容易理解核心实现和核心思路。在实现自定义功能时候,我们容易知道什么地方有扩展点。
我们使用spring 框架一般是使用ApplicationContext,很少单独使用BeanFactory,所以就重点回顾下ApplicationContext 的执行流程。
-
ApplicationContext 的创建过程 核心逻辑都实现在AbstractApplicationContext#refresh 中
-
ApplicationContext 预览了很多抽象方法给子类配置使用,单都是非核心的配置功能,比如
如何获取BeanFactory,如何制定配置文件位置,如何添加默认实现的bean 注册到BeanFactory中 -
重点流程还AbstractApplicationContext#refresh
1、 refreshBeanFactory:获取并且创建 BeanFactory,创建BeanFactory的同时完成bean 配置的注册
2、configureAllManagedObjects :实例化BeanFactory 中所有的配置的bean。
2.1 创建bean,更bean 设置属性值
2.2 如果bean实现了FactoryBean ,那么还会以及FactoryBean.getObjecct() 创建bean
2.3 创建bean 完成后 会判断bean 有没有实现InitializingBean,Lifecycle 接口
如果bean 实现了这些接口还会调用((InitializingBean) bean).afterPropertiesSet();
((Lifecycle) bean).setBeanFactory(this);
2.4 如果bean 实现了ApplicationContextAware 接口还会调用setApplicationContext方法
2.1 ~2.3 的扩展接口(FactoryBean,InitializingBean,Lifecycle)是在beans 定义的
2.4 的扩展接口(ApplicationContextAware)是在Context 模块中定义的
- refreshListeners :获取BeanFactory 所有实现ApplicationListener 接口的bean 。
- onRefresh hook 给子类实现
- publishEvent,将Context 完成
网友评论