十一小长假在家玩和太happy了。根本没有时间看java之类的东西,今天是假日最后一天,所以会把上次的补上
个人感觉在web中看spring如何解析如何运行是一件比较难的事,spring附加了在我们看来是没有用的代码,但是既然它写了肯定是有用处的,这是我们初级程序员可以学习的地方。好了不多说了。看代码
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
我们来看看ClassPathXmlApplicationContext的构造器
public ClassPathXmlApplicationContext(String configLocation)
/* */ throws BeansException
/* */ {
/* 83 */ this(new String[] { configLocation }, true, null);
/* */ }
为什么我的反编译有行数的。。你问我。。我也不知道。。。。
this是当前类继续看
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
/* */ throws BeansException
/* */ {
/* 136 */ super(parent);
/* 137 */ setConfigLocations(configLocations);
/* 138 */ if (refresh)
/* 139 */ refresh();
/* */ }
先看下super。。。super调用的是父类构造器
看下AbstractXmlApplicationContext
public AbstractXmlApplicationContext(ApplicationContext parent)
/* */ {
/* 58 */ super(parent);
/* */ }
还是一样。。继续看
看下AbstractRefreshableConfigApplicationContext
public AbstractRefreshableConfigApplicationContext(ApplicationContext parent)
{
super(parent);
}
还是一样。继续看下AbstractRefreshableApplicationContext
public AbstractRefreshableApplicationContext(ApplicationContext parent)
{
super(parent);
}
看下AbstractApplicationContext
public AbstractApplicationContext(ApplicationContext parent)
{
this.logger = LogFactory.getLog(getClass());
this.id = ObjectUtils.identityToString(this);
this.beanFactoryPostProcessors = new ArrayList();
this.active = false;
this.activeMonitor = new Object();
this.startupShutdownMonitor = new Object();
this.applicationListeners = new ArrayList();
this.parent = parent;
this.resourcePatternResolver = getResourcePatternResolver();
}
上面没有什么好看的。无非是初始化我们看下最后this.resourcePatternResolver = getResourcePatternResolver();
protected ResourcePatternResolver getResourcePatternResolver()
{
return new PathMatchingResourcePatternResolver(this);
}
这是我自己写的PathMatchingResourcePatternResolver
public static void main(String[] args){
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = null;
try {
resources = resolver.getResources("file:"+System.getProperty("user.dir")+"/WebRoot/WEB-INF/spring01/*/*.xml");
System.out.println(resources[0].getURL());
System.out.println(resources.length);
} catch (IOException e) {
e.printStackTrace();
}
}
这个类是干嘛的就是匹配*的,所以我们配spring.xml不用一个一个去配了。直接用这类,就行了。。
AbstractApplicationContext中主要是初始化。看不看意义不大,关键看下这个
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException
{
super(parent);
setConfigLocations(configLocations);
if (refresh)
refresh();
}
setConfigLocations(configLocations);这个不用说了吧。。。更简单了,把spring.xml的名字放进来嘛
看下if (refresh)
refresh();
其实refresh肯定为true,这个我们应该能感觉到,事实也是这样
public ClassPathXmlApplicationContext(String configLocation)
throws BeansException
{
this(new String[] { configLocation }, true, null);
}
直接把true传过来了
关键是看下refresh()这个方法。。我们来看下。。。。refresh()这个方法是在AbstractApplicationContext这个类中,spring的目的是解耦合,但是他自己写的确实耦合度不是一般的高
public void refresh() throws BeansException, IllegalStateException
{
synchronized (this.startupShutdownMonitor)
{
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try
{
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
catch (BeansException ex)
{
beanFactory.destroySingletons();
cancelRefresh(ex);
throw ex;
}
}
}
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
这个我们这里就不看了。无非是同步一些东西,看也看不懂,继续
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
我们看下obtainFreshBeanFactory这个方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory()
{
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (this.logger.isInfoEnabled()) {
this.logger.info("Bean factory for application context [" + getId() + "]: " + ObjectUtils.identityToString(beanFactory));
}
if (this.logger.isDebugEnabled()) {
this.logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
}
return beanFactory;
}
看下refreshBeanFactory()这个方法
protected abstract void refreshBeanFactory()
throws BeansException, IllegalStateException;
在他自己类中是这样写的。我们是看父类代码还是看子类代码呢。。。肯定是看子类的代码吗。abstract在,,那不用看了。。去他的子类找一找
在AbstractRefreshableApplicationContext中找到了refreshBeanFactory()的实现
protected final void refreshBeanFactory()
throws BeansException
{
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
}
}
我们看下第一个if()中写的是hasBeanFactory()英文意思写得非常明白是滞有bean工厂吗,有的话销毁beans还有关闭bean工厂吗。如果你是第一次初始化就直接看下try-catch里面代码好了
DefaultListableBeanFactory beanFactory = createBeanFactory();
这个是实例化beanFactory其实我们不用看的。浪费时间。。。。
继续
customizeBeanFactory(beanFactory);定制客户的专属bean工厂也不用看的
关键的来了
loadBeanDefinitions(beanFactory);我们看下原码
在它的本类中
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory paramDefaultListableBeanFactory)
throws IOException, BeansException;
写的又是这样一句话。。。。看子类嘛。。。。其实第一次看真的会晕
在AbstractXmlApplicationContext这个类中实现了loadBeanDefinitions的方法。看下
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws IOException
{
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
我们看最关键的
loadBeanDefinitions(beanDefinitionReader);
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException, IOException
{
Resource[] configResources = getConfigResources();
if (configResources != null)
reader.loadBeanDefinitions(configResources);
String[] configLocations = getConfigLocations();
if (configLocations != null)
reader.loadBeanDefinitions(configLocations);
}
getConfigResources();
protected Resource[] getConfigResources()
{
return null;
}
你说看了有什么用。。。直接不用看
String[] configLocations = getConfigLocations();
我们刚刚在refresh()上面是不是setConfigLocations()了;
那这里我们不就是直接获得了嘛,简单
if (configLocations != null)
reader.loadBeanDefinitions(configLocations);
这里configLocations肯定不为空啊。
看下
public int loadBeanDefinitions(String[] locations) throws BeanDefinitionStoreException
{
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
for (int i = 0; i < locations.length; ++i)
<pre class="html" name="code">counter += loadBeanDefinitions(locations[i]);
return counter;
}
看下
counter += loadBeanDefinitions(locations[i]);
我就直接copy出来了
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set actualResources)
throws BeanDefinitionStoreException
{
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
try
{
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
loadCount = loadBeanDefinitions(resources);
if (actualResources != null)
for (int i = 0; i < resources.length; ++i)
actualResources.add(resources[i]);
if (this.logger.isDebugEnabled())
this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null)
actualResources.add(resource);
if (this.logger.isDebugEnabled())
this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
return loadCount;
}
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
这个方法可以去看看上面我写的PathMatchingResourcePatternResolver这个类。。你就知道干嘛的了
loadCount = loadBeanDefinitions(resources);
主要看下这个
public int loadBeanDefinitions(Resource[] resources) throws BeanDefinitionStoreException
{
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (int i = 0; i < resources.length; ++i)
counter += loadBeanDefinitions(resources[i]);
return counter;
}
点开loadBeanDefinitions里进入到BeanDefiitionReader中的方法
public abstract int loadBeanDefinitions(Resource paramResource)
throws BeanDefinitionStoreException;
还是看子类啊
看下XmlBeanDifintionReader
public int loadBeanDefinitions(Resource resource)
throws BeanDefinitionStoreException
{
return loadBeanDefinitions(new EncodedResource(resource)); }
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
}
看下doLoadBeanDefinitions这个类
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException
{
int validationMode;
try
{
validationMode = getValidationModeForResource(resource);
Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex)
{
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex)
{
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex)
{
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex)
{
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex);
}
}
看到Document这个类了吗,肯定是dom解析xml吗。。这里我们不用管了。解析xml不是spring的范围。所以不用太在意。下一篇会总结一下。。。其实也不用总结了。。。差不多就是这个过程 。web中也是这样调的。。。。。。。。看懂了这个。。。差不多。。。web也没有问题
个人写得比较详细,第一个是让自己更好的学习,也希望大家有问题可以和我说。。大家一起进步