Web filter中如何引用Spring的bean

来源:互联网 发布:microsoft软件有哪些 编辑:程序博客网 时间:2024/06/01 08:30

今天写了写了阵微信公众号玩,Spring+Struts搭的,有个需求是签名验证,需要在本地缓存一个用户ticket,而获取ticket的逻辑在某个spring service中实现的。

对所有的jsp页面,想要注入对应的信息,而且不配置struts的话,想了想,最好用filter。实现了filter之后,准备注入service,这个时候启动webproject发现,service为null.怎么回事?为什么spring环境中明明通过@Component注入了对应的FIlter,并且通过@Autowired注入了对应的Service,为何Web请求的时候获取不到对应的Service?

应该有这么几个问题需要我搞清楚:1.web 加载的时候有filter,listener,servlet等元素,他们是如何加载的,顺序如何,是不是filter的环境spring 管不到。2.我的配置是如何启动?3.应该如何解决这个问题,即如何在filter中使用service?

一、Filter,Listener,Servlet对比

首先这三个东东来自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"></web-app>

第一行给出了XML头,用来定义字符编码和xml版本,一般的xml文件都有这个。紧接着是web-app元素,这个元素的xmlns,即xml namespace是定义该元素所支持的子元素的。可以看出,在web.xml中是namespace是来自于sun的javaee页面。


可以看出上面配置的,是06年发布的2.5标准。而最新的已经是13年4月发布的3.1。我看了下web-app_3.1.xsd,其中引入了

</pre><pre name="code" class="html"><xsd:include schemaLocation="web-common_3_1.xsd"/>

这个文件中定义这些元素:

 <xsd:element name="filter"                   type="javaee:filterType"/>      <xsd:element name="filter-mapping"                   type="javaee:filter-mappingType"/>      <xsd:element name="listener"                   type="javaee:listenerType"/>      <xsd:element name="servlet"                   type="javaee:servletType"/>      <xsd:element name="servlet-mapping"                   type="javaee:servlet-mappingType"/>
可以看到这几个元素都定义了name和type,这个type又是在哪儿定义的呢?原来web-common_3_1.xsd又引入了javaee.xsd和jsp_2_3.xsd。在javaee.xsd中,定义了这些type。

1.filterType和filterMappingTYpe的定义(在web-common_3.1.xsd中):

  <xsd:complexType name="filterType">    <xsd:annotation>      <xsd:documentation><span style="font-size:14px;"><span style="color:#3366ff;">        <strong>The filterType is used to declare a filter in the web        application. The filter is mapped to either a servlet or a        URL pattern in the filter-mapping element, using the        filter-name value to reference.</strong></span><span style="color:#ff0000;"> </span></span>Filters can access the        initialization parameters declared in the deployment        descriptor at runtime via the FilterConfig interface.                Used in: web-app              </xsd:documentation>    </xsd:annotation>    <xsd:sequence>      <xsd:group ref="javaee:descriptionGroup"/>      <xsd:element name="filter-name"                   type="javaee:filter-nameType"/>      <xsd:element name="filter-class"                   type="javaee:fully-qualified-classType"                   minOccurs="0"                   maxOccurs="1">        <xsd:annotation>          <xsd:documentation>            The fully qualified classname of the filter.                      </xsd:documentation>        </xsd:annotation>      </xsd:element>      <xsd:element name="async-supported"                   type="javaee:true-falseType"                   minOccurs="0"/>      <xsd:element name="init-param"                   type="javaee:param-valueType"                   minOccurs="0"                   maxOccurs="unbounded">        <xsd:annotation>          <xsd:documentation>            The init-param element contains a name/value pair as            an initialization param of a servlet filter                      </xsd:documentation>        </xsd:annotation>      </xsd:element>    </xsd:sequence>    <xsd:attribute name="id"                   type="xsd:ID"/>  </xsd:complexType>
