Spring Context를 이용하여 빈(Bean) & 서블릿(Servlet) 객체 가져오기

종원유·2022년 1월 13일
0

Spring

목록 보기
7/10

스프링 프레임워크를 사용하여 개발할 때 서비스나 DAO 객체에 bean을 얻기 위해서는 @Autowired 또는 @Resourse 어노테이션을 사용하여, 빈을 주입받아 사용한다.

HttpServletRequest, HttpServletResponse, HttpSession과 같은 서블릿 객체는 Controller 메서드의 인자로 받아서 사용하고 필요 시 서비스 객체로 보내줘야 한다.

하지만, 이외의 유틸리티성 객체에서 데이터베이스에 접근하고자 할 때, Controller나 서비스 객체가 아닌 리스너, AOP 등에서 서비스 객체 또는 DAO 객체등의 스프링 빈을 사용해야 할 때도 있다.
이럴 경우 필요한 빈 객체 또는 서블릿 객체에 직접 접근하는 방법이 있고, 이에 대해 정리해보고자 한다.

스프링 빈(Bean) 객체 가져오기

ContextLoader -> WebApplicationContext

//빈을 직접 얻기 위한 방법
WebApplicationContext context = 
	ContextLoader.getCurrentWebApplicationContext();
return context.getBean(beanName);

ContextLoader의 getCurrentWebApplicationContext() 메서드를 통해서 WebApplicationContext 객체를 얻는다.

ContextLoader ?

먼저 Context란 Spring Bean의 확장 버전으로 단순히 Bean을 다루는 것 외에 더 추가적인 기능을 제공한다.
ContextLoader는 ContextLoaderListener를 통해 등록된 Context를 접근할 수 있도록 하는 객체이다.

  • Context에 대한 깊은 설명은 내용을 추 후에 따로 정리해서 포스팅하려 한다.

WebApplicationContext ?

WebApplicationContext는 서비스 계층, DAO 등을 포함한 웹 환경에 독립적인 빈들을 담아두는 Context

WebApplicationContext의 .getBean() 메서드로 bean 객체의 beanName을 인자로 전달하여 Spring Bean으로 등록된 Bean 객체를 가져올 수 있다.

코드

//beanName을 통해서 Bean을 얻을 수 있다.
public static Object getBean(String beanName){
	return ContextLoader.getCurrentWebApplicationContext().getBean(beanName);
}

서블릿(Servlet) 객체 가져오기

RequestContextHolder -> ServletRequestAttributes

ServletRequestAttributes attr = 
	(ServletRequestAttributes) RequestContextHolder
    	.currentRequestAttributes();

RequestContextHolder 객체로부터 ServletRequestAttributes 객체를 얻는다.

RequestContextHolder ?
RequestContextHolder는 Spring 2.X이상 버전부터 제공하는 기능으로 HttpServletRequest에 접근할 수 있도록 도와준다.


원리

  • Spring은 static(정적)한 map을 하나 만들어놓고 servlet이 호출되면 key를 thread로 만들어서 제공받은 HttpServletRequest를 보관한다.
  • 그리고 Servlet이 종료될 때, 해당 thread를 key로 갖는 HttpServletRequest를 map에서 제거한다.


    이러한 이유로 호출된 Servlet과 동일한 thread 내에서는 어느 곳에서든 HttpServletRequest를 꺼내 쓸 수 있게된다(동일한 thread).
    (실제로는 HttpServletRequest 객체 자체가 아닌 가공된 데이터지만, HttpServletRequest를 가져다 쓰듯이 사용할 수 있다.)

ServletRequestAttributes ?
RequestContextHolder 객체는 위 설명처럼 HttpServletRequest를 ThreadLocalMap을 이용해서 HttpServletRequest 인스턴스의 정보들을 바인딩 해두는데, currentRequestAttributes(), getRequestAttributes() 메서드는 바인딩된 RequestAttributes 데이터를 ServletRequestAttributes 객체로 바인딩해서 리턴한다.

currentRequestAttributes()와 getRequestAttributes()의 차이
두 메서드는 현재 thread에 바인딩된 RequestAttributes를 가져오는 것은 동일하다.

둘의 차이는

  • currentRequestAttributes()는 RequestAttributes가 없으면 예외(IllegalStateException)를 발생하고,
  • getRequestAttributes() 메서드는 null을 반환한다.

값이 없을 경우 null로 반환할지, 예외를 발생시킬지에 따라서 사용 메소드에 차이가 있다.

코드

Servlet의 경우 Request, Session, Response 등 여러 객체를 반환할 수 있다.

HttpSevletRequest 객체 접근

//HttpServletRequest 객체 접근
public static HttpServletRequest getRequest(){
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    return attr.getRequest();
}

//getAttribute(Request에서 데이터 가져오기)
public static HttpServletRequest getRequest(){
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    return attr.getRequest();
}
    
//setAttribute(Request에 데이터 저장)
public static void setRequestAttributes(String key, Object obj){
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    attr.setAttribute(key, obj, attr.SCOPE_REQUEST);
}

Session 객체 접근

//HttpSession 객체 접근
public static HttpSession getSession(){
    return getRequest().getSession();
}

//getSessionAttribute(Session에서 데이터 가져오기)
public static Object getSessionAttributes(String key){
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    return attr.getAttribute(key, attr.SCOPE_SESSION);
}
//setSessionAttribute(Session에 데이터 저장)
public static void setSessionAttributes(String key, Object obj){
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    attr.setAttribute(key, obj, attr.SCOPE_SESSION);
}

Response 객체 접근

//HttpServletResponse 객체 얻기
public static HttpServletResponse getResponse(){
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    return attr.getResponse();
}

WebContext를 Util 객체로 사용한다면 다음과 같이 사용할 수 있다.

import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class RequestHandler {

    public static ServletRequestAttributes getServletRequestAttributes(){
        return (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    }

    //Request 객체 얻기
    public static HttpServletRequest getRequest(){
        return getServletRequestAttributes().getRequest();
    }

    //Set Request Attribute
    public static void setRequestAttributes(String key, Object obj){
        getServletRequestAttributes().setAttribute(key, obj, ServletRequestAttributes.SCOPE_REQUEST);
    }
    //Get Request Attribute
    public static Object getRequestAttributes(String key){
        return getServletRequestAttributes().getAttribute(key, ServletRequestAttributes.SCOPE_REQUEST);
    }

    //Session 객체 얻기
    public static HttpSession getSession(){
        return getRequest().getSession();
    }
    //Set Session Attributes
    public static void setSessionAttributes(String key, Object obj){
        getServletRequestAttributes().setAttribute(key, obj, ServletRequestAttributes.SCOPE_SESSION);
    }

    //Get Session Attributes
    public static void getSessionAttributes(String key){
        getServletRequestAttributes().getAttribute(key, getServletRequestAttributes().SCOPE_SESSION);
    }

    //HttpServletResponse 객체 얻기
    public static HttpServletResponse getResponse(){
        return getServletRequestAttributes().getResponse();
    }

    //beanName을 통해서 Bean을 얻을 수 있다.
    public static Object getBean(String beanName){
        return ContextLoader.getCurrentWebApplicationContext().getBean(beanName);
    }
}
profile
개발자 호소인

0개의 댓글