【spring】深入IOC
spring IOC容器封装了我们自定义的bean信息,为我们持有bean及管理bean的生命周期
IOC容器初始化过程包含bean信息的定位、载入和注册过程
要初始化IOC容器,首先需要对定义的bean信息进行定位,找到所需的bean信息
然后把这些bean信息载入到内存中
持有bean信息的数据结构是 BeanDefinition,封装了bean的所有基本属性
包括class,singleton,和bean所依赖的内部属性,如bean引用,各种value值等
而BeanDefinitionHolder 则封装了 BeanDefinition ,bean的名字和bean的别名组
这个beanDefinition 的持有与管理,是在DefaultListableBeanFactory 里维护的,
其中构建了一个
ConcurrentHashMap 来管理
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
//demo,通过 FileSystemXmlApplicationContext 构建IOC容器
//IOC容器就是持有和管理我们所需要的bean信息及其间的依赖关系的一个容器
// FileSystemXmlApplicationContext 就是通过查找文件系统信息寻找相关的bean信息定义文件
// ClassPathXmlApplicationContext 就是通过查找classpath路径寻找相关bean信息定义文件
// 两者在IOC容器的实现上是一致的,区别也就是路径查找上的一些不同而已
public class SpringDemo5 {
public static void main(String[] args) {
// ApplicationContext context =
// new ClassPathXmlApplicationContext("com\\ming\\ sns\\test\\bean-config.xml");
ApplicationContext context =
new FileSystemXmlApplicationContext( "src\\com\\ming\\sns\\test\\bean-config.xml" );
//构建好容器后,通过getBean方法就可以获取到所需要的bean实例
MyFactory2 test = (MyFactory2) context.getBean( "MyFactory2");
test.show();
}
}
//FileSystemXmlApplicationContext
//org.springframework.context.support.FileSystemXmlApplicationContext.class
// 构造方法中非常关键的方法是 refresh方法 。refresh函数 初始化context,整个IOC容器
// refresh方法启动整个IOC容器的初始化过程,包括bean信息的定位载入注册的过程
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
// 这是refresh方法的具体实现
//org.springframework.context.support.AbstractApplicationContext.class
public void refresh () throws BeansException, IllegalStateException {
synchronized (this .startupShutdownMonitor ) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取BeanFactory 各种bean信息,及上下文信息就是在这个容器里维护的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
//org.springframework.context.support.AbstractApplicationContext.class
protected ConfigurableListableBeanFactory obtainFreshBeanFactory () {
// 这个方法非常重要,构建BeanFactory
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger .isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
org.springframework.context.support.AbstractRefreshableApplicationContext.class
protected final void refreshBeanFactory () throws BeansException {
// 把旧的容器清除
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 构建一个新的容器
// DefaultListableBeanFactory 为持有和管理上下文使用的IOC容器
// DefaultListableBeanFactory 里封装了所需要的数据结构,用以保存所需要的bean信息等
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 载入所需要的bean信息
loadBeanDefinitions(beanFactory);
synchronized (this .beanFactoryMonitor ) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
org.springframework.context.support.AbstractXmlApplicationContext.class
@Override
protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
// bean信息的载入是由一个reader类来执行,这里是XmlBeanDefinitionReader
// XmlBeanDefinitionReader 能够读取并解析xml文件,把文件中的各类信息解析出来并载入到内存里
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment( this.getEnvironment());
beanDefinitionReader.setResourceLoader( this);
beanDefinitionReader.setEntityResolver( new ResourceEntityResolver(this ));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
// 信息载入的方法
loadBeanDefinitions(beanDefinitionReader);
}
// org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.class
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析xml中的元素,封装成一个BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils. registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error( "Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered( new BeanComponentDefinition(bdHolder));
}
}
// org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.class
// bean信息解析和创建封装bean信息的具体方法实现
/**
* Parse the bean definition itself, without regard to name or aliases. May return
* <code>null</code> if problems occured during the parse of the bean definition.
*/
public AbstractBeanDefinition parseBeanDefinitionElement (
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState .push(new BeanEntry(beanName));
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute( CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute( PARENT_ATTRIBUTE);
}
// 创建一个封装bean信息的BeanDefinition类
// 其中非常重要的是bean的类对象信息,通过下面的语句进行设置
// bd.setBeanClass(ClassUtils.forName(className, classLoader));
// forName 方法里通过类加载构建bean类型的类对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// parseBeanDefinitionAttributes 方法用来设置bean的各种属性,如singleton
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils. getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT ));
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd);
// 这里对bean 里的各个属性值进行解析并进行封装保存
// 如可能有 ref 引用,或者是value值,这些内容会被封装成PropertyValue值保存到BeanDefinition中
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
bd.setResource( this.readerContext .getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error( "Bean class [" + className + "] not found" , ele, ex);
}
catch (NoClassDefFoundError err) {
error( "Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error( "Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState .pop();
}
return null ;
}
// 如果bean信息里 有内部属性,就调用这个方法进行处理
// 内部属性包括,bean和list等结构元素
// 对于list 等集合元素,会构建并返回相关的集合对象,添加到Beandefinition中
/**
* Parse a value, ref or collection sub -element of a property or
* constructor -arg element.
* @param ele subelement of property element; we don't know which yet
* @param defaultValueType the default type (class name) for any
* <code><value></code> tag that might be created
*/
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
if (!isDefaultNamespace(ele)) {
return parseNestedCustomElement(ele, bd);
}
else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
else if (nodeNameEquals(ele, REF_ELEMENT)) {
// A generic reference to any name of any bean.
String refName = ele.getAttribute( BEAN_REF_ATTRIBUTE);
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in the same XML file.
refName = ele.getAttribute( LOCAL_REF_ATTRIBUTE);
if (!StringUtils.hasLength(refName)) {
// A reference to the id of another bean in a parent context.
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE );
toParent = true;
if (!StringUtils.hasLength(refName)) {
error( "'bean', 'local' or 'parent' is required for <ref> element", ele);
return null ;
}
}
}
if (!StringUtils.hasText(refName)) {
error( "<ref> element contains empty target attribute", ele);
return null ;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
return parseIdRefElement(ele);
}
else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
return parseValueElement(ele, defaultValueType);
}
else if (nodeNameEquals(ele, NULL_ELEMENT)) {
// It's a distinguished null value. Let's wrap it in a TypedStringValue
// object in order to preserve the source location.
TypedStringValue nullHolder = new TypedStringValue(null );
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
return parseArrayElement(ele, bd);
}
else if (nodeNameEquals(ele, LIST_ELEMENT)) {
return parseListElement(ele, bd);
}
else if (nodeNameEquals(ele, SET_ELEMENT)) {
return parseSetElement(ele, bd);
}
else if (nodeNameEquals(ele, MAP_ELEMENT)) {
return parseMapElement(ele, bd);
}
else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
return parsePropsElement(ele);
}
else {
error( "Unknown property sub-element: [" + ele.getNodeName() + "]" , ele);
return null ;
}
}
// org.springframework.beans.factory.support.DefaultListableBeanFactory.class
// 在之前创建的BeanFactory 容器里注册 所解析到的 BeanDefinition信息
public void registerBeanDefinition (String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert. hasText(beanName, "Bean name must not be empty");
Assert. notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
synchronized (this .beanDefinitionMap ) {
Object oldBeanDefinition = this.beanDefinitionMap .get(beanName);
if (oldBeanDefinition != null) {
if (!this .allowBeanDefinitionOverriding ) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound." );
}
else {
if (this .logger .isInfoEnabled()) {
this.logger .info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames .add(beanName);
this.frozenBeanDefinitionNames = null;
}
// BeanDefinition 信息 最终是在一个map里保存的,保存格式是,bean的名字和封装了bean的各类信息的BeanDefinition结构
this.beanDefinitionMap .put(beanName, beanDefinition);
resetBeanDefinition(beanName);
}
}