복붙노트

[SPRING] 서블릿으로의 스프링 주입

SPRING

서블릿으로의 스프링 주입

그래서 나는이 질문을 보았다.

다른 인스턴스에 대한 Spring 종속성 삽입

내 방법이 효과가 있는지 궁금해하고있었습니다.

1) Spring 애플리케이션 컨텍스트에서 beans 선언하기

    <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="initialSize" value="${jdbc.initialSize}" />
        <property name="validationQuery" value="${jdbc.validationQuery}" /> 
        <property name="testOnBorrow" value="${jdbc.testOnBorrow}" />
    </bean>

    <bean id="apiData" class="com.mydomain.api.data.ApiData">
        <property name="dataSource" ref="dataSource" />
        <property name="apiLogger" ref="apiLogger" />
    </bean>

    <bean id="apiLogging" class="com.mydomain.api.data.ApiLogger">
        <property name="dataSource" ref="dataSource" />
    </bean>

2) 다음과 같이 서블릿의 init 메소드를 오버라이드한다.

    @Override
    public void init(ServletConfig config) throws ServletException {
       super.init(config);

       ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

       this.apiData = (ApiData)ac.getBean("apiData");
       this.apiLogger = (ApiLogger)ac.getBean("apiLogger");
    }

이 기능이 작동합니까? 아니면 스프링이 아직 웹 애플리케이션 배치의이 시점에서 빈을 내 서블릿에 전달할 준비가되지 않았습니까? web.xml에 콩을 넣는 것과 같이 좀 더 전통적인 방식으로해야합니까?

