IOC容器
IoC容器:的两个核心功能是(1)完成了完成对象的创建和(2)bean依赖的管理注入......
spring ioc 容器抽象的的几个主要接口:
Resource //资源文件的抽象,xml 、 properties ... BeanDefinition //bean的抽象定义 (bean的一些基本信息是否是 抽象、单例、懒加载、作用域...)基本信息 BeanDefinitionReader //不同的资源文件的bean的解析 BeanFactory //bean工厂的顶层抽象定义了几个基础的方法 getBean() contanisBean() .... ApplicationContext //应用程序上下文
1: Resource 接口
实现类:ClasspathResource、 解析classpath下的资源文件 URLResource、 解析url网络资源文件namespace
FileSystemResource、 解析系统资源文件
Spring 提供了一些org.springframework.core.io.Resource接口的实现,可以帮助我们快速获取Resource信息。
1. URLResource
封装了java.net.URL:通过URL可以获得的对象。
Resource resource = new UrlResource("file:/D:/java/src/bean.xml");
Resource resource = new UrlResource("http://127.0.0.1:8080/index.html");
Resource resource = new UrlResource(new URI("http://127.0.0.1:8080/index.html"));
2. FileSystemResource
处理java.io.File 本地资源文件
Resource resource = new FileSystemResource("file:C:\bean.xml");
3. ClassPathResource
获取classpath下面的Resource
Resource resource = new ClassPathResource("com/resource/bean.xml");
Resource接口的一些常用方法:
2:BeanDefinition 接口 (描述一个bean对象的基本数据结构)
几个重要的实现
BeanDefinitionParserDelegate //解析配置文件
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
parseBeanDefinitionElement()...多个重载方法实现bean的定义
public class ChildBeanDefinition extends AbstractBeanDefinition 、
public class RootBeanDefinition extends AbstractBeanDefinition 、
public class GenericBeanDefinition extends AbstractBeanDefinition 、
RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition均继承了AbstractBeanDefiniton,
BeanDefinition对象是配置文件中<bean>元素标签在容器中内部表示形式。
<bean>元素标签拥有class、scope、lazy-init等配置属性。
BeanDefinition则提供了相应的beanClass、scope、lazyInit属性。
BeanDefinition和<bean>中的属性是一一对应的。
其中RootBeanDefinition是最常用的实现类、它对应一般性的<bean>元素标签,
GenericBeanDefinition是自2.5以后新加入的bean文件配置属性定义类,是一站式服务类。
在配置文件中可以定义父<bean>和子<bean>,父<bean>用RootBeanDefinition表示,而子<bean>用ChildBeanDefiniton表示,而
没有父<bean>的<bean>就使用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象。
Spring通过BeanDefinition将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些BeanDefiniton注册到BeanDefinitonRegistry中。
Spring容器的BeanDefinitionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接从BeanDefinitionRegistry中读取配置信息。
一般情况下,BeanDefinition只在容器启动时加载并解析,除非容器刷新或重启,这些信息不会发生变化。
如果用户有特殊的需求,也可以通过编程的方式在运行期调整BeanDefinition的定义。
创建最终的BeanDefinition主要包括两个步骤:
1)利用BeanDefinitionReader对配置信息Resource进行读取,通过XML解析器解析配置信息的DOM对象,简单地为每个<bean>生成对应的BeanDefinition对象。
但是这里生成的BeanDefinition可能是半成品,因为在配置文件中,我们可能通过占位符变量引用外部属性文件的属性,这些占位符变量在这一步还没有被解析出来。
2)利用容器中注册的BeanFactoryPostProcessor对半成品的BeanDefinition进行加工处理,
将以占位符表示的配置解析为最终的实际值,这样半成品的BeanDefinition就为成品的BeanDefinition。
3:BeanDefinitionReader 接口将配置信息转换程BeanDefinition
BeanDefinitionReader将外部资源对象描述的bean定义统一转化为统一的内部数据结构BeanDefinition。
主要实现类:
XmlBeanDefinitionReader、用来读取xml描述配置的bean对象。
PropertiesBeanDefinitionReader、用来解析 ×.properties文件描述配置的bean对象。
最后都会 registerBeanDefinitions(...) 注册解析到的bean对象到map
4:BeanFactory 接口 (bean的工厂)
主要方法
protected Object doGetBean(final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException { //bean name处理,去除FactoryBean前缀等 final String beanName = transformedBeanName(name); Object bean = null; //先从singleton缓存中查看是否已经实例化过该Bean,根据是否有缓存分为两个分支分别处理 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { // 分支一,若缓存中获取到了并且该BeanDefinition信息表明该bean是singleton的,直接将获取到的缓存Bean //(有可能是半成品)交给getObjectForBeanInstance处理 //调用getObjectForBeanInstance处理 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }else { // 分支二:没有缓存,则需要从头实例化该bean // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName);} // 检查BeanDefinition是否在当前工厂或父工厂 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (args != null) { // 父工厂getBean return parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } //将bean加入“正在创建”的集合,完成后会remove,对应afterSingletonCreation/afterPrototypeCreation方法 if (!typeCheckOnly) { markBeanAsCreated(beanName); } final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 解决依赖关系,将依赖的bean提前实例化 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (int i = 0; i < dependsOn.length; i++) { String dependsOnBean = dependsOn[i]; getBean(dependsOnBean); registerDependentBean(dependsOnBean, beanName); } } // 这里又需要根据bean的类型分为三种情况:singleton、prototype、request/session if (mbd.isSingleton()) { //通过自定义ObjectFactory实例化Bean,此结果可能是半成品(是FactoryBean等) sharedInstance = getSingleton(beanName, new ObjectFactory() { public Object getObject() throws BeansException { try { //真正实例化装配的逻辑在createBean方法中 return createBean(beanName, mbd, args); } catch (BeansException ex) { //显式地删除实例从单缓存:它可能已经把那里
//热切的创建过程,允许循环引用的决议。
//删除任何bean,得到一个临时bean的引用。 destroySingleton(beanName); throw ex; } } }); //上一步半成品的Bean交给getObjectForBeanInstance方法处理 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); //真正实例化装配的逻辑在createBean方法中 prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } //上一步半成品的Bean交给getObjectForBeanInstance方法处理 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { //request、session 的bean String scopeName = mbd.getScope(); final Scope scope = (Scope) this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory() { public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { //真正实例化装配的逻辑在createBean方法中 return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); //上一步半成品的Bean交给getObjectForBeanInstance方法处理 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; " + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } // Check if required type matches the type of the actual bean instance. if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return bean; }
创建bean的步骤:
检查Bean缓存,已经有缓存的Bean对象(有可能是半成品)则交给getObjectForBeanInstance方法处理、
否则先根据Bean的生命周期类型分别实例化,每种情况大致都分两步,
第一步都交给createBean方法生产一个半成品的bean对象,
然后同样是将半成品的bean交给getObjectForBeanInstance方法
ps:为什么createBean方法创建完的bean是半成品,该半成品交给getObjectForBeanInstance()方法后执行了什么操作?
5:ApplicationContext 接口
public interface ApplicationContext extends EnvironmentCapable,
ListableBeanFactory, //beanFactory
HierarchicalBeanFactory, //beanFactory
MessageSource, //处理消息的基本接口 可以实现国际化....
ApplicationEventPublisher, //事件监听
ResourcePatternResolver { //资源处理
主要实现类
ClasspathXmlApplicationContext,
FileSystemXmlApplicationContext,
WebApplicationContext Web上下文容器 (ServletContext)
//初始化过程 ClasspathXmlApplicationContext为例
1.把配置xml文件转换成resource。resource的转换是先通过ResourcePatternResolver来解析可识别格式的配置文件的路径
(如"classpath*:"等),如果没有指定格式,默认会按照类路径的资源来处理。
2.利用XmlBeanDefinitionReader完成对xml的解析,将xml Resource里定义的bean对象转换成统一的BeanDefinition。
3.将BeanDefinition注册到BeanFactory,完成对BeanFactory的初始化。BeanFactory里将会维护一个BeanDefinition的Map。
最后在调用 getBean的时候会执行
public void refresh() throws BeansException, IllegalStateException {
...
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //创建BeanFactory
//会实例化一个XmlBeanDefinitionReader来解析Resource文件。
...
.... }太长了不翻译了
参考文档:
1:http://www.neversaydie.cc/spring-ioc-introduce/
其它参考文章稍后贴出...