`
hotforcc
  • 浏览: 61255 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring DispatcherServlet MVC 源码分析(BeanFactory的初始化)

阅读更多

BeanFactory的初始化的触发——><o:p></o:p>

FrameworkServlet中的wac.refresh()<o:p></o:p>

<o:p> </o:p>
如下为初始化
MVC部分的操作:<o:p></o:p>

java 代码
  1. initmultipartresolver();  
  2. initlocaleresolver();  
  3. initthemeresolver();  
  4. inithandlermappings();  
  5. inithandleradapters();  
  6. inithandlerexceptionresolvers();  
  7. initviewresolver();  

<o:p></o:p>

<o:p> </o:p>

现在有一个疑问 initHandlerMappings(ApplicationContext context)中的ApplicationContext的实现在web中是哪一个,可以从下面得到结论<o:p></o:p>

<o:p> </o:p>

java 代码
 
  1. public static final Class DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;  
  2. private Class contextClass = DEFAULT_CONTEXT_CLASS;  

<o:p></o:p>

<o:p> </o:p>

可以看出这个地方是实例化的是XmlWebApplicationContext的一个实例,那么这个实例是在哪个地方被实例化的呢?在DispatchServelet的父类FrameworkServlet中可以找到如下的代码,<o:p></o:p>

<o:p> </o:p>

java 代码
  1. WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
  2. WebApplicationContext wac = createWebApplicationContext(parent);  

<o:p></o:p>

<o:p> </o:p>

ok,我们现在就可以用这个wac了,顺便看看这个实例里边都有什么东西:<o:p></o:p>

<o:p> </o:p>

java 代码
 
  1. wac.setParent(parent);//web.xml中加载的context  
  2. wac.setServletContext(getServletContext());  
  3. wac.setServletConfig(getServletConfig());  
  4. wac.setNamespace(getNamespace());  
  5. if (getContextConfigLocation() != null) {  
  6.     wac.setConfigLocations(  
  7.     StringUtils.tokenizeToStringArray(  
  8.     getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));  
  9. }//比较有用  
  10. wac.addApplicationListener(this);  

<o:p></o:p>

<o:p> </o:p>

继续我们的MVC探索--><o:p></o:p>

下面是MVC的部分,提前分析一下<o:p></o:p>

java 代码
 
  1. protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface) throws BeansException {  
  2.     String key = strategyInterface.getName();//equals org.springframework.web.servlet.HandlerMapping  
  3.     List strategies = null;  
  4.     String value = defaultStrategies.getProperty(key);  
  5.     //org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping.class  
  6.     if (value != null) {  
  7.         String[] classNames = StringUtils.commaDelimitedListToStringArray(value);//等效于split  
  8.         strategies = new ArrayList(classNames.length);  
  9.         for (int i = 0; i < classNames.length; i++) {  
  10.             String className = classNames[i];  
  11.             try {  
  12.                 Class clazz = ClassUtils.forName(className, getClass().getClassLoader());  
  13.                 Object strategy = createDefaultStrategy(context, clazz);  
  14.                 strategies.add(strategy);  
  15.             }  
  16.             catch (ClassNotFoundException ex) {  
  17.                 throw new BeanInitializationException(  
  18.                     "Could not find DispatcherServlet's default strategy class [" + className +  
  19.                     "] for interface [" + key + "]", ex);  
  20.             }  
  21.             catch (LinkageError err) {  
  22.                 throw new BeanInitializationException(  
  23.                     "Error loading DispatcherServlet's default strategy class [" + className +  
  24.                     "] for interface [" + key + "]: problem with class file or dependent class", err);  
  25.             }  
  26.         }  
  27.     }else {  
  28.         strategies = Collections.EMPTY_LIST;  
  29.     }  
  30.     return strategies;  
  31. }  
  32.   
  33. protected Object createDefaultStrategy(ApplicationContext context, Class clazz) throws BeansException {  
  34.     return context.getAutowireCapableBeanFactory().createBean(  
  35.         clazz, AutowireCapableBeanFactory.AUTOWIRE_NO, false);  
  36.         //org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping.class  
  37. }  

<o:p></o:p>

context XmlWebApplicationContext的一个实例,而<o:p></o:p>

<o:p> </o:p>

java 代码
 
  1. public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext  
  2.   
  3. public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableApplicationContext  
  4. implements ConfigurableWebApplicationContext, ThemeSource  
  5.   
  6. public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext   
  7.   
  8. public abstract class AbstractApplicationContext extends DefaultResourceLoader  
  9. implements ConfigurableApplicationContext, DisposableBean {  
  10.     public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {  
  11.         return getBeanFactory();  
  12.     }  
  13. }  
  14.   
  15. 在AbstractRefreshableApplicationContext中  
  16. public final ConfigurableListableBeanFactory getBeanFactory() {  
  17.     synchronized (this.beanFactoryMonitor) {  
  18.         if (this.beanFactory == null) {  
  19.             throw new IllegalStateException("BeanFactory not initialized or already closed - " +  
  20.             "call 'refresh' before accessing beans via the ApplicationContext");  
  21.         }  
  22.         return this.beanFactory;  
  23.     }  
  24. }  

<o:p>

说明这个时候BeanFactory已经初始化好了,那么在哪个地方初始化好的呢?可以想象到的地方就是XmlWebApplicationContextnew的时候会初始化这个BeanFactory?在WebApplicationContext createWebApplicationContext(WebApplicationContext parent)时候,也就是在初始化ApplicationContext的时候有如下操作<o:p></o:p>

<o:p> </o:p>

wac.refresh();<o:p></o:p>

<o:p> </o:p>

也就是初始化ApplicationContext之后会马上初始化BeanFacory<o:p></o:p>

从类结构里我们能找到这个方法来自它的父类: AbstractApplicationContext 在它的 refresh() 方法内我们可以看到 spring 的复杂逻辑。首先执行了refreshBeanFactory(); (来自 AbstractRefreshableApplicationContext )见 (a),<o:p></o:p>

<o:p> </o:p>

(a)refreshBeanFactory(); 这个方法由负责维护变量 beanFactory 的子类AbstractRefreshableApplicationContext 实现,默认情况下<o:p></o:p>

这个方法直接实例化一个新的 DefaultListableBeanFactory 类型的 BeanFacorty, <o:p></o:p>

java 代码
 
  1. protected final void refreshBeanFactory() throws BeansException {  
  2.     DefaultListableBeanFactory beanFactory = createBeanFactory();  
  3.     customizeBeanFactory(beanFactory);  
  4.     loadBeanDefinitions(beanFactory);  
  5. }  
  6. protected DefaultListableBeanFactory createBeanFactory() {  
  7.     return new DefaultListableBeanFactory(getInternalParentBeanFactory());  
  8. }  
  9.   
  10. AbstractApplicationContext.java  
  11. protected BeanFactory getInternalParentBeanFactory() {//判断用的是ApplicationContext or BeanFactory   
  12.     return (getParent() instanceof ConfigurableApplicationContext) ?  
  13.         ((ConfigurableApplicationContext) getParent()).getBeanFactory() : (BeanFactory) getParent();  
  14. }  
  15. public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory  
  16. implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {}  
  17.   
  18. XmlWebApplicationContext.java-->  
  19. /** 
  20. * Loads the bean definitions via an XmlBeanDefinitionReader. 
  21. * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 
  22. * @see #initBeanDefinitionReader 
  23. * @see #loadBeanDefinitions 
  24. */  
  25. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  
  26.     // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
  27.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  28.   
  29.     // Configure the bean definition reader with this context's  
  30.     // resource loading environment.  
  31.     beanDefinitionReader.setResourceLoader(this);  
  32.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  33.   
  34.     // Allow a subclass to provide custom initialization of the reader,  
  35.     // then proceed with actually loading the bean definitions.  
  36.     initBeanDefinitionReader(beanDefinitionReader);  
  37.     loadBeanDefinitions(beanDefinitionReader);  
  38. }  
  39. public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {  
  40. }  
  41. XmlBeanDefinitionReader 继承了 AbstractBeanDefinitionReader,AbstractBeanDefinitionReader的构造函数如下:  
  42. protected AbstractBeanDefinitionReader(BeanDefinitionRegistry beanFactory) {//DefaultListableBeanFactory实现了  
  43.                                         //BeanDefinitionRegistry   
  44.     Assert.notNull(beanFactory, "Bean factory must not be null");  
  45.     this.beanFactory = beanFactory;  
  46.     // Determine ResourceLoader to use.如果beanFactory不但实现了BeanDefinitionRegistry,而且实现了ResourceLoader   
  47.     //通常的这样的情况是实现了org.springframework.context.ApplicationContext的BeanFactory,这一点可以查看(c)部分  
  48.     if (this.beanFactory instanceof ResourceLoader) {  
  49.         this.resourceLoader = (ResourceLoader) this.beanFactory;  
  50.     }else {  
  51.         this.resourceLoader = new PathMatchingResourcePatternResolver();  
  52.     }  
  53. }  

<o:p></o:p>

初始化完了AbstractBeanDefinitionReader之后,继续XmlBeanDefinitionReaderd的初始化:<o:p></o:p>

java 代码
 
  1. public XmlBeanDefinitionReader(BeanDefinitionRegistry beanFactory) {  
  2.     if (getResourceLoader() != null) {//getResourceLoader已经得到  
  3.         this.entityResolver = new ResourceEntityResolver(getResourceLoader());  
  4.         //entityResolver  
  5.     }else {  
  6.         this.entityResolver = new DelegatingEntityResolver(ClassUtils.getDefaultClassLoader());  
  7.     }  
  8. }  

<o:p></o:p>

上面的初始化相当于初始化了 XmlBeanDefinitionReaderresourceLoaderentityResolver<o:p></o:p>

然后就是对各个配置路径的初始化工作:<o:p></o:p>

java 代码
 
  1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
  2.     String[] configLocations = getConfigLocations();  
  3.     if (configLocations != null) {  
  4.         for (int i = 0; i < configLocations.length; i++) {  
  5.             reader.loadBeanDefinitions(configLocations[i]);  
  6.         }  
  7.     }  
  8. }  

<o:p></o:p>

XmlBeanDefinitionReader中的初始化工作,因此所有的xml的解析实际上是在这个类文件中完成的 <o:p></o:p>

java 代码
 
  1. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {  
  2.     InputStream inputStream = encodedResource.getResource().getInputStream();  
  3.     try {  
  4.         InputSource inputSource = new InputSource(inputStream);  
  5.         if (encodedResource.getEncoding() != null) {  
  6.             inputSource.setEncoding(encodedResource.getEncoding());  
  7.         }  
  8.         return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  
  9.         }  
  10.         finally{  
  11.             inputStream.close();  
  12.         }  
  13.     }catch (IOException ex) {  
  14.         throw new BeanDefinitionStoreException(  
  15.         "IOException parsing XML document from " + encodedResource.getResource(), ex);  
  16.     }  
  17. }  
  18. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)  
  19.     throws BeanDefinitionStoreException {  
  20.     int validationMode = getValidationModeForResource(resource);  
  21.     Document doc = this.documentLoader.loadDocument(//获得解析的dom路径  
  22.         inputSource, this.entityResolver, this.errorHandler, validationMode, this.namespaceAware);  
  23.     return registerBeanDefinitions(doc, resource);  
  24. }  
  25.   
  26. (c)  
  27. public abstract class AbstractApplicationContext extends DefaultResourceLoader  
  28. implements ConfigurableApplicationContext, DisposableBean{};//AbstractApplicationContext继承了DefaultResourceLoader  
  29. public class DefaultResourceLoader implements ResourceLoader{}//DefaultResourceLoader实现了ResourceLoader  
  30. public DefaultResourceLoader() {//构造函数  
  31.         this.classLoader = ClassUtils.getDefaultClassLoader();  
  32. }  
  33. public static ClassLoader getDefaultClassLoader() {   
  34.     cl = Thread.currentThread().getContextClassLoader();//取得Application级的ClassLoader      
  35. }  

<o:p></o:p>

<o:p> </o:p>

<o:p> </o:p>

然后调用一个起缓冲作用的配置函数生成一个将 beanFacroty 包装起来的对象 beanDefinitionReader ,然后对这个对象进行属性配置,实际上该方法主要负责生成一个临时的操作对象,对应调用的函数为“loadBeanDefinitions(beanFactory);”该方法为初始化期间较为重要的一个。该方法来自其子类:AbstractRefreshableWebApplicationContext <o:p></o:p>

<o:p>

java 代码
 
  1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
  2.     String[] configLocations = getConfigLocations();// xml文件的配置的路径  
  3.     if (configLocations != null) {  
  4.         for (int i = 0; i < configLocations.length; i++) {  
  5.             reader.loadBeanDefinitions(configLocations[i]);  
  6.         }  
  7.     }  
  8. }  

<o:p>

对应的函数:<o:p></o:p>

protected void loadBeanDefinitions(DefaultListableBeanFactory) ,然后这里又调用了自己定义的 <o:p></o:p>

protected void loadBeanDefinitions(XmlBeanDefinitionReader) 方法。此时,它就使用到了在以前中设置了的( wac.setConfigLocations(……)) 我们开发中密切相关的配置文件。(同时也要记住此时这个函数的参数 beanDefinitionReader ,之前已经设置了”beanDefinitionReader.setResourceLoader(this) “这里的 this 是我们在前面见到的 XmlWebApplicationContext (一个定义好了的上下文))。接着往下:reader.loadBeanDefinitions(configLocations[i]); reader 开始加载我们配置文件内的东西了,不过真正复杂的实现此时才开始,我们继续往下走,在接下来的方法内默认情况下会执行:if (resourceLoader instanceof ResourcePatternResolver)(该判断条件为true ,由于从上面我们知道: beanDefinitionReader.setResourceLoader(this); this 的类型为: XmlWebApplicationContext所以 ((ResourcePatternResolver) resourceLoader).getResources(location); 得到一个 Resource[] 数组,接下来调用:int loadCount = loadBeanDefinitions(resources); 该函数继续调用自己子类定义的一系列临时接口最终执行到 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); 在这个函数内初始化了处理 xml 文件的一些对象并将用户的配置文件解析为一个 Document 对象。然后又执行了一系列函数直到return parser.registerBeanDefinitions(this, doc, resource); 这个函数来自我们新建的 DefaultXmlBeanDefinitionParser,在这个类里最终执行了对 xml 文件的解析工作和对 beanFacroty 变量执行了设置工作。<o:p></o:p>

<o:p> </o:p>

(b)终于我们从这些繁杂的逻辑中跳了出来,继续执行 AbstractApplicationContext.refresh() 下面的工作,后续的代码主要仍旧是往一些常量里面设值。<o:p></o:p>

<o:p> </o:p>

此时 Spring BeanFactory初始化过程就结束了。
分享到:
评论

相关推荐

    Spring源码分析.rar

    在Spring框架的源码中,BeanFactory是管理bean的核心接口,它负责bean的实例化、初始化、装配和查找。而ApplicationContext是BeanFactory的扩展,增加了对国际化、事件传播、资源加载等功能,它是Spring应用的主要...

    spring-mvc 程序结构以及调用流程

    在Spring MVC应用中,DispatcherServlet作为Web层的核心,在web.xml中配置后,它会负责整个Web层的初始化工作,包括加载HandlerMapping、Controller等。 HandlerMapping用于将HTTP请求映射到对应的Controller处理器...

    Spring2(源码)

    源码分析是理解Spring工作原理的关键,能帮助开发者深入掌握如何在实际项目中有效地使用和优化Spring。下面将对Spring框架的核心组件、设计理念以及源码中的关键部分进行详细的解释。 1. **依赖注入(DI)** - ...

    spring源码中英文注释

    8. **事件驱动**:Spring框架允许应用在特定事件(如bean的初始化或销毁)发生时进行响应。`ApplicationEvent`和`ApplicationListener`接口是实现事件驱动的关键。 9. **国际化与本地化**:Spring提供了`...

    深入剖析Spring Web源码(含一二版)带目录

    - **Bean的生命周期**:从BeanFactory到ApplicationContext,了解Bean的实例化、初始化、依赖注入、作用域和销毁过程。 - **AOP(面向切面编程)**:理解切点、通知、代理等概念,以及如何在Spring中实现AOP。 - ...

    spring mvc中文教程

    1. **配置DispatcherServlet**:在 web.xml 文件中配置 DispatcherServlet,指定初始化参数以加载 Spring 配置文件。 2. **定义控制器**:控制器类需要使用 `@Controller` 注解标记,方法上可以使用 `@...

    spring2.5源码包

    通过 `ApplicationContext` 的测试版,我们可以方便地在测试环境中初始化和管理 Bean。 总的来说,Spring 2.5 源码包是一份宝贵的教育资源,它揭示了 Spring 框架的强大功能和优雅设计。通过学习这些源码,开发者...

    Spring MVC原理

    例如,DispatcherServlet的初始化过程中,会通过BeanFactory获取所有配置的HandlerMapping和HandlerAdapter,这体现了IoC;而拦截器的链式调用则是AOP的应用。 工具方面,Spring MVC与IDE(如Eclipse、IntelliJ ...

    spring、spring-mvc学习总结-.pdf

    Bean的生命周期包括初始化、使用和销毁三个阶段,开发者可以自定义这些阶段的行为。 在Web环境中,通常使用Servlet监听器来加载`applicationContext.xml`,并使用`FileSystemXmlApplicationContext`或`...

    spring-frameword3.0源码

    在这个模块中,我们可以深入理解BeanFactory和ApplicationContext的区别,以及如何自定义bean的初始化和销毁行为。 4. `org.springframework.web.servlet`:这部分源码主要处理HTTP请求,实现了MVC架构。我们能从中...

    Spring-framework源码工程

    它负责管理对象的生命周期和装配,源码里可以学习到Bean的创建、初始化、配置和查找过程。 4. **数据访问抽象层**:Spring 提供了对各种数据存取技术的抽象,包括JDBC、ORM(如Hibernate、MyBatis)、OXM(对象-XML...

    最全中文注释版Spring4源码

    源码中的注释将帮助我们理解`BeanFactory`和`ApplicationContext`是如何加载和管理Bean的生命周期,包括初始化、装配、销毁等过程。此外,我们还可以通过注释了解`@Component`、`@Service`、`@Repository`和`@...

    官方原版源码 spring-framework-5.2.9.RELEASE.zip

    1. **ApplicationContext**:这是Spring的核心接口,负责初始化、加载配置文件,管理Bean的生命周期。源码中可以看到它是如何解析XML或Java配置,创建并管理Bean的。 2. **BeanFactory**:作为ApplicationContext的...

    spring源码下载

    1. **Bean的生命周期**:研究BeanFactory和ApplicationContext接口,了解如何加载和管理Bean,以及Bean的初始化、销毁过程。 2. **AOP的实现**:查看AOP代理(JDK动态代理和CGLIB)的实现,理解切面如何织入目标...

    spring-code-based

    1. org.springframework.web.servlet.DispatcherServlet:这是 Spring MVC 的入口点,源码中可以看到它如何初始化 MVC 配置,并进行请求调度。 2. org.springframework.web.servlet.mvc.method.annotation....

    spring5源码

    `BeanDefinition`类是Bean的元信息,它包含Bean的类型、初始化方法、依赖关系等信息。`BeanPostProcessor`接口允许自定义Bean的后处理器,可以在Bean实例化前后执行自定义逻辑。 在AOP部分,`Aspect`和`Advice`是...

    spring 源码四

    Spring管理的对象称为Bean,其生命周期包括初始化、正常运行以及销毁三个阶段。BeanFactory和ApplicationContext提供了各种回调方法,如init-method、postProcessBeforeInitialization、...

    Spring2.0.8源码包

    在这个版本中,你将看到如何通过`BeanFactory`和`ApplicationContext`接口来管理bean的实例化、初始化、装配和销毁。 `spring-context`模块扩展了`spring-beans`,引入了上下文的概念,提供了更丰富的特性,如AOP...

    spring4源码

    Spring 4 源码分析 Spring 是一个广泛使用的开源 Java 框架,它以其模块化、灵活性和全面的企业级应用支持而闻名。Spring 4 版本引入了许多改进和新特性,使得开发者能够更高效地构建和管理应用程序。在深入研究 ...

    spring源码分析

    源码中,`BeanFactory`和`ApplicationContext`定义了对bean的创建、初始化、容器中的注册以及销毁的接口方法。 3. **AOP(面向切面编程)** - AOP使得我们可以在不修改业务代码的情况下,对程序进行功能增强,如...

Global site tag (gtag.js) - Google Analytics