我有以下问题:
我正在使用Spring MVC 3开发基于Web的应用程序。在我的web.xml配置中,我有两个上下文(root-context.xml -Global Context - 由ContextLoadListener和servlet-context.xml加载 - 用于DispatcherServlet的)。
但是在我的配置中,我需要一个使用DelegatingFilterProxy实现的过滤器,并配置如下:
<filter>
<filter-name>cheapigFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
此过滤器指向一个名为SegurancaFilter的类,该类从OncePerRequestFilter扩展而来。但是,为了使这个过滤器执行它需要访问servlet-context.xml中的bean @Autowired,并且过滤器本身必须是一个Spring托管bean,所以我必须使用@Component标记它(这将无法工作) ,因为我既没有在root-context中设置也没有将过滤器设置为XML bean。)
如果我放置
<mvc:annotation-driven /> <context:component-scan base-package="br.com.cheapig" />
在我的root上下文中,我的所有bean都会连线两次,导致应用程序调用beans方法两次。那是因为我在root-context.xml和servlet-context.xml中有相同的配置。但是如果我删除了servlet-context.xml的这个配置并将其保存在root-context.xml中,则会出现以下错误:
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
为了提供更多信息,我的过滤器实现如下:
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;
}
}
我的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>
我的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>
重点是:我如何配置我的应用程序以便@Autowired在我的过滤器中工作而不会多次加载我的bean?
答案 0 :(得分:2)
您可以选择性地进行组件扫描。在根上下文中:
<context:component-scan base-package="...">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
在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>
答案 1 :(得分:0)
过滤器被设计为被调用两次。查看the diagram on this page:
FilterX ---&gt; FilterY ---&gt; Servlet ---&gt; FilterY ---&gt; FilterX