@Autowired in DelegatingFilterProxy

I have the following issue:

I'm developing a web-based application using Spring MVC 3. In my web.xml configuration I have two contexts (root-context.xml -Global Context - loaded by the ContextLoadListener and servlet-context.xml - for the DispatcherServlet).

However in my configuration I need a filter which I have implemented using DelegatingFilterProxy, and configured as following:

<filter>
 <filter-name>cheapigFilter</filter-name>
 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>      
</filter>

This filter points to a class called SegurancaFilter that extends from OncePerRequestFilter. But, in order to this filter execute it tasks it needs to access beans @Autowired in the servlet-context.xml and the filter itself has to be a Spring managed bean so I have to tag it with @Component (which won't work, because I haven't neither set in root-context nor set the filter as a XML bean).

If I place

<mvc:annotation-driven /> <context:component-scan base-package="br.com.cheapig" />

In my root-context, all my beans will be wired twice, causing the application to call beans methods twice. That's because I would have the same config in root-context.xml and servlet-context.xml. But if I erase this config of the servlet-context.xml and keep it in root-context.xml the following error shows up:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:924)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:478)
    ... 51 more

To provide further information, my filter is implemented as following:

package br.com.cheapig.seguranca;

import java.io.IOException;
import java.util.Date;
import java.util.Locale;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.LocaleResolver;

import br.com.cheapig.controlador.HistoricoVisitasController;
import br.com.cheapig.dominio.HistoricoVisitas;
import br.com.cheapig.dominio.Usuario;
import br.com.cheapig.exception.ControleAcessoException;
import br.com.cheapig.util.CheapigUtil;
import br.com.cheapig.util.ConstantesAmbiente;
import br.com.cheapig.util.ConstantesGenericas;
import br.com.cheapig.util.ConstantesHistoricoVisitas;
import br.com.cheapig.util.ConstantesSessao;
import br.com.cheapig.util.WorkflowUtil;
import br.com.cheapig.workflow.Request;

/**
 * Classe responsável por fazer a filtragem do controle de acesso aos recursos do site
 * 
 * @author Guilherme Macedo
 * @since Apr 30, 2012
 */
@Component(value = "cheapigFilter")
public class SegurancaFilter extends OncePerRequestFilter {

    @Autowired
    private ConstantesAmbiente constantesAmbiente;

    @Autowired
    private LocaleResolver localeResolver;

    @Autowired
    private ControleAcesso controleAcesso;

    @Autowired
    private HistoricoVisitasController historicoVisitasController;

    /**
     * Cria um novo objeto SegurancaFilter
     */
    public SegurancaFilter() {
        super();
    }

    /**
     * @see org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(javax.servlet.http.HttpServletRequest,
     *      javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
     */
    @SuppressWarnings("unchecked")
    @Override
    protected void doFilterInternal(HttpServletRequest pRequest, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Locale locale = new Locale("pt", "br");
        this.localeResolver.setLocale(pRequest, response, locale);
        LocaleContextHolder.setLocale(locale);
        String path = pRequest.getRequestURI().substring(pRequest.getContextPath().length());
        String uri = pRequest.getRequestURI();
        HttpSession vSession = pRequest.getSession();
        String appId = (String) vSession.getAttribute("facebookAppId");
        if(appId == null || appId.isEmpty()){
            vSession.setAttribute("facebookAppId", this.constantesAmbiente.getFacebookAppId()); 
        }

        if (path.startsWith("/resources") || path.startsWith("/css")) {
            filterChain.doFilter(pRequest, response); // Goes to default servlet.
        } else {
            this.salvaVisita(pRequest);

            if (uri.equals("/") || uri.equals("/cheapig/")) {
                pRequest.getSession().setAttribute("loadCidadeList", true);
            } else {
                pRequest.getSession().setAttribute("loadCidadeList", false);
            }
            String vUrl = uri.substring("/cheapig".length());
            String vLogado = (String) vSession.getAttribute(ConstantesSessao.SESSION_LOGADO);

            if (vLogado == null) {
                vLogado = ConstantesGenericas.SIGLA_NAO;
                vSession.setAttribute(ConstantesSessao.SESSION_LOGADO, ConstantesGenericas.SIGLA_NAO);
            }

            if (vLogado.equals(ConstantesGenericas.SIGLA_SIM) && vUrl.contains("login")) {
                String vRedirectURL = "/cheapig/";  
                response.sendRedirect(vRedirectURL);
            }else{
                Usuario vUsuario = (Usuario) vSession.getAttribute(ConstantesSessao.SESSION_USUARIO);

                try {
                    if (vLogado.equalsIgnoreCase(ConstantesGenericas.SIGLA_NAO)) {
                        this.controleAcesso.verificaPermissoesAnonimas(vUrl);
                    } else {
                        this.controleAcesso.verificaAcesso(vUsuario, vUrl);
                    }                   
                    pRequest.getRequestDispatcher(uri).forward(pRequest, response);
                } catch (ControleAcessoException e) {
                    Request vRequest = new Request();
                    vRequest.setRequestURI(uri);
                    vRequest.setRequestURL(vUrl);
                    vRequest.setRequestParameters(WorkflowUtil.montaParametrosURLParameterMap(pRequest.getParameterMap()));
                    vRequest.setRequestMethod(pRequest.getMethod());
                    vSession.setAttribute("COMING_REQUEST", vRequest);
                    response.sendRedirect("/cheapig/loginTela");
                    return;
                }   
            }


        }
    }