<xsd:complexType name="filter-mappingType">    <xsd:annotation>      <xsd:documentation>        Declaration of the filter mappings in this web        application is done by using filter-mappingType.         The container uses the filter-mapping      <span style="background-color: rgb(255, 255, 255);"><span style="color:#000099;">  <strong>declarations to decide which filters to apply to a request,        and in what order.</strong> </span></span>The container matches the request URI to        a Servlet in the normal way. To determine which filters to        apply it matches filter-mapping declarations either on        servlet-name, or on url-pattern for each filter-mapping        element, depending on which style is used. The order in        which filters are invoked is the order in which        filter-mapping declarations that match a request URI for a        servlet appear in the list of filter-mapping elements.The        filter-name value must be the value of the filter-name        sub-elements of one of the filter declarations in the        deployment descriptor.              </xsd:documentation>    </xsd:annotation>    <xsd:sequence>      <xsd:element name="filter-name"                   type="javaee:filter-nameType"/>      <xsd:choice minOccurs="1"                  maxOccurs="unbounded">        <xsd:element name="url-pattern"                     type="javaee:url-patternType"/>        <xsd:element name="servlet-name"                     type="javaee:servlet-nameType"/>      </xsd:choice>      <xsd:element name="dispatcher"                   type="javaee:dispatcherType"                   minOccurs="0"                   maxOccurs="5"/>    </xsd:sequence>    <xsd:attribute name="id"                   type="xsd:ID"/>  </xsd:complexType>


2.listener定义在javaee_7.xsd.
  <xsd:complexType name="listenerType">    <xsd:annotation>      <xsd:documentation>        <span style="background-color: rgb(255, 255, 255);"><span style="color:#000099;"><strong>The listenerType indicates the deployment properties for a web        application listener bean.</strong></span></span>              </xsd:documentation>    </xsd:annotation>    <xsd:sequence>      <xsd:group ref="javaee:descriptionGroup"/>      <xsd:element name="listener-class"                   type="javaee:fully-qualified-classType">        <xsd:annotation>          <xsd:documentation>            The listener-class element declares a class in the            application must be registered as a web            application listener bean. The value is the fully            qualified classname of the listener class.                      </xsd:documentation>        </xsd:annotation>      </xsd:element>    </xsd:sequence>    <xsd:attribute name="id"                   type="xsd:ID"/>  </xsd:complexType>

3.Servlet定义在web-commmon_3.1.xsd中,

 <xsd:complexType name="servletType">    <xsd:annotation>      <xsd:documentation>        <span style="background-color: rgb(255, 255, 255);"><span style="color:#000099;"><strong>The servletType is used to declare a servlet.</strong></span></span>        It contains the declarative data of a        servlet. If a jsp-file is specified and the load-on-startup        element is present, then the JSP should be precompiled and        loaded.                Used in: web-app              </xsd:documentation>    </xsd:annotation>    <xsd:sequence>      <xsd:group ref="javaee:descriptionGroup"/>      <xsd:element name="servlet-name"                   type="javaee:servlet-nameType"/>      <xsd:choice minOccurs="0"                  maxOccurs="1">        <xsd:element name="servlet-class"                     type="javaee:fully-qualified-classType">          <xsd:annotation>            <xsd:documentation>              The servlet-class element contains the fully              qualified class name of the servlet.                          </xsd:documentation>          </xsd:annotation>        </xsd:element>        <xsd:element name="jsp-file"                     type="javaee:jsp-fileType"/>      </xsd:choice>      <xsd:element name="init-param"                   type="javaee:param-valueType"                   minOccurs="0"                   maxOccurs="unbounded"/>      <xsd:element name="load-on-startup"                   type="javaee:load-on-startupType"                   minOccurs="0">        <xsd:annotation>          <xsd:documentation>            The load-on-startup element indicates that this            servlet should be loaded (instantiated and have            its init() called) on the startup of the web            application. The optional contents of these            element must be an integer indicating the order in            which the servlet should be loaded. If the value            is a negative integer, or the element is not            present, the container is free to load the servlet            whenever it chooses. If the value is a positive            integer or 0, the container must load and            initialize the servlet as the application is            deployed. The container must guarantee that            servlets marked with lower integers are loaded            before servlets marked with higher integers. The            container may choose the order of loading of            servlets with the same load-on-start-up value.                      </xsd:documentation>        </xsd:annotation>      </xsd:element>      <xsd:element name="enabled"                   type="javaee:true-falseType"                   minOccurs="0"/>      <xsd:element name="async-supported"                   type="javaee:true-falseType"                   minOccurs="0"/>      <xsd:element name="run-as"                   type="javaee:run-asType"                   minOccurs="0"/>      <xsd:element name="security-role-ref"                   type="javaee:security-role-refType"                   minOccurs="0"                   maxOccurs="unbounded"/>      <xsd:element name="multipart-config"                   type="javaee:multipart-configType"                   minOccurs="0"                   maxOccurs="1"/>    </xsd:sequence>    <xsd:attribute name="id"                   type="xsd:ID"/>  </xsd:complexType><!-- **************************************************** -->  <xsd:complexType name="servlet-mappingType">    <xsd:annotation>      <xsd:documentation>        The servlet-mappingType defines a mapping between a        servlet and a url pattern.                 Used in: web-app              </xsd:documentation>    </xsd:annotation>    <xsd:sequence>      <xsd:element name="servlet-name"                   type="javaee:servlet-nameType"/>      <xsd:element name="url-pattern"                   type="javaee:url-patternType"                   minOccurs="1"                   maxOccurs="unbounded"/>    </xsd:sequence>    <xsd:attribute name="id"                   type="xsd:ID"/>  </xsd:complexType><!-- **************************************************** -->  <xsd:complexType name="servlet-nameType">    <xsd:annotation>      <xsd:documentation>        The servlet-name element contains the canonical name of the        servlet. Each servlet name is unique within the web        application.              </xsd:documentation>    </xsd:annotation>    <xsd:simpleContent>      <xsd:extension base="javaee:nonEmptyStringType"/>    </xsd:simpleContent>  </xsd:complexType>

