복붙노트

[SPRING] ApplicationContextAware 구현 중 - ApplicationContext가 NULL 임

SPRING

ApplicationContextAware 구현 중 - ApplicationContext가 NULL 임

일부 내부 서비스의 프록시 역할을하는 Tomcat 애플리케이션을 프로그래밍하고 있습니다.

스프링 프로젝트를 혼합 된 XML 및 주석 기반 구성에서 Java 및 주석 기반 구성으로 전환했습니다.

구성 스타일을 전환하기 전에 응용 프로그램이 정상적으로 작동했습니다. 이제 두 가지 문제가 있습니다.

스프링 부팅 코드 :

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;
    }

}

디스패처 서블릿 컨텍스트에 대한 코드 :

@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 올바른 (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());
    }
}    

나는 모든 지시 사항 # 2을 따랐다. 하지만 이제는이 예외가 발생합니다.

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를 세 번 사용하면 내 필터가 체인에 어떻게 연결되어 있는지 궁금합니다. 메소드의 매개 변수 이름이 빈 이름과 연관된 필터입니까?

부트 스트랩 코드에서 필터 체인을 만드는 코드는 다음과 같습니다.

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();
    }
}

필터에 대한 의존성 주입은 여전히 ​​존재하지 않습니다. 부트 스트랩 단계에서 필터 체인이 만들어지고 콩이 루트 컨텍스트에서 만들어지기 때문입니까?

이것은 인증 필터의 필수 코드입니다.

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>

해결법

  1. ==============================

    1.응용 프로그램 컨텍스트가 컨트롤러에 올바르게 삽입되었으므로 Spring이 올바르게 초기화되었다고 가정합니다. 그러나 필터는 스프링 빈이 아니라 원시 필터로 선언되므로 스프링 주석은 무시됩니다.

    응용 프로그램 컨텍스트가 컨트롤러에 올바르게 삽입되었으므로 Spring이 올바르게 초기화되었다고 가정합니다. 그러나 필터는 스프링 빈이 아니라 원시 필터로 선언되므로 스프링 주석은 무시됩니다.

    응용 프로그램 컨텍스트에 액세스하는 두 가지 방법이 있습니다.

  2. ==============================

    2.범인은 MyAppSpringBoot의 addFilter (..) 메소드입니다.

    범인은 MyAppSpringBoot의 addFilter (..) 메소드입니다.

    이 LOC FilterRegistration.Dynamic 등록을 자세히 살펴보면 container.addFilter ( "u3rAuthentication", UserDbAuthenticationFilter.class); UserDbAuthenticationFilter가 ServletContext에 필터로 등록 되더라도 Spring Context와 어떤 식으로도 연관되어 있지 않다는 것을 알 수있다. (클래스가 직접 등록 되었기 때문에 ApplicationContext와 emf 각각의 null 참조를 설명 할 Spring 빈이 아니기 때문에) .

    동일한 클래스 인 UserDbAuthenticationFilter는 봄에 스캔되어 나중에 Bean으로 등록되지만 ServletContext와 필터로 연결되지는 않지만 (이 Bean은 필터로 등록되지 않아 호출되지 않으며 디버깅하는 동안 ApplicationContext가 설정되는 것을 볼 수 있습니다)

    따라서 같은 클래스 인 UserDbAuthenticationFilter에는 서블릿 필터와 두 개의 인스턴스가 있고, 다른 하나는 서로 연결 / 연결되지 않은 스프링 빈입니다.

    여기서 필요한 것은 스프링 빈인 서블릿 컨테이너에 등록 된 필터입니다. GenericFilterBean이 당신의 구조에옵니다. 필요에 따라 확장하고 아래의 잡아 당김을 인식하십시오 (API 문서에서 가져옴)

    희망이 도움이됩니다. 어떤 문제에 직면 할 경우를 대비하여 의견을 말하고 추가 도움이 필요합니다.

  3. from https://stackoverflow.com/questions/31983613/implementing-applicationcontextaware-applicationcontext-is-null by cc-by-sa and MIT license