项目架构分析-web.xml文件解读

来源:互联网 发布:网络攻防大赛 编辑:程序博客网 时间:2024/06/12 23:06

利用闲暇时间多刚刚结束的项目进行总结,这是一个普惠系统。支持业务员进件、审核、流转,同时支持管理员对员工、权限等进行管理。项目采用dubbo框架,前台用了freemarker+bootstrap。这里开始分析系统架构,从web.xml开始。

web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://java.sun.com/xml/ns/javaee"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"         version="2.5">    <display-name>Manage Server</display-name>    <!--在tomcat下部署两个或多个项目时,web.xml文件中最好定义webAppRootKey参数,如果不定义,将会缺省为“webapp.root”-->    <context-param>        <param-name>webAppRootKey</param-name>        <param-value>Manage-Server.root</param-value>    </context-param>    <!-- 添加日志监听器 -->    <!--logbackConfigLocation以及下面的监听是logback相关配置-->    <context-param>        <param-name>logbackConfigLocation</param-name>        <param-value>classpath:logback.xml</param-value>    </context-param>    <listener>        <listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>    </listener>    <!--contextConfigLocation参数定义了需要装入spring的配置文件-->    <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>            classpath:spring/applicationContext-*.xml            classpath:spring/dubbo-consumer-parent.xml        </param-value>    </context-param>    <!-- Spring 刷新Introspector防止内存泄露 -->    <listener>        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>    </listener>    <listener>        <listener-class>            com.myph.manage.common.listener.CustomContextLoaderListener        </listener-class>    </listener>    <filter>        <filter-name>SetCharacterEncoding</filter-name>        <filter-class>            org.springframework.web.filter.CharacterEncodingFilter        </filter-class>        <init-param>            <param-name>encoding</param-name>            <param-value>utf-8</param-value>        </init-param>        <init-param>            <param-name>forceEncoding</param-name>            <param-value>true</param-value>        </init-param>    </filter>    <filter>        <filter-name>shiroFilter</filter-name>        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>        <init-param>            <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->            <param-name>targetFilterLifecycle</param-name>            <param-value>true</param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>SetCharacterEncoding</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>    <filter-mapping>        <filter-name>shiroFilter</filter-name>        <url-pattern>*.htm</url-pattern>    </filter-mapping>    <filter>        <filter-name>sessionFilter</filter-name>        <filter-class>com.myph.common.filter.SessionFilter</filter-class>        <init-param>            <!-- 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 -->            <param-name>targetFilterLifecycle</param-name>            <param-value>true</param-value>        </init-param>    </filter>    <filter-mapping>        <filter-name>sessionFilter</filter-name>        <url-pattern>*.htm</url-pattern>    </filter-mapping>    <filter>        <filter-name>AntiXssFilter</filter-name>        <filter-class>com.myph.manage.common.util.AntiXssFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>AntiXssFilter</filter-name>        <url-pattern>*.jsp</url-pattern>        <url-pattern>*.html</url-pattern>        <url-pattern>*.htm</url-pattern>        <url-pattern>/</url-pattern>        <dispatcher>REQUEST</dispatcher>        <dispatcher>FORWARD</dispatcher>        <dispatcher>ERROR</dispatcher>        <dispatcher>INCLUDE</dispatcher>    </filter-mapping>    <servlet>        <servlet-name>mvc</servlet-name>        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>        <init-param>            <param-name>contextConfigLocation</param-name>            <param-value>                classpath:spring/spring-app-mvc.xml            </param-value>        </init-param>        <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>        <servlet-name>mvc</servlet-name>        <url-pattern>*.htm</url-pattern>    </servlet-mapping>    <session-config>        <session-timeout>420</session-timeout>    </session-config>    <welcome-file-list>        <welcome-file>login.htm</welcome-file>    </welcome-file-list>    <!-- Error Page定义 -->    <error-page>        <error-code>404</error-code>        <location>/error/404.html</location>    </error-page>    <error-page>        <error-code>500</error-code>        <location>/error/500.html</location>    </error-page></web-app>

