我已经将我的Spring项目从混合的XML和注释配置切换到基于Java和注释的配置。
在切换配置样式之前,该应用程序运行良好。现在我有两个问题。
1. 在执行两个过滤器中的init-methods时,ApplicationContext为null。当我调试我的应用程序时,我可以看到setApplicationContext方法被执行。
2. EntityManagerFactory没有注入到身份验证过滤器中(emf为null)。
启动Spring的代码如下:
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class MyAppSpringBoot implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
initRootContext(container);
initDispatcherContext(container);
addFilters(container);
}
private void initDispatcherContext(ServletContext container) {
AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext();
servletContext.register(MyAppDispatcherServletContext.class);
ServletRegistration.Dynamic dispatcher
= container.addServlet("myAppDispatcherServlet", new DispatcherServlet(servletContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}
private void initRootContext(ServletContext container) {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(MyAppRootContext.class);
container.addListener(new ContextLoaderListener(rootContext));
}
private void addFilters(ServletContext container) {
FilterRegistration.Dynamic registration
= container.addFilter("u3rAuthentication", UserDbAuthenticationFilter.class);
registration.addMappingForUrlPatterns(null, false, "/entry/*");
registration = container.addFilter("responseXmlFilter", ResponseTextXmlFilter.class);
registration.addMappingForUrlPatterns(null, false, "/entry/*");
}
}
根目录的代码:
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException;
import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.stereotype.Controller;
@Configuration
@ComponentScan(basePackages = "com.application", excludeFilters = @ComponentScan.Filter(Controller.class))
public class MyAppRootContext {
@Bean
public DataSource userDbJpaDataSource() throws DataSourceLookupFailureException {
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource("jdbc/userDbPostgres");
}
@Bean
public EntityManagerFactory entityManagerFactory() {
//return Persistence.createEntityManagerFactory(MyAppConstants.U3R_PERSISTENCE_UNIT);
LocalContainerEntityManagerFactoryBean fb = new LocalContainerEntityManagerFactoryBean();
fb.setDataSource(userDbJpaDataSource());
return fb.getNativeEntityManagerFactory();
}
@Bean
public DiskFileItemFactory diskFileItemFactory() {
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(50_000 * 1024);
factory.setRepository(new File("/WEB-INF/upload"));
return factory;
}
@Bean
public XMLOutputFactory xmlOutputFactory() {
return XMLOutputFactory.newInstance();
}
@Bean
public XMLInputFactory xmlInputFactory() {
return XMLInputFactory.newInstance();
}
@Bean
public XMLEventFactory xmlEventFactory() {
return XMLEventFactory.newInstance();
}
@Bean
public UrlPairing urlPairing() throws IOException {
return new UrlPairing(myAppProperties().getProperty("myApp.UrlPairingFile"));
}
@Bean
public Properties myAppProperties() throws IOException {
Properties p = new Properties();
p.load(MyAppRootContext.class.getResourceAsStream("/myAppConfig.properties"));
return p;
}
@Bean
public MyAppXmlFilterWords xmlFilterWords() throws IOException {
MyAppXmlFilterWords words = MyAppXmlFilterWords.createFilterWords(myAppProperties().getProperty("myApp.xmlFilterWordFile"));
return words;
}
}
调度器servlet上下文的代码:
@Configuration
@ComponentScan(
basePackages = "de.lgn.doorman",
includeFilters = @ComponentScan.Filter(Controller.class)
)
public class MyAppDispatcherServletContext
{
// all beans are defined in root context
// correct ???
}
用于根认证过滤器的代码:
@Component
public class UserDbAuthenticationFilter implements Filter, ApplicationContextAware
{
private static final Logger logger = LogManager.getLogger(UserDbAuthenticationFilter.class.getName());
@Autowired
EntityManagerFactory emf;
private ApplicationContext appContext;
@Override
public void init(FilterConfig filterConfig)
{
logger.debug("Filter {} initialisiert. App-Context: {} {}", this.getClass().getName(),appContext.hashCode(), appContext);
// ******************* NullPointerException here *******************
}
@Override
public void destroy()
{ }
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
appContext = applicationContext;
}
/*
@PostConstruct // ***************** this annotation isn't working **********************
public void filterInit() throws ServletException
{
logger.debug("Filter {} initialisiert. App-Context: {} {}", this.getClass().getName(),appContext.hashCode(), appContext);
}
*/
}
在我的控制器中,
ApplicationContext
是正确的(非空)。@Controller
@RequestMapping(value = "entry/**")
public class MyAppProxyController implements ApplicationContextAware
{
@Autowired
Properties myAppProperties;
private ApplicationContext appContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
appContext = applicationContext;
}
@PostConstruct
public void init() throws ServletException // this is working fine
{
logger.debug("Controller {} initialisiert. App-Context: {} {}", this.getClass().getName(),
appContext.hashCode(), appContext);
logger.debug("Beans im Zugriff von Controller:");
for (String beanName : appContext.getBeanDefinitionNames())
{
logger.debug(" {}", beanName);
}
MyAppProxyController controller = (MyAppProxyController) appContext.getBean("myAppProxyController");
logger.debug("controller-hash im Controller={}", controller.hashCode());
}
}
Serge Ballesta的答案更新
我按照您的第二条指示进行了操作,但现在出现了以下异常:
13-Aug-2015 13:03:27.264 INFO [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.ApplicationContext.log Spring WebApplicationInitializers detected on classpath: [de.lgn.doorman.config.DmSpringBoot@c427b4f]
13-Aug-2015 13:03:27.655 INFO [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.ApplicationContext.log Initializing Spring root WebApplicationContext
13-Aug-2015 13:03:28.308 SEVERE [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.StandardContext.filterStart Exception starting filter responseXmlFilter
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'responseXmlFilter' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1174)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:283)
当我使用三次DelegatingFilterProxy时,我想知道我的自定义过滤器是如何连接到链中的。方法addFilter中的参数名称是否与bean名称相关联?请注意保留HTML标记。
更新Serge Ballesta答案的第二部分
下面是在引导代码中创建过滤器链的代码:
private void addFilters(ServletContext container)
{
FilterRegistration.Dynamic registration =
container.addFilter("userDbAuthenticationFilter", DelegatingFilterProxy.class);
registration.addMappingForUrlPatterns(null, false, "/mapgate/*");
registration = container.addFilter("prepareRequestFilter", DelegatingFilterProxy.class);
registration.addMappingForUrlPatterns(null, false, "/mapgate/*");
registration = container.addFilter("responseTextXmlFilter", DelegatingFilterProxy.class);
registration.addMappingForUrlPatterns(null, false, "/mapgate/*");
}
这些是我在根上下文中的过滤器 bean 定义:
:
@Configuration
@ComponentScan(basePackages = "com.application", excludeFilters = @ComponentScan.Filter(Controller.class))
public class MyAppRootContext
{
@Bean
public UserDbAuthenticationFilter userDbAuthenticationFilter()
{
return new UserDbAuthenticationFilter();
}
@Bean
public PrepareRequestFilter prepareRequestFilter()
{
return new PrepareRequestFilter();
}
@Bean
public ResponseTextXmlFilter responseTextXmlFilter()
{
return new ResponseTextXmlFilter();
}
@Bean
public DataSource userDbJpaDataSource() throws DataSourceLookupFailureException
{
JndiDataSourceLookup lookup = new JndiDataSourceLookup();
return lookup.getDataSource("jdbc/userDbPostgres");
}
@Bean
public EntityManagerFactory entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean fb = new LocalContainerEntityManagerFactoryBean();
fb.setDataSource(userDbJpaDataSource());
return fb.getNativeEntityManagerFactory();
}
}
过滤器仍然没有依赖注入。这是因为过滤器链是在引导阶段创建的,而bean是在根上下文中创建的吗?
Serge Ballesta答案的第3个更新
这是身份验证过滤器中的基本代码:
public class U3RAuthenticationFilter implements Filter, ApplicationContextAware
{
private static final Logger logger = LogManager.getLogger(U3RAuthenticationFilter.class.getName());
@Autowired(required = true)
EntityManagerFactory entityManagerFactory;
private ApplicationContext appContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
appContext = applicationContext;
}
@PostConstruct
public void filterInit() throws ServletException
{
logger.debug("Filter {} initialisiert. App-Context: {} {}", this.getClass().getName(),appContext.hashCode(), appContext);
logger.debug("Beans accessable by {}:", this.getClass().getName());
for (String beanName : appContext.getBeanDefinitionNames())
{
logger.debug(" {}", beanName);
}
logger.debug("EntityManagerFactory: {}", (EntityManagerFactory)appContext.getBean("entityManagerFactory"));
}
}
不会抛出任何异常。以下是日志记录:
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] controller-hash im Controller=1481031354
20150814-090718 INFO [RMI TCP Connection(3)-127.0.0.1] Mapped "{[/mapgate/**],methods=[GET]}" onto protected void com.application.controller.MyAppProxyController.doGet(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
20150814-090718 INFO [RMI TCP Connection(3)-127.0.0.1] Mapped "{[/mapgate/**],methods=[POST]}" onto protected void com.application.controller.MyAppProxyController.doPost(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws javax.servlet.ServletException,java.io.IOException
20150814-090718 INFO [RMI TCP Connection(3)-127.0.0.1] Looking for @ControllerAdvice: WebApplicationContext for namespace 'myAppDispatcherServlet-servlet': startup date [Fri Aug 14 09:07:18 CEST 2015]; parent: Root WebApplicationContext
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] Filter com.application.filter.UserDbAuthenticationFilter initialisiert. App-Context: 641348200 WebApplicationContext for namespace 'myAppDispatcherServlet-servlet': startup date [Fri Aug 14 09:07:18 CEST 2015]; parent: Root WebApplicationContext
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] Beans accessable by com.application.filter.UserDbAuthenticationFilter:
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.internalConfigurationAnnotationProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.internalAutowiredAnnotationProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.internalRequiredAnnotationProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.internalCommonAnnotationProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.internalPersistenceAnnotationProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.event.internalEventListenerProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.event.internalEventListenerFactory
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] myAppDispatcherServletContext
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] myAppRootContext
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] myAppProxyController
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] requestMappingHandlerMapping
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcContentNegotiationManager
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] viewControllerHandlerMapping
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] beanNameHandlerMapping
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] resourceHandlerMapping
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcResourceUrlProvider
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] defaultServletHandlerMapping
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] requestMappingHandlerAdapter
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcConversionService
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcValidator
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcPathMatcher
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcUrlPathHelper
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcUriComponentsContributor
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] httpRequestHandlerAdapter
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] simpleControllerHandlerAdapter
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] handlerExceptionResolver
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] mvcViewResolver
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] userDbAuthenticationFilter
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] prepareRequestFilter
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] responseTextXmlFilter
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] myAppFilterChain
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] userDbJpaDataSource
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] <b>entityManagerFactory</b>
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] diskFileItemFactory
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] xmlOutputFactory
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] xmlInputFactory
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] xmlEventFactory
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] urlPairing
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] myAppProperties
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] xmlFilterWords
20150814-090718 DEBUG [RMI TCP Connection(3)-127.0.0.1] <b>EntityManagerFactory: null</b>
WebApplicationInitializer
中有rootContext.register(DmRootContext.class);
这行代码,而你的根上下文配置类为public class MyAppRootContext
,是否打错了? - Serge Ballesta