    public ControleAcesso getControleAcesso() {
        return this.controleAcesso;
    }

    public LocaleResolver getLocaleResolver() {
        return this.localeResolver;
    }

    @Override
    protected void initFilterBean() throws ServletException {

    }

    /**
     * Coleta as informações do usuário e persiste no histórico de visitas
     * 
     * @param request
     *            HttpServletRequest
     */
    private void salvaVisita(HttpServletRequest request) {
        String locale = request.getLocale().getLanguage();
        String browser = CheapigUtil.identificaBrowser(request.getHeader(ConstantesHistoricoVisitas.HTTP_BROWSER));
        String metodo = request.getMethod();
        String ip = request.getRemoteAddr();
        String pagAcessada = request.getRequestURI();
        String host = request.getRemoteHost();

        HistoricoVisitas historico = new HistoricoVisitas();
        historico.setLinguagemNavegador(locale);
        historico.setBrowser(browser);
        historico.setDataAcesso(new Date());
        historico.setHost(host);
        historico.setIpVisitante(ip);
        historico.setPagAcessada(pagAcessada);
        historico.setRequestMethod(metodo);

        this.historicoVisitasController.cadastrarHistoricoVisitas(historico);
    }

    public void setControleAcesso(ControleAcesso controleAcesso) {
        this.controleAcesso = controleAcesso;
    }

    public void setLocaleResolver(LocaleResolver localeResolver) {
        this.localeResolver = localeResolver;
    }
}

My root-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
        http://www.springframework.org/schema/aop       
        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        ">

    <mvc:annotation-driven />
    <context:component-scan base-package="br.com.cheapig" />

    <!-- <import resource="cheapig/servlet-context.xml" /> -->

    <!-- Root Context: defines shared resources visible to all other web components -->
    <!-- Configurações de Internacionalização -->
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
        <property name="defaultEncoding" value="latin1" />
    </bean>

    <bean id="localeChangeInterceptor"
        class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
        <property name="paramName" value="lang" />
    </bean>

    <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
        <property name="defaultLocale" value="pt" />
    </bean>

    <bean id="handlerMapping"
        class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="interceptors">
            <ref bean="localeChangeInterceptor" />
        </property>
    </bean>

    <!-- Mapeamento da view "rssViewer" para o bean "rssViewer" -->
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
    <bean id="rssViewer" class="br.com.cheapig.servico.CustomRssViewer" />

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- one of the properties available; the maximum file size in bytes -->
        <property name="maxUploadSize" value="3145728" />
        <property name="maxInMemorySize" value="3145728"></property>
    </bean>

    <bean id="velocityEngine"
        class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
        <property name="velocityProperties">
            <value>
                resource.loader=file
                file.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
            </value>
        </property>
    </bean>
    <!-- <bean id="velocityEngine" class="org.springframework.ui.velocity.VelocityEngineFactoryBean"> 
        <property name="velocityProperties"> <value> resource.loader=class class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader 
        </value> </property> <property name="resourceLoaderPath"> <value>/WEB-INF/velocity</value> 
        </property> </bean> -->



    <!-- <bean id="controleAcesso" class="br.com.cheapig.seguranca.ControleAcesso"> 
        <bean id="cheapigFilter" class="br.com.cheapig.seguranca.SegurancaFilter" 
        > <property name="controleAcesso" ref="controleAcesso" /> <property name="localeResolver" 
        ref="localeResolver" /> </bean> -->

</beans>

My servlet-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">

    <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->

    <!-- Enables the Spring MVC @Controller programming model -->
<!--    <annotation-driven /> -->
    <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
    <resources mapping="/resources/**" location="/resources/" />

    <!-- Imports user-defined @Controller beans that process client requests -->
    <beans:import resource="controllers.xml" />
    <beans:import resource="hibernateMySQL5.xml"/>  
    <beans:import resource="integracaoTiles2.xml"/>
    <beans:import resource="servicoEmail.xml"/>

    <!-- <context:component-scan base-package="br.com.cheapig" /> -->
    <task:annotation-driven/>
</beans:beans>

The point is: How can I configure my application in order to the @Autowired works in my filter without loading my beans multiple times?


You can do component-scan selectively. In your root context:

<context:component-scan base-package="...">
    <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>

In your servlet-context.xml

<context:component-scan base-package="..." use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
    <context:include-filter expression=".*Filter" type="regex" />
</context:component-scan>

Filters are designed to be called twice. Check out the diagram on this page:

FilterX ---> FilterY ---> Servlet ---> FilterY ---> FilterX

链接地址: http://www.djcxy.com/p/44070.html

上一篇: 为DelegatingFilterProxy分离Spring上下文

下一篇: @Autowired DelegatingFilterProxy