WEB工程加载web.xml过程

web工程在启动时,会先读取web.xml配置文件中的配置,当这一步正确完成时,项目才能被正常启动起来。
1、启动项目时,首先会读取<listener>节点和<context-param>节点。
2、创建一个ServletContext(servlet上下文),这个web项目的所有部分都共享这个上下文。
3、容器将<context-param>转换键值对,并交给servletContext。
4、容器将创建<listener>中的类实例,创建监听。
web.xml中,各个元素的加载顺序是一定的,与各元素即使在文件中顺序无关。
servletContext–context-param–listener–filter–servlet。
需要注意的是,同一元素的加载是按顺序加载的,例如filter与filter-mapping,必须先定义filter,才能正确解析对应名字的filter-mapping。

webAppRootKey

web项目配置webAppRootKey 获得根目录。
Spring通过 org.springframework.web.util.WebAppRootListener 这个监听器来压入项目路径。但是如果在web.xml中已经配置了 ch.qos.logback.ext.spring.web.LogbackConfigListener这个监听器,则不需要配置WebAppRootListener了。因为Log4jConfigListener已经包含了WebAppRootListener的功能。

contextConfigLocation

contextConfigLocation参数定义了需要装入spring的配置文件。

IntrospectorCleanupListener

在服务器运行过程中,Spring不停的运行的计划任务和OpenSessionInViewFilter,使得Tomcat反复加载对象而产生框架并用时可能产生的内存泄漏,则使用IntrospectorCleanupListener作为相应的解决办法。
spring中的提供了一个名为org.springframework.web.util.IntrospectorCleanupListener的监听器。它主要负责处理由 JavaBeans Introspector的使用而引起的缓冲泄露。spring中对它的描述如下:它是一个在web应用关闭的时候,清除JavaBeans Introspector的监听器.web.xml中注册这个listener.可以保证在web 应用关闭的时候释放与掉这个web 应用相关的class loader 和由它管理的类如果你使用了JavaBeans Introspector来分析应用中的类,Introspector 缓冲中会保留这些类的引用.结果在你的应用关闭的时候,这些类以及web 应用相关的class loader没有被垃圾回收.不幸的是,清除Introspector的唯一方式是刷新整个缓冲.这是因为我们没法判断哪些是属于你的应用的引用.所以删除被缓冲的introspection会导致把这台电脑上的所有应用的introspection都删掉.需要注意的是,spring 托管的bean不需要使用这个监听器.因为spring它自己的introspection所使用的缓冲在分析完一个类之后会被马上从javaBeans Introspector缓冲中清除掉.应用程序中的类从来不直接使用JavaBeans Introspector.所以他们一般不会导致内部查看资源泄露.但是一些类库和框架往往会产生这个问题。

CustomContextLoaderListener

这是我们项目自己实现的监听,由于项目采用dubbo框架,dubbo默认使用log4j作为日志输出,而我们项目是采用logback来输出日志。
因此通过监听,设置切换成slf4j。

public class CustomContextLoaderListener extends ContextLoaderListener {    static{        //设置dubbo使用slf4j来记录日志        System.setProperty("dubbo.application.logger","slf4j");    }}

CharacterEncodingFilter

这是spring MVC提供的字符集过滤器,防止乱码。

shiroFilter

项目中用了shiro来管理权限,这里用了代理来注入spring bean,先filter中加入DelegatingFilterProxy类,”targetFilterLifecycle”指明作用于filter的所有生命周期。
原理是,DelegatingFilterProxy类是一个代理类,所有的请求都会首先发到这个filter代理,然后再按照”filter-name”委派到spring中的这个bean。
关于shiro,稍后再总结。
在Spring中配置的bean的name要和web.xml中的<filter-name>一样,在项目中是这样配置的:

