Spring MVC源码解析
来源:互联网 发布:女流和陈一发 知乎 编辑:程序博客网 时间:2024/06/05 15:17
转载请标明出处 http://coderknock.com
XXXAware
XXXAware在Spring中该类接口用于通过Spring自动向XXXAware实现类中实现的setXXX(XXX xxx)方法中注入XXX对象,方便在实现类中调用XXX对象。
例如:
A类需要使用当前的ApplicationContext,那么只要是A实现ApplicationContextAware接口,然后实现接口中的setApplicationContext(ApplicationContext applicationContext)方法,Spring就会自动调用setApplicationContext方法将applicationContext传给A类。
XXXCapable
实现XXXCapable接口后说明该实现类具有提供XXX的能力,当Spring需要XXX时会通过该类的getXXX方法来获取XXX对象。
Environment
Environment具体功能与Servlet中的ServletContext类似。
HttpServletBean中Environment使用的是StandardServletEnvironment。
@Override public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = this.createEnvironment(); } return this.environment; } protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); }
StandardServletEnvironment中封装了ServletContext、ServletConfig、JndiProperty、系统环境变量以及系统属性。
StandardServletEnvironment{ activeProfiles=[ ], defaultProfiles=[ default ], propertySources=[ servletConfigInitParams, servletContextInitParams, jndiProperties, systemProperties, systemEnvironment ]}
具体属性大家可以调试一下查看
转载请标明出处 http://coderknock.com
Servlet在创建时会直接调用无参init方法
HttpServletBean的init方法如下:
@Override public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet '" + getServletName() + "'"); } try { // 将web.xml中init-param参数封装到pvs变量中,requiredProperties是指必须的一些参数,没有的话会报错 PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties); //bw是对DispatcherServlet的封装 //【BeanWrpper是Spring提供的用于操作JavaBean属性的一个工具类,通过它封装一个对象后可以直接修改对象的属性】 BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext()); bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment())); //对DispatcherServlet做一些初始化的工作 initBeanWrapper(bw); //将配置值设置到DispatcherServlet bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); throw ex; } // 子类通过该方法初始化【该类中只是声明了该方法】 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet '" + getServletName() + "' configured successfully"); } } protected void initServletBean() throws ServletException { }
转载请标明出处 http://coderknock.com
FrameworkServlet,通过之前HttpServletBean详解,我们知道,FrameworkServlet是通过initServletBean来实现自身的初始化的。我们看一下initServletBean:
@Override protected final void initServletBean() throws ServletException { getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); if (this.logger.isInfoEnabled()) { this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); } long startTime = System.currentTimeMillis(); try { this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); } catch (ServletException ex) { this.logger.error("Context initialization failed", ex); throw ex; } catch (RuntimeException ex) { this.logger.error("Context initialization failed", ex); throw ex; } if (this.logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } } protected void initFrameworkServlet() throws ServletException { }
可以看到这个方法中的核心语句:
this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();
其中initFrameworkServlet是供子类Override后实现自身的一些初始化工作【DispatcherServlet中并没有对initFrameworkServlet进行Override】。
可见,FrameworkServlet在构建工程中主要作用就是初始化webApplicationContext:
protected WebApplicationContext initWebApplicationContext() {//获取rootContext WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; //判断是否在构造方法中以及初始化了webApplicationContext if (this.webApplicationContext != null) { // 一个WebApplicationContext实例在构建实例的时候被注入 wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { // 上下文尚未Refresh -> 配置并Refresh // 设置父上下文,设置WebApplicationContext id等等 if (cwac.getParent() == null) { // 如果上下文被注入时没有明确的设置Parent,则在这里设置 // 设置rootContext为Parent【可能为null】 cwac.setParent(rootContext); } configureAndRefreshWebApplicationContext(cwac); } } } if (wac == null) { //如果在构建实例时没有注入WebApplicationContext //查找WebApplicationContext是否已经存在于ServletContext中【通过配置在Servlet中的contextAttribute获取】 wac = findWebApplicationContext(); } if (wac == null) { // 如果还是没有WebApplicationContext,那么创建一个 wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { // 如果还是没有WebApplicationContext 既不是一个ConfigurableApplicationContext支持Refresh,并且WebApplicationContext注入时没有Refresh- >手动触发onRefresh【供子类Override】。 onRefresh(wac); } if (this.publishContext) { // 将WebApplicationContex保存到ServletContext String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (this.logger.isDebugEnabled()) { this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute with name [" + attrName + "]"); } } return wac; } protected void onRefresh(ApplicationContext context) { // For subclasses: do nothing by default. }
initWebApplicationContext做了三件事:
1. 获取Spring都得rootContext
Spring默认将rootContext设置于ServletContext的属性中,属性名为ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
- 设置WebApplicationContext并根据情况调用onRefresh方法
设置WebApplicationContext一共三种方法:
一、构造方法传入
这种方法主要用于Servlet3.0以后的环境中,在程序中使用ServletContext.addServlet方式注册Servlet,这时可以在新建FrameworkServlet和其子类时通过构造方法传递WebApplicationContext
二、WebApplicationContext已经存在ServletContext中,这是只要将DispatcherServlet配置是将WebApplicationContext配置到contextAttribute就可以。
三、创建一个WebApplicationContext【最终调用下面的方法】
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { //获取要创建的类型 Class<?> contextClass = getContextClass(); if (this.logger.isDebugEnabled()) { this.logger.debug("Servlet with name '" + getServletName() + "' will try to create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", using parent context [" + parent + "]"); } //检查获取到的类似是否是ConfigurableWebApplicationContext的子类 if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException( "Fatal initialization error in servlet with name '" + getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext"); } //具体创建 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); wac.setParent(parent); //将servlet配置地址【web.xml contextConfigLocation设置】 wac.setConfigLocation(getContextConfigLocation()); configureAndRefreshWebApplicationContext(wac); return wac; } protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + "/" + getServletName()); } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); //添加ContextRefreshListener wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); } postProcessWebApplicationContext(wac); applyInitializers(wac); wac.refresh(); }
- 将WebApplicationContext设置到ServletContext中
总结一下可配置项:
1. contextAttribute:在ServletContext中,用作WebApplicationContext的属性名称
2. contextClass:创建的WebApplicationContext的类型
3. contextConfigLocation:SpringMVC配置文件的位置
4. publishContext:是否将WebApplicationContext设置到ServletContext中。
转载请标明出处 http://coderknock.com
通过之前FrameworkServlet的分析,我们知道DispatcherServlet的入口方法是onRefresh。
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
onRefresh调用了initStrategies,initStrategies中初始化了九大组件,其中的initXXXX方法基本实现都是通过WebApplicationContext.getBean(名称, class);
获取注册的对应组件,如果找不到会通过getDefaultStrategy
方法获取默认的组件。
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) { List<T> strategies = getDefaultStrategies(context, strategyInterface); if (strategies.size() != 1) { throw new BeanInitializationException( "DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]"); } return strategies.get(0); }protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) { String key = strategyInterface.getName(); String value = defaultStrategies.getProperty(key); if (value != null) { String[] classNames = StringUtils.commaDelimitedListToStringArray(value); List<T> strategies = new ArrayList<T>(classNames.length); for (String className : classNames) { try { Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader()); Object strategy = createDefaultStrategy(context, clazz); strategies.add((T) strategy); } catch (ClassNotFoundException ex) { throw new BeanInitializationException( "Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", ex); } catch (LinkageError err) { throw new BeanInitializationException( "Error loading DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]: problem with class file or dependent class", err); } } return strategies; } else { return new LinkedList<T>(); } } private static final Properties defaultStrategies; static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage()); } }
getDefaultStrategy调用了getDefaultStrategies,而getDefaultStrategies是通过defaultStrategies来查找value值的。defaultStrategies对应的是DispatcherServlet.properties:
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
这里的默认设置并不是最优配置,也不是Spring推荐配置,只是为了防止没有配置。
这些默认配置是在没有配置时才会使用,使用<mvc:annotation-driven/>
之后并不会全部使用默认配置。<mvc:annotation-driven/>
会配置HandlerMapping、HandlerAdapter、HandlerExceptionResolver等。
- Spring MVC源码解析
- Spring MVC源码解析简介
- Spring mvc 源码解析之初始化
- Spring MVC源码分析—Servlet解析
- Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析
- Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析
- spring mvc json及各类视图解析 源码分析
- Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析
- Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析
- spring mvc json及各类视图解析 源码分析
- Spring mvc 视图解析器 ContentNegotiatingViewResolver 源码分析
- spring MVC (4) spring MVC 的重定向和源码解析
- Spring MVC源码分析
- spring mvc 源码小解
- Spring Mvc 源码理解。
- Spring MVC 源码
- Spring MVC源码分析
- Spring MVC源码剖析
- 求质数的几种算法
- [打字练习]Three
- 开启windows系统ssh登录管理
- 解密SparkStreaming另类实验及SparkStreaming本质解析(第一篇)
- Android 读取assets中的Json文件
- Spring MVC源码解析
- 2016中国首届虚拟现实+高峰论坛 报名者蜂拥而至
- madplay 的移植
- CocoaPods安装 使用
- Java学习-21天
- csdn规则
- IO与NIO
- 数据库创建emp和dept练习表
- Codeforces 246B-Increase and Decrease【模拟】