从上章里我们已经看到:

DispatcherServlet extends FrameworkServlet

FrameworkServlet extends HttpServletBean implements ApplicationContextAware

那么HttpServletBean作为DispatcherServlet的父类,起到了一个什么作用呢?

spring中这样描述的:

/**
* Simple extension of {@link javax.servlet.http.HttpServlet} which treats
* its config parameters ({@code init-param} entries within the
* {@code servlet} tag in {@code web.xml}) as bean properties.
*
* <p>A handy superclass for any type of servlet. Type conversion of config
* parameters is automatic, with the corresponding setter method getting
* invoked with the converted value. It is also possible for subclasses to
* specify required properties. Parameters without matching bean property
* setter will simply be ignored.
*
* <p>This servlet leaves request handling to subclasses, inheriting the default
* behavior of HttpServlet ({@code doGet}, {@code doPost}, etc).
*
* <p>This generic servlet base class has no dependency on the Spring
* {@link org.springframework.context.ApplicationContext} concept. Simple
* servlets usually don't load their own context but rather access service
* beans from the Spring root application context, accessible via the
* filter's {@link #getServletContext() ServletContext} (see
* {@link org.springframework.web.context.support.WebApplicationContextUtils}).
*
* <p>The {@link FrameworkServlet} class is a more specific servlet base
* class which loads its own application context. FrameworkServlet serves
* as direct base class of Spring's full-fledged {@link DispatcherServlet}.*/

我们可以从HttpServletBean的继承关系来分析它的作用:

HttpServletBean extends HttpServlet
implements EnvironmentCapable, EnvironmentAware

1. 继承了javax.servlet.http.HttpServlet

简单的说HttpServletBean是javax.servlet.http.HttpServlet类的简单扩展,在web.xml文件中<servlet>标签的下一级标签中通过<init-param>来配置该servlet的参数。实例如下:

    <!-- This servlet must be loaded first to configure the log4j
system and create the WebApplicationContext
-->
<servlet>
<servlet-name>config</servlet-name>
<servlet-class>org.springframework.framework.web.context.ContextLoaderServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.framework.web.context.XMLWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>log4jPropertiesUrl</param-name>
<param-value>/WEB-INF/log4j_PRODUCTION.properties</param-value>
</init-param>
<!-- This is essential -->
<load-on-startup>1</load-on-startup>
</servlet>

2. 继承了EnvironmentAware

EnvironmentAware到底起了什么作用呢?这需要我们首先了解一下Aware接口的作用:

/**
* Marker superinterface indicating that a bean is eligible to be
* notified by the Spring container of a particular framework object
* through a callback-style method. Actual method signature is
* determined by individual subinterfaces, but should typically
* consist of just one void-returning method that accepts a single
* argument.
*
* <p>Note that merely implementing {@link Aware} provides no default
* functionality. Rather, processing must be done explicitly, for example
* in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.
* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
* and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
* for examples of processing {@code *Aware} interface callbacks.
*
* @author Chris Beams
* @since 3.1
*/
public interface Aware { }

容器中定义的Bean一般不需要了解容器的状态或者直接使用容器,但是在某些情况下,是需要在Bean中直接对IOC容器进行操作的,这时候,就需要在Bean中设定对容器的感知。Spring IOC容器也提供了该功能,它是通过特定的Aware接口来完成的。这个比较抽象,我们来从代码来理解吧:

从spring-beans模块中我发现有三个实现了Aware接口,它们分别是:

BeanNameAware: Interface to be implemented by beans that want to be aware of their bean name in a bean factory. Note that it is not usually recommended that an object depend on its bean name, as this represents a potentially brittle dependence on external configuration, as well as a possibly unnecessary dependence on a Spring API.

BeanFactoryAware: Interface to be implemented by beans that wish to be aware of their owning {@link BeanFactory}.For example, beans can look up collaborating beans via the factory (Dependency Lookup). Note that most beans will choose to receive references to collaborating beans via corresponding bean properties or constructor arguments (Dependency Injection).

BeanClassLoaderAware: Callback that allows a bean to be aware of the bean {@link ClassLoader class loader}; that is, the class loader used by the present bean factory to load bean classes. This is mainly intended to be implemented by framework classes which  have to pick up application classes by name despite themselves potentially being loaded from a shared class loader.

上面三个接口分别实现了响应的set方法:

