I'm programming a Tomcat application which serves as a proxy for some internal services.
I've switched my Spring project from a mixed XML and annotation-based configuration to Java and annotation based configuration.
Before switching the configuration style, the app worked fine. Now I have two issues.
when executing init-methods in two of my filters,
ApplicationContextis null. When I debug my App, I can see that the MethodsetApplicationContextis executed.the
EntityManagerFactoryis not injected in the authentication filter (emfis null)
Code for booting 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/*");
}
}
Code for root context:
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;
}
}
Code for dispatcher servlet context:
@Configuration
@ComponentScan(
basePackages = "de.lgn.doorman",
includeFilters = @ComponentScan.Filter(Controller.class)
)
public class MyAppDispatcherServletContext
{
// all beans are defined in root context
// correct ???
}
Code for root authentication filter:
@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);
}
*/
}
In my controller, the ApplicationContext is correct (not null).
@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());
}
}
Update to the answer of Serge Ballesta
I followed all your instructions #2. But now I get this exception:
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)
I wonder how my own filters are connected to the chain when I use three times DelegatingFilterProxy. Is the paramter name in the method addFilter associated with the bean name?
Update 2 to the answer of Serge Ballesta
This is the code for creating the filter chain in the bootstrap code:
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/*");
}
These are my filter bean definitions in the root context:
@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();
}
}
There is still no dependency injection to the filters. Is it because the filter chain is created during the bootstrap phase, and the beans are created in the root context?
Update 3 to the answer of Serge Ballesta
This is the essential code in the authentication filter :
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"));
}
}
No exception is thrown. This the logging:
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>
rootContext.register(DmRootContext.class);in yourWebApplicationInitializer, and your root context configuration class ispublic class MyAppRootContext?