해결법

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

    1.당신이하려는 것은 모든 서블릿이 그것 자신의 ApplicationContext 인스턴스를 갖도록 할 것이다. 어쩌면 이것이 당신이 원하는 것일 수도 있지만 의심 스럽습니다. ApplicationContext는 응용 프로그램에 대해 고유해야합니다.

    당신이하려는 것은 모든 서블릿이 그것 자신의 ApplicationContext 인스턴스를 갖도록 할 것이다. 어쩌면 이것이 당신이 원하는 것일 수도 있지만 의심 스럽습니다. ApplicationContext는 응용 프로그램에 대해 고유해야합니다.

    이를 수행하는 적절한 방법은 ApplicationContext를 ServletContextListener에 설정하는 것입니다.

    public class SpringApplicationContextListener implements ServletContextListener {
            @Override
        public void contextInitialized(ServletContextEvent sce) {
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            sce.getServletContext().setAttribute("applicationContext", ac);            
        }
        ... // contextDestroyed
    }
    

    이제 모든 서블릿은 ServletContext 속성을 통해 동일한 ApplicationContext에 액세스 할 수 있습니다.

    @Override
    public void init(ServletConfig config) throws ServletException {
       super.init(config);
    
       ApplicationContext ac = (ApplicationContext) config.getServletContext().getAttribute("applicationContext");
    
       this.apiData = (ApiData)ac.getBean("apiData");
       this.apiLogger = (ApiLogger)ac.getBean("apiLogger");
    }
    
  2. ==============================

    2.Sotirios Delimanolis가 제공하는 솔루션을 활용하려고했지만 투명 자동 와이어 링을 추가했습니다. 아이디어는 일반 서블릿을 autowire 인식 객체로 변환하는 것입니다.

    Sotirios Delimanolis가 제공하는 솔루션을 활용하려고했지만 투명 자동 와이어 링을 추가했습니다. 아이디어는 일반 서블릿을 autowire 인식 객체로 변환하는 것입니다.

    그래서 스프링 컨텍스트를 가져오고 autowiring 가능 팩토리를 가져온 부모 추상 서블릿 클래스를 생성하고 그 팩토리를 사용하여 서블릿 인스턴스 (실제로는 서브 클래 싱)를 autowire합니다. 또한 하위 클래스가 필요할 경우를 대비하여 인스턴스 변수로 팩토리를 저장합니다.

    그래서 부모 추상 서블릿은 다음과 같습니다 :

    public abstract class AbstractServlet extends HttpServlet {
    
        protected AutowireCapableBeanFactory ctx;
    
        @Override
        public void init() throws ServletException {
            super.init();
            ctx = ((ApplicationContext) getServletContext().getAttribute(
                    "applicationContext")).getAutowireCapableBeanFactory();
            //The following line does the magic
            ctx.autowireBean(this);
        }
    }
    

    서블릿 서브 클래스는 다음과 같습니다.

    public class EchoServlet extends AbstractServlet {
    
        @Autowired
        private MyService service;
    
        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
            response.getWriter().println("Hello! "+ service.getMyParam());
        }
    }
    

    EchoServlet이 수행해야 할 유일한 작업은 일반적인 Spring 실습에서 bean을 선언하는 것입니다. 마법은 수퍼 클래스의 init () 메소드에서 수행됩니다.

    나는 그것을 철저히 시험하지 않았다. 그러나 이것은 간단한 bean MyService와 함께 작동하는데, 이것은 Spring 관리 속성 파일에서 autowired 속성을 가져옵니다.

    즐겨!

    노트 :

    다음과 같이 Spring 고유의 컨텍스트 리스너를 사용하여 응용 프로그램 컨텍스트를로드하는 것이 가장 좋습니다.

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    

    그런 다음 다음과 같이 검색하십시오.

    WebApplicationContext context = WebApplicationContextUtils
        .getWebApplicationContext(getServletContext());
    ctx = context.getAutowireCapableBeanFactory();
    ctx.autowireBean(this);
    

    spring-web 라이브러리는 가져올 필요가 있지만 spring-mvc는 가져올 필요가 없습니다.

  3. ==============================

    3.지금까지의 답변은 나에게 부분적으로 만 작용했습니다. 특히 @Configuration 어노테이션이있는 클래스는 무시되었고 xml 구성 파일을 사용하고 싶지 않았습니다. 다음은 스프링 (4.3.1) 주석 기반 설치를 사용하여 주입 작업을 수행하기 위해 수행 한 작업입니다.

    지금까지의 답변은 나에게 부분적으로 만 작용했습니다. 특히 @Configuration 어노테이션이있는 클래스는 무시되었고 xml 구성 파일을 사용하고 싶지 않았습니다. 다음은 스프링 (4.3.1) 주석 기반 설치를 사용하여 주입 작업을 수행하기 위해 수행 한 작업입니다.

    web-app 아래의 web.xml에서 AnnotationConfigWebApplicationContext를 부트 스트랩합니다. 매개 변수로 contextClass와 contextConfigLocation (주석이 달린 구성 클래스)이 필요합니다.

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
    org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.example.config.AppConfig</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    

    그런 다음 서블릿의 init 메소드를 덮어 씁니다. HttpServlet을 확장 한 추상 클래스를 사용하므로 모든 서블릿에서이를 반복 할 필요가 없습니다.

    @Configurable
    public abstract class MySpringEnabledServlet extends HttpServlet
    {
      @Override
      public void init(
          ServletConfig config) throws ServletException
      {
        super.init(config);
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
      }
    [...]
    }
    

    마지막으로 web.xml에 언급 된 AppConfig 클래스의 주요 구성이 있습니다.

    @Configuration
    @ComponentScan(basePackages = "com.example")
    @Import(
    { SomeOtherConfig.class })
    public class AppConfig
    {
    }
    

    종속 클래스에 주석이 추가됩니다.

    @Component
    public class AnnotatedClassToInject
    

    내 서블릿에서 autowiring을 통해 주입되었습니다.

    @Autowired
    private AnnotatedClassToInject myClass;
    
  4. ==============================

    4.Spring은 Servlet 시작과 무관합니다. 봄이 지나면 바로 콩을 배달 할 준비가 될 것입니다. 아래 문장 바로 다음에 콩이 이미 있습니다.

    Spring은 Servlet 시작과 무관합니다. 봄이 지나면 바로 콩을 배달 할 준비가 될 것입니다. 아래 문장 바로 다음에 콩이 이미 있습니다.

    ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    

    또한 @LuiggiMendoza가 지적한 것처럼, 각 ApplicationContext는 자신 만의 Bean을 생성 / 유지할 것이므로 항상 ApplicationContext를 한 번 만들고 다른 서블릿에서 다시 사용할 수 있습니다 (Servlet의 init () 메소드 내에서 생성하는 것과는 대조적 임)

  5. from https://stackoverflow.com/questions/18745770/spring-injection-into-servlet by cc-by-sa and MIT license