看完这3个元素的定义,总结一句话,他们是干啥的,servlet呢是定义servlet的,listener呢是定义listener的,filter是定义filter的。扯了半天蛋,其实要了解web.xml中的这几个元素,还是得看看其它资料,先看看百度百科吧,Servlet(http://baike.baidu.com/link?url=PK8201TxZwwQZKAwLiu9Mob6rPo2AnApub5uT8PCPoigifBFGdGyFMQeyuBL3e6KWdTpQkxpxZwPJGvwgHLF8K),Filter(http://baike.baidu.com/link?url=Zb9NDPAOIgkyy2OvquA7pLapG58QlM0O1fTBlIIVdFk8NoJXhuC2fKJnOnksnNaf62T7936X8isYIvDHWp59iq).然后就知道了,servlet可以看成一个简单的服务提供者,filter则是一个在请求到达服务提供者之前对request进行预处理的过滤器,而listener则是在web应用启动的时候进行初始化,然后拦截相关的请求,只有当应用重新部署或者停止的时候才干掉。

这几个元素都是通过实现几个接口才能拓展,这几个接口分别是:

1.FIlter.java

/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License").  You * may not use this file except in compliance with the License.  You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt.  See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license."  If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above.  However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. * * * This file incorporates work covered by the following copyright and * permission notice: * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package javax.servlet;import java.io.IOException;/** * A filter is an object that performs filtering tasks on either the * request to a resource (a servlet or static content), or on the response * from a resource, or both. *  * <p>Filters perform filtering in the <code>doFilter</code> method. * Every Filter has access to a FilterConfig object from which it can obtain * its initialization parameters, and a reference to the ServletContext which * it can use, for example, to load resources needed for filtering tasks. * * <p>Filters are configured in the deployment descriptor of a web * application. * * <p>Examples that have been identified for this design are: * <ol> * <li>Authentication Filters * <li>Logging and Auditing Filters * <li>Image conversion Filters * <li>Data compression Filters * <li>Encryption Filters * <li>Tokenizing Filters * <li>Filters that trigger resource access events * <li>XSL/T filters * <li>Mime-type chain Filter * </ol> * * @since Servlet 2.3 */public interface Filter {    /**      * Called by the web container to indicate to a filter that it is     * being placed into service.     *     * <p>The servlet container calls the init     * method exactly once after instantiating the filter. The init     * method must complete successfully before the filter is asked to do any     * filtering work.     *      * <p>The web container cannot place the filter into service if the init     * method either     * <ol>     * <li>Throws a ServletException     * <li>Does not return within a time period defined by the web container     * </ol>     */    public void init(FilterConfig filterConfig) throws ServletException;    /**     * The <code>doFilter</code> method of the Filter is called by the     * container each time a request/response pair is passed through the     * chain due to a client request for a resource at the end of the chain.     * The FilterChain passed in to this method allows the Filter to pass     * on the request and response to the next entity in the chain.     *     * <p>A typical implementation of this method would follow the following     * pattern:     * <ol>     * <li>Examine the request     * <li>Optionally wrap the request object with a custom implementation to     * filter content or headers for input filtering     * <li>Optionally wrap the response object with a custom implementation to     * filter content or headers for output filtering     * <li>     * <ul>     * <li><strong>Either</strong> invoke the next entity in the chain     * using the FilterChain object     * (<code>chain.doFilter()</code>),     * <li><strong>or</strong> not pass on the request/response pair to     * the next entity in the filter chain to     * block the request processing     * </ul>     * <li>Directly set headers on the response after invocation of the     * next entity in the filter chain.     * </ol>     */    public void doFilter(ServletRequest request, ServletResponse response,                         FilterChain chain)            throws IOException, ServletException;    /**     * Called by the web container to indicate to a filter that it is being     * taken out of service.     *     * <p>This method is only called once all threads within the filter's     * doFilter method have exited or after a timeout period has passed.     * After the web container calls this method, it will not call the     * doFilter method again on this instance of the filter.     *     * <p>This method gives the filter an opportunity to clean up any     * resources that are being held (for example, memory, file handles,     * threads) and make sure that any persistent state is synchronized     * with the filter's current state in memory.     */    public void destroy();}

Servlet.java

/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License").  You * may not use this file except in compliance with the License.  You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt.  See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license."  If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above.  However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. * * * This file incorporates work covered by the following copyright and * permission notice: * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package javax.servlet;import java.io.IOException;/** * Defines methods that all servlets must implement. * * <p>A servlet is a small Java program that runs within a Web server. * Servlets receive and respond to requests from Web clients, * usually across HTTP, the HyperText Transfer Protocol.  * * <p>To implement this interface, you can write a generic servlet * that extends * <code>javax.servlet.GenericServlet</code> or an HTTP servlet that * extends <code>javax.servlet.http.HttpServlet</code>. * * <p>This interface defines methods to initialize a servlet, * to service requests, and to remove a servlet from the server. * These are known as life-cycle methods and are called in the * following sequence: * <ol> * <li>The servlet is constructed, then initialized with the <code>init</code> method. * <li>Any calls from clients to the <code>service</code> method are handled. * <li>The servlet is taken out of service, then destroyed with the  * <code>destroy</code> method, then garbage collected and finalized. * </ol> * * <p>In addition to the life-cycle methods, this interface * provides the <code>getServletConfig</code> method, which the servlet  * can use to get any startup information, and the <code>getServletInfo</code> * method, which allows the servlet to return basic information about itself, * such as author, version, and copyright. * * @author Various * * @see GenericServlet * @see javax.servlet.http.HttpServlet * */public interface Servlet {    /**     * Called by the servlet container to indicate to a servlet that the      * servlet is being placed into service.     *     * <p>The servlet container calls the <code>init</code>     * method exactly once after instantiating the servlet.     * The <code>init</code> method must complete successfully     * before the servlet can receive any requests.     *     * <p>The servlet container cannot place the servlet into service     * if the <code>init</code> method     * <ol>     * <li>Throws a <code>ServletException</code>     * <li>Does not return within a time period defined by the Web server     * </ol>     *     *     * @param configa <code>ServletConfig</code> object      *containing the servlet's     * configuration and initialization parameters     *     * @exception ServletException if an exception has occurred that     *interferes with the servlet's normal     *operation     *     * @see UnavailableException     * @see #getServletConfig     *     */    public void init(ServletConfig config) throws ServletException;            /**     *     * Returns a {@link ServletConfig} object, which contains     * initialization and startup parameters for this servlet.     * The <code>ServletConfig</code> object returned is the one      * passed to the <code>init</code> method.      *     * <p>Implementations of this interface are responsible for storing the      * <code>ServletConfig</code> object so that this      * method can return it. The {@link GenericServlet}     * class, which implements this interface, already does this.     *     * @returnthe <code>ServletConfig</code> object     *that initializes this servlet     *     * @see #init     *     */    public ServletConfig getServletConfig();            /**     * Called by the servlet container to allow the servlet to respond to      * a request.     *     * <p>This method is only called after the servlet's <code>init()</code>     * method has completed successfully.     *      * <p>  The status code of the response always should be set for a servlet      * that throws or sends an error.     *     *      * <p>Servlets typically run inside multithreaded servlet containers     * that can handle multiple requests concurrently. Developers must      * be aware to synchronize access to any shared resources such as files,     * network connections, and as well as the servlet's class and instance      * variables.      * More information on multithreaded programming in Java is available in      * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">     * the Java tutorial on multi-threaded programming</a>.     *     *     * @param req the <code>ServletRequest</code> object that contains     *the client's request     *     * @param res the <code>ServletResponse</code> object that contains     *the servlet's response     *     * @exception ServletException if an exception occurs that interferes     *with the servlet's normal operation      *     * @exception IOException if an input or output exception occurs     *     */    public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;    /**     * Returns information about the servlet, such     * as author, version, and copyright.     *      * <p>The string that this method returns should     * be plain text and not markup of any kind (such as HTML, XML,     * etc.).     *     * @return a <code>String</code> containing servlet information     *     */    public String getServletInfo();            /**     *     * Called by the servlet container to indicate to a servlet that the     * servlet is being taken out of service.  This method is     * only called once all threads within the servlet's     * <code>service</code> method have exited or after a timeout     * period has passed. After the servlet container calls this      * method, it will not call the <code>service</code> method again     * on this servlet.     *     * <p>This method gives the servlet an opportunity      * to clean up any resources that are being held (for example, memory,     * file handles, threads) and make sure that any persistent state is     * synchronized with the servlet's current state in memory.     *     */    public void destroy();}


ServletContextListener.java

/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License").  You * may not use this file except in compliance with the License.  You can * obtain a copy of the License at * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html * or packager/legal/LICENSE.txt.  See the License for the specific * language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each * file and include the License file at packager/legal/LICENSE.txt. * * GPL Classpath Exception: * Oracle designates this particular file as subject to the "Classpath" * exception as provided by Oracle in the GPL Version 2 section of the License * file that accompanied this code. * * Modifications: * If applicable, add the following below the License Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyright [year] [name of copyright owner]" * * Contributor(s): * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license."  If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above.  However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. * * * This file incorporates work covered by the following copyright and * permission notice: * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package javax.servlet;import java.util.EventListener;/**  * Interface for receiving notification events about ServletContext * lifecycle changes. * * <p>In order to receive these notification events, the implementation * class must be either declared in the deployment descriptor of the web * application, annotated with {@link javax.servlet.annotation.WebListener}, * or registered via one of the addListener methods defined on * {@link ServletContext}. * * <p>Implementations of this interface are invoked at their * {@link #contextInitialized} method in the order in which they have been * declared, and at their {@link #contextDestroyed} method in reverse * order. * * @see ServletContextEvent * * @since Servlet 2.3 */public interface ServletContextListener extends EventListener {    /**     * Receives notification that the web application initialization     * process is starting.     *     * <p>All ServletContextListeners are notified of context     * initialization before any filters or servlets in the web     * application are initialized.     *     * @param sce the ServletContextEvent containing the ServletContext     * that is being initialized     */    public void contextInitialized(ServletContextEvent sce);    /**     * Receives notification that the ServletContext is about to be     * shut down.     *     * <p>All servlets and filters will have been destroyed before any     * ServletContextListeners are notified of context     * destruction.     *     * @param sce the ServletContextEvent containing the ServletContext     * that is being destroyed     */    public void contextDestroyed(ServletContextEvent sce);}
这三个接口都在package javax.servlet下。

好吧,差不多该看看起初提出的问题了,web 加载的时候有filter,listener,servlet等元素,他们是如何加载的,顺序如何,是不是filter的环境spring 管不到?

Listener的加载是在应用一开始启动的时候,多个listener之间是没有顺序的,如果有多个listener需要顺序加载,可以考虑把多个listener合并成一个。(eg:http://www.iteye.com/problems/33443)Filter的加载是按照在web.xml中的先后顺序的,其中的init方法,按照的是filter的顺序,doFilter方法是按照filter-mapping的顺序,如果多个filter被一次请求匹配到,则是按照一个filter栈的逻辑进行调用。Servlet的加载顺序则没有前后之别,是请求匹配到哪个就进行哪个的加载。 它们3个之间的顺序关系是,可以看这个(http://www.oschina.net/code/snippet_52678_44994),启动-->listener-->filter-->servlet--->访问-->filter-->servlet-->关闭-->servlet--->filter-->listener。

那么spring bean是否可以在filter中加载到?

从上面的启动顺序可以看出,filter调用的时候,Spring是通过listener进行加载的,肯定是已经启动了。那么为什么我直接把Filter添加Spring的@Component注解,通过@Autowired却加载不到呢?这是由于,在spring对对应的bean进行扫描的时候,filter还没有执行初始化,filter的加载是在listener之后的,那么想要在filter中加载到spring的环境,那么可以通过init方法进行注入,或者在doFilter的时候进行注入(这样成本较高,每次都得注入)。具体实现在第三部分。


二、我的配置是如何启动的。

代码:

<?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"><!-- 加载SPRING配置文件 --><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/spring.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- STRUTS2配置 --><filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class><init-param>    <param-name>config</param-name>          <param-value>struts-default.xml,struts-plugin.xml,struts2/struts.xml,struts2/struts-redis.xml</param-value>  </init-param></filter><filter-mapping><filter-name>struts2</filter-name><url-pattern>*</url-pattern></filter-mapping><!-- 过滤器可以作用于jsp而拦截器只能拦截action. --><filter>        <filter-name> wechat_web_filter</filter-name>        <filter-class>        com.marsyoung.filter.WeChatJspFilter        </filter-class>    </filter>    <filter-mapping>        <filter-name>wechat_web_filter</filter-name>        <url-pattern>*.jsp</url-pattern>    </filter-mapping><pre name="code" class="plain"><span style="font-family: Arial, Helvetica, sans-serif;"><!-- 超时时间,半小时 --></span>
<session-config> <session-timeout>30</session-timeout> </session-config><welcome-file-list><welcome-file>/jsp/index.jsp</welcome-file></welcome-file-list></web-app>



日志:

九月 01, 2015 2:57:44 下午 org.apache.coyote.AbstractProtocol init信息: Initializing ProtocolHandler ["http-nio-8080"]九月 01, 2015 2:57:44 下午 org.apache.tomcat.util.net.NioSelectorPool getSharedSelector信息: Using a shared selector for servlet write/read九月 01, 2015 2:57:44 下午 org.apache.coyote.AbstractProtocol init信息: Initializing ProtocolHandler ["ajp-nio-8009"]九月 01, 2015 2:57:44 下午 org.apache.tomcat.util.net.NioSelectorPool getSharedSelector信息: Using a shared selector for servlet write/read九月 01, 2015 2:57:44 下午 org.apache.catalina.startup.Catalina load信息: Initialization processed in 998 ms九月 01, 2015 2:57:44 下午 org.apache.catalina.core.StandardService startInternal信息: Starting service Catalina九月 01, 2015 2:57:44 下午 org.apache.catalina.core.StandardEngine startInternal信息: Starting Servlet Engine: Apache Tomcat/8.0.24九月 01, 2015 2:57:45 下午 org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom信息: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [105] milliseconds.九月 01, 2015 2:57:52 下午 org.apache.jasper.servlet.TldScanner scanJars信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.九月 01, 2015 2:57:52 下午 org.apache.catalina.core.ApplicationContext log信息: No Spring WebApplicationInitializer types detected on classpath九月 01, 2015 2:57:52 下午 org.apache.catalina.core.ApplicationContext log信息:<strong> <span style="color:#ff0000;">Initializing Spring root WebApplicationContext</span></strong>2015-09-01 14:57:56.812  INFO Program init successful.九月 01, 2015 2:57:58 下午 org.apache.coyote.AbstractProtocol start信息: Starting ProtocolHandler ["http-nio-8080"]九月 01, 2015 2:57:58 下午 org.apache.coyote.AbstractProtocol start信息: Starting ProtocolHandler ["ajp-nio-8009"]九月 01, 2015 2:57:58 下午 org.apache.catalina.startup.Catalina start信息: Server startup in 13985 ms

额,日志中只打出了spring listener进行加载的这一句,前面是tomcat进行启动。其实启动过程就是,加载那个context-param,然后加载listener,然后listener中加载spring.xm的配置,引入了其中配置的数据源bean,Service Bean,以及Struts Action Bean。之后在加载Filter。


三、如何写在Filter中加载Spring环境。

package com.marsyoung.filter;import java.io.IOException;import java.util.Map;import java.util.Set;import java.util.UUID;import java.util.Map.Entry;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils;import com.marsyoung.constants.WeiXinConstants;import com.marsyoung.service.WeChatService;/** * 微信验证过滤器 *  * @author Mars *  */public class WeChatJspFilter implements Filter {Logger logger = LoggerFactory.getLogger(WeChatJspFilter.class);private static final String EQUAL_SIGN = "=";private static final String PLUS_SIGN = "+";private static final String AND = "&";WeChatService weChatService;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {ServletContext servletContext = filterConfig.getServletContext();WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);weChatService = wac.getBean(WeChatService.class);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;// HttpSession session = request.getSession();String timestamp = (System.currentTimeMillis() + "").substring(0, 10);// 时间戳String nonce = create_nonce_str();String createSignature = null;try {createSignature = weChatService.getJsapiTicket();} catch (Exception e) {logger.info("获取签名失败,{}", e);}request.setAttribute("signature", createSignature);// 这个值得设置应该放到Action中去。request.setAttribute("timestamp", timestamp);request.setAttribute("appId", WeiXinConstants.WeiXin_AppID);request.setAttribute("nonce", nonce);log(request, response);chain.doFilter(request, response);}private void log(HttpServletRequest request, HttpServletResponse response) {String remoteHost = request.getHeader("x-real-ip"); // 获取客户端的主机名if (remoteHost == null) {remoteHost = "“没有获取到客户端IP”";}String requestURL = request.getRequestURL().toString(); // 获取客户端请求的URLMap<String, String[]> paramsMap = request.getParameterMap(); // 获取所有的请求参数/* * 获取所有参数的名值对信息的字符串表示,存储在变量paramsStr中 */StringBuilder paramsStrSb = new StringBuilder();if (paramsMap != null && paramsMap.size() > 0) {Set<Entry<String, String[]>> paramsSet = paramsMap.entrySet();for (Entry<String, String[]> param : paramsSet) {StringBuilder paramStrSb = new StringBuilder();String paramName = param.getKey(); // 参数的名字String[] paramValues = param.getValue(); // 参数的值if (paramValues.length == 1) { // 参数只有一个值,绝大多数情况paramStrSb.append(paramName).append(EQUAL_SIGN).append(paramValues[0]);} else {paramStrSb.append(paramName).append(EQUAL_SIGN);for (String paramValue : paramValues) {paramStrSb.append(paramValue);paramStrSb.append(PLUS_SIGN);}paramStrSb.deleteCharAt(paramStrSb.length() - 1);}paramsStrSb.append(paramStrSb).append(AND);}paramsStrSb.deleteCharAt(paramsStrSb.length() - 1);}String paramsStr = paramsStrSb.toString();logger.info("收到来自" + remoteHost + "的请求,URL:" + requestURL + ",参数:" + paramsStr);}private static String create_nonce_str() {return UUID.randomUUID().toString();}@Overridepublic void destroy() {}}






0 0