public interface BeanNameAware extends Aware {
void setBeanName(String name);
}
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface BeanClassLoaderAware extends Aware {
void setBeanClassLoader(ClassLoader classLoader);
}

从上述三个例子中,我们可以看到实现了Aware接口,bean就可以在spring容器中使用相应的对象。

那么我们来详细分析一个EnvironmentAware接口:

/**
* Interface to be implemented by any bean that wishes to be notified
* of the {@link Environment} that it runs in.
*
* @author Chris Beams
* @since 3.1
*/
public interface EnvironmentAware extends Aware { /**
* Set the {@code Environment} that this object runs in.
*/
void setEnvironment(Environment environment); }

我们来看一下HttpServletBean下的setEnvironment方法实现。

    /**
* {@inheritDoc}
* @throws IllegalArgumentException if environment is not assignable to
* {@code ConfigurableEnvironment}.
*/
@Override
public void setEnvironment(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
this.environment = (ConfigurableEnvironment) environment;
} /**
* {@inheritDoc}
* <p>If {@code null}, a new environment will be initialized via
* {@link #createEnvironment()}.
*/
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = this.createEnvironment();
}
return this.environment;
} /**
* Create and return a new {@link StandardServletEnvironment}. Subclasses may override
* in order to configure the environment or specialize the environment type returned.
*/
protected ConfigurableEnvironment createEnvironment() {
return new StandardServletEnvironment();
}

从上述代码中我们可以看到默认情况下的

environment=new StandardServletEnvironment()
StandardServletEnvironment 后续章节讲到,这里我们仅仅看作Spring抽象了一个Environment来表示环境配置。

3. 继承了EnvironmentCapable

/**
* Interface indicating a component that contains and exposes an {@link Environment} reference.
*
* <p>All Spring application contexts are EnvironmentCapable, and the interface is used primarily
* for performing {@code instanceof} checks in framework methods that accept BeanFactory
* instances that may or may not actually be ApplicationContext instances in order to interact
* with the environment if indeed it is available.
*
* <p>As mentioned, {@link org.springframework.context.ApplicationContext ApplicationContext}
* extends EnvironmentCapable, and thus exposes a {@link #getEnvironment()} method; however,
* {@link org.springframework.context.ConfigurableApplicationContext ConfigurableApplicationContext}
* redefines {@link org.springframework.context.ConfigurableApplicationContext#getEnvironment
* getEnvironment()} and narrows the signature to return a {@link ConfigurableEnvironment}.
* The effect is that an Environment object is 'read-only' until it is being accessed from
* a ConfigurableApplicationContext, at which point it too may be configured.
*
* @author Chris Beams
* @since 3.1
* @see Environment
* @see ConfigurableEnvironment
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
*/
public interface EnvironmentCapable { /**
* Return the {@link Environment} associated with this component.
*/
Environment getEnvironment(); }

4. Environment 环境配置信息

EnvironmentCapable 接口和EnvironmentAware分别实现抽象了
Environment getEnvironment();
void setEnvironment(Environment environment);

它的主要几个实现如下所示:

MockEnvironment:模拟的环境,用于测试时使用;

StandardEnvironment:标准环境,普通Java应用时使用,会自动注册System.getProperties() 和 System.getenv()到环境;

public class StandardEnvironment extends AbstractEnvironment {

    /** System environment property source name: {@value} */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment"; /** JVM system properties property source name: {@value} */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties"; @Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); //System.getProperties();
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));//System.getenv()
} }

其中

StandardServletEnvironment:标准Servlet环境,其继承了StandardEnvironment,Web应用时使用,除了StandardEnvironment外,会自动注册ServletConfig(DispatcherServlet)、ServletContext及JNDI实例到环境;

public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {

    /** Servlet context init parameters property source name: {@value} */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams"; /** Servlet config init parameters property source name: {@value} */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams"; /** JNDI property source name: {@value} */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties"; @Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
} @Override
public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
} }

5. 小结

HttpServletBean分别实现了HttpServlet,EnvironmentCapable,EnvironmentAware.

简单扩展HttpServlet,给各种类型的servlet提供了一个便利的超类,提供了对属性的操作。

关于属性操作,会在下一步文件中介绍。