    <!--shiro过滤器配置,bean的id值须与web中的filter-name的值相同-->    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <property name="securityManager" ref="securityManager"/>        <property name="loginUrl" value="/login.htm"/>        <property name="successUrl" value="/index.htm"/>  <!-- 登陆成功之后跳转的页面 -->        <property name="unauthorizedUrl" value="/unauthorized.htm"/>        <property name="filters">            <map>                <entry key="authc" value-ref="formAuthenticationFilter"/>                <entry key="concurrentlogin" value-ref="concurrentLoginControlFilter"/>            </map>        </property>        <property name="filterChainDefinitions">            <value>                /css/** = anon                /js/** = anon                /images/** = anon                /commom/** = anon                /unauthorized.htm = anon                /login.htm=anon                /sendLoginSmsCode.htm=anon                /dologin.htm=anon                /**/*.htm=authc,concurrentlogin            </value>        </property>    </bean>

此外,spring bean实现了Filter接口,但默认情况下,是由spring容器来管理其生命周期的(不是由tomcat这种服务器容器来管理)。如果设置”targetFilterLifecycle”为True,则spring来管理Filter.init()和Filter.destroy();若为false,则这两个方法失效。

sessionFilter

用于检查用户是否登录了系统,如果未登录,则重定向到指的登录页面。
http://blog.csdn.net/buster2014/article/details/42082141
这里看了这篇文章,觉得我们的这个过滤器没有起作用。

AntiXssFilter

这是我们项目自己定义的校验html、sql特殊字符的过滤器。
核心代码:

    /**     * 判断是否包含html特殊字符 getIncludeHtmlSpecialCharsFlag     */    public static boolean getIncludeHtmlSpecialCharsFlag(String s) throws UnsupportedEncodingException {        boolean res = false;        s = replaceSpecialChars(s);        if ( // XSS黑名单        s.indexOf("javascript:") != -1 || s.indexOf("document.cookie") != -1 || s.indexOf("<script") != -1                || s.indexOf("<iframe") != -1 || s.indexOf("\"><script") != -1 || s.indexOf("<style") != -1                || s.indexOf("<img") != -1 || s.indexOf("onclick=") != -1 || s.indexOf("\"><style") != -1                || s.indexOf(")//") != -1 || s.indexOf("\">") != -1 || s.indexOf("<body") != -1                || s.indexOf("/xss/") != -1 || s.indexOf("onfocus") != -1                || s.indexOf("alert") != -1 // || s.indexOf(";") != -1                || s.indexOf("fromcharcode") != -1 || s.indexOf("eval") != -1 || s.indexOf("<a") != -1                || s.indexOf("cookie") != -1 || s.indexOf("document.write") != -1 || s.indexOf(">@import ") != -1) {            res = true;        }        return res;    }    /**     * 判断是否包含sql特殊字符 getIncludeSqlSpecialCharsFlag     */    public static boolean getIncludeSqlSpecialCharsFlag(String str) {        // 过滤掉的sql关键字,可以手动添加        String badStr = "'|and |exec |execute |insert |select |delete |update |count |trim|"                + "char|declare|sitename|net user|xp_cmdshell|like |create |drop |"                + "table |from |grant |use |group_concat|column_name|"                + "information_schema.columns|table_schema|union |where |order |by |"                + "chr|mid|master|truncate |or ";        String[] badStrs = badStr.split("\\|");        for (int i = 0; i < badStrs.length; i++) {            if (str.indexOf(badStrs[i]) >= 0) {                return true;            }        }        return false;    }

load-on-startup

1)load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)。
2)它的值必须是一个整数,表示servlet应该被载入的顺序
3)当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
4)当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。
5)正数的值越小,该servlet的优先级越高,应用启动时就越先加载。
6)当值相同时,容器就会自己选择顺序来加载。
所以,<load-on-startup>x</load-on-startup>,中x的取值1,2,3,4,5代表的是优先级,而非启动延迟时间。

0 0