Spring bean 配置文件初始化
Spring框架基础之模块-IOC,主要提供了依赖注入的实现。甚为重要,小洋闲来无事,再此专研一番。记之、
事前准备
1. 新建一个maven项目,导入最基本的spring包依赖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>rpc</artifactId> <groupId>com.xxx.rpc</groupId> <version>1.3.0</version> </parent> <modelVersion>4.0.0</modelVersion>
<artifactId>spring-bean-init</artifactId>
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </dependency> </dependencies> </project>
|
写个一简单的bean类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class User { private String userName; private String password;
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getUserName() {
return userName; }
public void setUserName(String userName) { this.userName = userName; }
@Override public String toString() { return "User{" + "userName='" + userName + '\'' + ", password='" + password + '\'' + '}'; } }
|
3. 新建spring.xml文件,配置一下User。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.lty.bean"/>
<bean id="user" class="com.lty.bean.User"> <property name="userName" value="LTY"/> <property name="password" value="PASSWORD"/> </bean>
</beans>
|
4. 写个启动类,加载spring.xml文件,并获取配置的bean。
1 2 3 4 5 6 7
| public class Boot { public static void main(String[] args) { System.out.println(new ClassPathXmlApplicationContext("spring.xml").getBean("user",User.class).toString()); }
}
|
简单设想
上面是很简单的Spring用法,可以看到小洋自定义的bean已经交给Spring管理了,看输出结果属性的值也初始化了。小洋默默深思,这一切是怎么发生的呢,在Java的世界里能通过运行时去加载的类的,也就只有反射了。是不是通过标签的class属性去加载User,然后在根据配置的属性通过反射设置进去呢。为了解决这个疑问和设想,小洋开始了源码之旅。
源码之旅
1 2 3 4 5 6 7 8 9 10 11 12
|
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); this.setConfigLocations(configLocations); if(refresh) { this.refresh(); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory);
try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var5) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt", var5); this.destroyBeans(); this.cancelRefresh(var5); throw var5; }
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { this.refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if(this.logger.isDebugEnabled()) { this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory); }
return beanFactory; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
protected final void refreshBeanFactory() throws BeansException { if(this.hasBeanFactory()) { this.destroyBeans(); this.closeBeanFactory(); }
try { DefaultListableBeanFactory ex = this.createBeanFactory(); ex.setSerializationId(this.getId()); this.customizeBeanFactory(ex); this.loadBeanDefinitions(ex); Object var2 = this.beanFactoryMonitor; synchronized(this.beanFactoryMonitor) { this.beanFactory = ex; } } catch (IOException var5) { throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
protected void doRegisterBeanDefinitions(Element root) { BeanDefinitionParserDelegate parent = this.delegate; this.delegate = this.createDelegate(this.getReaderContext(), root, parent); if(this.delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute("profile"); if(StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; "); if(!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { return; } } } this.preProcessXml(root); this.parseBeanDefinitions(root, this.delegate); this.postProcessXml(root); this.delegate = parent; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if(delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for(int i = 0; i < nl.getLength(); ++i) { Node node = nl.item(i); if(node instanceof Element) { Element ele = (Element)node; if(delegate.isDefaultNamespace(ele)) { this.parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); }
}
|
上我们可以看到,当解析到具体的某个标签的时候,Spring有两个分支,自定义和默认的。很好理解我们可以通过在xml文件配置来让Spring初始化,也可以什么都不写直接在类上面加Component注解就行,然后在xml文件指定一些Spring的扫描路径。下面我先看通过配置的解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { if(delegate.nodeNameEquals(ele, "import")) { this.importBeanDefinitionResource(ele); } else if(delegate.nodeNameEquals(ele, "alias")) { this.processAliasRegistration(ele); } else if(delegate.nodeNameEquals(ele, "bean")) { this.processBeanDefinition(ele, delegate); } else if(delegate.nodeNameEquals(ele, "beans")) { this.doRegisterBeanDefinitions(ele); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if(bdHolder != null) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException var5) { this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5); }
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) { String id = ele.getAttribute("id"); String nameAttr = ele.getAttribute("name"); ArrayList aliases = new ArrayList(); if(StringUtils.hasLength(nameAttr)) { String[] beanName = StringUtils.tokenizeToStringArray(nameAttr, ",; "); aliases.addAll(Arrays.asList(beanName)); }
String beanName1 = id; if(!StringUtils.hasText(id) && !aliases.isEmpty()) { beanName1 = (String)aliases.remove(0); if(this.logger.isDebugEnabled()) { this.logger.debug("No XML \'id\' specified - using \'" + beanName1 + "\' as bean name and " + aliases + " as aliases"); } }
if(containingBean == null) { this.checkNameUniqueness(beanName1, aliases, ele); } AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName1, containingBean); if(beanDefinition != null) { if(!StringUtils.hasText(beanName1)) { try { if(containingBean != null) { beanName1 = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true); } else { beanName1 = this.readerContext.generateBeanName(beanDefinition); String aliasesArray = beanDefinition.getBeanClassName(); if(aliasesArray != null && beanName1.startsWith(aliasesArray) && beanName1.length() > aliasesArray.length() && !this.readerContext.getRegistry().isBeanNameInUse(aliasesArray)) { aliases.add(aliasesArray); } }
if(this.logger.isDebugEnabled()) { this.logger.debug("Neither XML \'id\' nor \'name\' specified - using generated bean name [" + beanName1 + "]"); } } catch (Exception var9) { this.error(var9.getMessage(), ele); return null; } }
String[] aliasesArray1 = StringUtils.toStringArray(aliases); return new BeanDefinitionHolder(beanDefinition, beanName1, aliasesArray1); } else { return null; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; if(ele.hasAttribute("class")) { className = ele.getAttribute("class").trim(); }
try { String ex = null; if(ele.hasAttribute("parent")) { ex = ele.getAttribute("parent"); } AbstractBeanDefinition bd = this.createBeanDefinition(className, ex); this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description")); this.parseMetaElements(ele, bd); this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); this.parseConstructorArgElements(ele, bd); this.parsePropertyElements(ele, bd); this.parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(this.extractSource(ele)); AbstractBeanDefinition var7 = bd; return var7; } catch (ClassNotFoundException var13) { this.error("Bean class [" + className + "] not found", ele, var13); } catch (NoClassDefFoundError var14) { this.error("Class that bean class [" + className + "] depends on not found", ele, var14); } catch (Throwable var15) { this.error("Unexpected failure during bean definition parsing", ele, var15); } finally { this.parseState.pop(); }
return null; }
|
到此bean解析成BeanDefinition数据对象,就到此结束了,小洋也感觉到筋疲力尽了,但感觉还是很有成就感的,正准备歇息一番,突然一想,不妙啊,这里只是把bean标签解析成了BeanDefinition对象,可是我们getBean拿到的是一个实例对象啊。还有上面只看到了配置bean处理,还没有看扫描注解包的处理。小洋对此只能仰天长叹,道路还很长啊。后面看小洋如何披荆斩棘,雄霸天下。
我读的书愈多,就愈亲近世界,愈明了生活的意义,愈觉得生活的重要。
—— 高尔基