spring mvc DispatcherServlet详解前传---HttpServletBean类的更多相关文章

  1. spring mvc DispatcherServlet详解之前传---前端控制器架构

    前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端.前端控制器既可以使用Filter实现 ...

  2. spring mvc DispatcherServlet详解之前传---FrameworkServlet

    做项目时碰到Controller不能使用aop进行拦截,从网上搜索得知:使用spring mvc 启动了两个context:applicationContext 和WebapplicationCont ...

  3. (转载)spring mvc DispatcherServlet详解之一---处理请求深入解析

    要深入理解spring mvc的工作流程,就需要先了解spring mvc的架构: 从上图可以看到 前端控制器DispatcherServlet在其中起着主导作用,理解了DispatcherServl ...

  4. spring mvc DispatcherServlet详解之四---视图渲染过程

    整个spring mvc的架构如下图所示: 现在来讲解DispatcherServletDispatcherServlet的最后一步:视图渲染.视图渲染的过程是在获取到ModelAndView后的过程 ...

  5. spring mvc DispatcherServlet详解之一---处理请求深入解析

    要深入理解spring mvc的工作流程,就需要先了解spring mvc的架构: 从上图可以看到 前端控制器DispatcherServlet在其中起着主导作用,理解了DispatcherServl ...

  6. spring mvc DispatcherServlet详解之三---request通过ModelAndView中获取View实例的过程

    整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet第二步:通过request从Controller获取ModelAndView.现在来讲解第三步:reques ...

  7. spring mvc DispatcherServlet详解之二---request通过Controller获取ModelAndView过程

    整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet通过request获取控制器Controller的过程,现在来讲解DispatcherServletDisp ...

  8. spring mvc DispatcherServlet详解之一--request通过HandlerMaping获取控制器Controller过程

    整个spring mvc的架构如下图所示: 现在来讲解DispatcherServletDispatcherServlet的第一步:获取控制器. HandlerMapping HandlerMappi ...

  9. spring mvc DispatcherServlet详解之interceptor和filter的区别

    首先我们看一下spring mvc Interceptor的功能及实现: http://wenku.baidu.com/link?url=Mw3GaUhCRMhUFjU8iIDhObQpDcbmmRy ...

随机推荐

  1. java之两个字符串的比较

    compareTo() 的返回值是int, 它是先比较对应字符的大小(ASCII码顺序)1.如果字符串相等返回值02.如果第一个字符和参数的第一个字符不等,结束比较,返回他们之间的差值(ascii码值 ...

  2. 系统默认字体Mac OS,Windows,XP,Lunix

    可查获的信息太少,目前得知的是以中文为例, OS : Helvetical,Lucida Grande(西文默认字体) Windows 7: Microsoft Yahei Xp : Simsun,T ...

  3. JQuery 点击控件获取当前坐标时不兼容IE7

    现在要求在点击文本框时,获取文本框的坐标,需要相对文本框的位置来显示信息. 思路就是,绑定文本框的click 事件,一旦有点击就触发,去调用clickevent 函数执行计算. $('#txt_m') ...

  4. PHP 关于MongoDB的操作

    <?php header("Content-type:text/html;charset=utf-8"); $m = new MongoClient(); // 连接 $db ...

  5. MySql数据库3【优化1】表的优化

    一.表结构的优化 1.标准化  标准化是在数据库中组织数据的过程.其中包括,根据设计规则创建表并在这些表间建立关系:通过取消冗余度与不一致相关性,该设计规则可以同时保护数据并提高数据的灵活性.通常数据 ...

  6. how to make choices about girls?

    yb ldge nvhl, yige hf csmn, hv bmig, hv zofj, hfyb uhjnxn;ldyige ybdm bfbfde, gjjt hf djip, djui hfk ...

  7. python之正则表达式备忘

    一简介:就其本质而言,正则表达式(或 RE)是一种小型的.高度专业化的编程语言,(在Python中)它内嵌在Python中,并通过 re 模块实现.正则表达式模式被编译成一系列的字节码,然后由用 C ...

  8. 20141127 测试使用Word2013书写博客(代码高亮+公式支持)。

      PS :又经过几次测试,发现用于Word2010的高亮插件在Word2013上排版效果不是很好,慎用.不过公式编辑倒是挺方便的 测试使用Word2013书写博客. 大概一个月前,使用WindowL ...

  9. [BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】

    题目链接: BZOJ - 3626 题目分析 考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就 ...

  10. Json传递后台数据的问题

    在后台我有两个类: public Class Person { private String name; private Address address;//一个自定义的类 //getter和sett ...