리스너(Listner)

 

JSP는 자바 서블릿을 사용해서 만든 웹 컨텐츠 구축 장치다.

생존주기 이벤트 리스너(life-cycle event listner) 는 서블릿 2.3부터 새로 추가된 기능이다.

필터는 쉽게 말해 웹 기반의 리소스(서블릿,JSP페이지,정적 컨텐트등) 위에다가 별도의 기능을 얹을수 있데 하는 장치를 말한다.

필터를 사용하면 요청과 응답을 가로채어 새로운 동작을 수행할수 있는 것이다.

리스너는 컨테이너가 애플리케이션과 HTTP세션에 관련된 어떤 동작을 할떄마다 개발자가 정의한 다른 코드를 실행할수 있도록 만든 장치라 할수 있겠다.

 

 

오늘은 리스너에 대해 알아보자.

리스너는 웹 애플리케이션 개발자로 하여금 컨테이너가 수행한 특정한 동작(event) 을 감시하다가, 해당 이벤트에 대해 개발자가 정의한 적절한 동작을 실행할수 있도록 연결해주는 메커니즘이다.

이런 동작의 알림(notification)을 받아내기 위한 메소드 를 정의하고 있는 java interface 형태로 존재한다.

또한 리스너는 세션동작을 감시하는 리스너와 애플리케이션 수준에서의 생존주기 이벤트를 감시하는 리스너로 나뉜다.

필자는 리스너를 두가지로 분류하고 명칭을 아래와 같이 정의했다.

리스너  -  1. 세션 리스너(session listner)

    2. 애플리케이션 리스너(application listner)

 

 

인터페이스의 종류

javax.servlet.http.HttpSessionBindingListner

javax.servlet.http.HttpSessionActivationListner

javax.servlet.http.HttpSessionListner

javax.servlet.http.HttpSessionAttributeListner

javax.servlet.http.ServletContextListner

javax.servlet.http.ServletContextAttributeListner

 

 

 

 

 

 

 

 

 

 

1-1.세션 리스너(session listner)

javax.servlet.http.HttpSessionBindingListner

valueBound(event) - 객체가 세션에 추가되고 있음을 알린다.

valueUnBound(event) - 객체가 세션에서 제거되고 있음을 알린다.

 

사용자의 HTTP세션 이벤트에 반응하여 사용자가 세션에 추가되거나, 빠질때 컨테이너가 이 인터페이스를 구현한 객체를 호출하게 되는 방식.

 

 

 

 

javax.servlet.http.HttpSessionActivationListner

sessionDidActivate(event) - 세션이 active 상테가 되었음을 알린다.

sessionWillPassivate(event) -  세션이 passive 상테가 되었음을 알린다.

 

HttpSessionBindingListner 와 비슷하게 동작한다. HttpSessionActivationListner 를 구현한 클래스로 만들어진 객체가 세션에 추가되면, 이 객체는 세션이 active 상태나 passive 상태가 될때마다 event 알림을 받는다. 이때 이 인터페이스를 구현한 객체가 호출된다.

세션을 active 상태나 passive 상태로 만드는 기능은 분산처리를 지원하는 애플리케이션 서버의 고급기능에 분류될수 있다.

이기능을 지원하는 서버는 로드밸런싱을 적절하게 수행하여, 같은 컴퓨터 혹은 여러대의 컴퓨터에 떠있는 각각의 JVM사이에서 세션을 주고받게 할수 있다.

어떤 세션이 다른 JVM으로 옮겨질 목적으로 저장되는 것을 passivate(패시브상태로 만든다) 라고 한다.

그래서 HttpSessionActivationListner인터페이스를 구현한 객체가 세션 속성으로 저장되면, 이 객체는 sessionWillPassivate() 메소드를 통해 컨테이너로부터 호출된다.

세션이 다른 JVM으로 전송된후에는 active상테가 되었다 라고 한다.

이때 HttpSessionActivationListner 인터페이스를 구현한 객체는 sessionDidActivate() 메소드를 통해 호출된다.

이 두가지의 경우, 메소드의 매개변수로 javax.servlet.http.HttpSessionEvent의 인스턴스가 넘겨진다.

이 인스턴스의 getSession() 메소드를 통해 HttpSession 객체에 접근할수 있다.

 

 

 

DEV.WON-Comment)

당연히 두 인터페이스는 다중상속이 된다.

그러므로 HttpSessionBindingListner, HttpSessionActivationListner 모두 구현하면 두가지의 리스너 성격을 띄는 객체가 되는것이다.

그리고 HttpSessionBindingListner, HttpSessionActivationListner 인터페이스 를 구현하는 리스너를 컨테이너에 따로 등록하는 절차는 필요없다. 만들어놓기만 하면 이벤트 처리가 자동으로 된다는 것이다.

 

하지만, 앞으로 보게될 인터페이스들은 특정한 클래스를 통해 구현된다.

또한, 애플리케이션에 등록해야한다. 동록은 애플리케이션 배포 설명자라 불리는 XML형식의 구성파일에 기술한다.

애플리케이션이 로드되고 초기화될 동안에, 애플리케이션은 배포 설명자 파일에서 구성 정보를 메모리로 읽어들이고 , 이때 리스너클래스도 같이 식별되며, 컨테이너는 이클래스의 인스턴스를 생성한후 이벤트를 보내기 시작한다.

또한 하나의 객체에 영향을 주는 이벤트만 받는게 아니라, 특정 종류의 이벤트를 모두 받는다는 점이 차이점이다.

 

 

 

 

javax.servlet.http,HttpSessionListner

sessionCreated(event)  - 세션이 메모리에 올라오고 초기화됨을 알린다.

sessionDestroyed(event)  - 세션이 메모리에서 없어졌음을 알린다.

 

세션의 생성과 소멸을 나타내는 기능을 한다.

 

 

javax.servlet.http,HttpSessionAttributeListner

attributeAdded(event)  - 새로운 세션의 속성에 값이 대입되었다는 것을 알린다.

attributeReplaced(event)  - 이미 있는 세션 속성에 새로운 값이 대입되었음을 알린다.

AttributeRemoved(event)  - 세션 속성이 제거되었음을 알린다.

 

세션속성에 관련된 이벤트 전달 인터페이스라 할수 있겠다.

어떤 세션에 어떤 속성 하나가 추가될 때(예를들어, session.setAttribute() 메소드에 의해, 혹은 <jsp:useBean>태그의 scope속성을 session으로 지정하여 사용할 경우) 컨테이너는 HttpSessionAttributeListner 인터페이스를 구현,등록한 객체의 attributeAdded()를 호출하는 것이다.

이때 매개변수로 javax.servlet.http.HttpSessionBindingEvent 객체가 전달된다.

이 이벤트 클래스는 아까 얘기한 HttpSessionEvent 클래스의 하위 클래스이다. 이 클래스는 getName() 과 getValue() 라는 메소드를 추가로 가지고 있어, 추가되는 속성의 이름과 그 속성의 값을 알아낼수 있다.

 

이미 있는 속성에 새로운 값이 대입되면? attributeReplaced() 메소드가 실행된다.

이 경우에는 이벤트 인스턴스의 getValue() 메소드를 통해 반환된 값은 해당 속성의 이전값임을 주의해야한다.

 

속성이 제거되면? attributeRemoved() 메소드가 실행된다.

이때 이벤트 인스턴스의 getName() 메소드를 호출하면 제거된 속성의 이름이 반환된다.

getValue() 메소드를 호출하면 제거되기 전의 속성에 저장되어있던 마지막 값이 반환된다.

 

결국 HttpSessionAttributeListner와 HttpSessionBindingListner 는 동작 원리가 비슷하다.

차이점은, HttpSessionBindingListner는 세션에 추가되는 객체가 직접 구현한다는 것과 HttpSessionAttributeListner는 구현하는 클래스가 세션에 직접 들어가지 않아도 된다는 점이다.
 

결론적으로 , HttpSessionAttributeListner인터페이스는 invasivity 가 상대적으로 떨어진다고 할수있다.

그 이유는 바로, 세션 동작에 가담하고 있는 객체의 소스 코드를 수정할 필요없이 세션의 동작을 감시 , 감지 할수 있기 때문이다.

 

 

DEV.WON-Comment)

하지만 그렇다고 해서 굳이 HttpSessionBindingListner 인터페이스를 구현한다해서 세션에 들어가는 객체의 클래스 소스를 직접 건드릴 필요는 없다. Invasivity를 떨어뜨릴수 있는 방법은 존재한다.

원래 세션에 가담하는 객체의 클래스를 상속함과 동시에 HttpSessionBindingListner 를 구현하는 서브 클래스 방식으로 처리하면 된다.

또는 delegation 디자인 패턴을 써도 되겠다.

delegation 디자인 패턴을 사용하는 방법을 잠깐 언급하자면, HttpSessionBindingListner를 구현하는 클래스를 만들되, 이 클래스 안에 원래 세션에 가담하는 객체의 인스턴스를 인스턴스 변수로 참조하는 것이다. 결국, HttpSessionBindingListner 의 메소드는 새 클래스에서 직접 구현하고, 원래 세션에 가담하는 객체의 동작은 새로 만든 클래스에서 인스턴스 변수를 통해 메소드를 호출함으로써 해결하는 방식을 말한다.

 

 

어떤 리스너를 사용할것인가 선택하는 이슈는 결국 어떤 애플리케이션을 어떻게 만드느냐에 따라 다르다.

애플리케이션 개발에 폭넓게 사용할수 있는 객체의 경우(예를들면, 굳이 웹기반이 아니더라도 사용될수 있는) 에는 HttpSessionAttributeListner가 적절하다고 말할수 있다.

세션에 관련된 기능은 별도의 클래스에 기술한후, 객체가 웹기반의 애플리케이션에 쓰일때만 사용하는 방식이다.

 

반면에, 서블릿이나 JSP 페이지와 함께 deploy될 목적이라면 객체의 클래스에 HttpSessionBindingListner와 HttpSessionActivationListner도 구현하는 것이 적절하겠다.

 

 

 

 

 

 

 

 

 

1-2.애플리케이션 리스너(application listner)

생존주기 리스너 혹은 애플리케이션 리스너라 불리는 이 리스너는 웹 애플리케이션 자체의 동작과 관련되어있다.

 

애플리케이션 리소스는 javax.servlet.ServletContext 클래스의 인스턴스로 모든 웹애플리케이션에서 공유한다.

, 이 인스턴스를 마치 application 내부 객체처럼 JSP페이지에서 가져다가 쓸수 있다는 뜻이다.

이 메커니즘을 이용해 애플리케이션의 전역 속성과 초기화 매개변수를 설정할수 있는 것이다.

 

따라서 ServletContext 인스턴스는 모든 서블릿과 JSP페이지들이 공유한다는 점 떄문에, 오랜 기간 동안 사용해야 하는 전역 리소스(예를들면, database connection pool 이나 대용량의 자료구조등) 를 저장하는 장소로 적격이다.

하지만 , 애플리케이션이 로드 또는 언로드 될대마다 이 리소스들을 관리하는 별도의 동작을 취해야할 이슈가 있을때가 있다.

, 애플리케이션의 로드 및 언로드 상황을 감지하는 메커니즘이 필요하고 , 이런 이유로 javax.servlet.ServletContextListner 라는 것이 있는 것이다.

 

사실 , servlet 컨테이너는 동시에 몇 개의 웹애플리케이션(context) 를 실행할수 있다.

또한 각각의 웹애플리케이션(context) 들은 서로에 대해 알지 못하며, 의존하지 않는다.

 

 

javax.servlet.ServletContextListner

contextInitialized(event)  - 애플리케이션이 로드되고 초기화되었음을 알린다.

contextDestroyed(event)  - 애플리케이션이 언로드 되었음을 알린다.

 

Servlet컨테이너가 ServletContextListner 인터페이스를 구현한 리스너를 가지고있는 애플리케이션을 로드하면, ServletContextListner 를 구현한 모든 리스너의 contextInitialized() 메소드가 실행된다. 이때 매개변수는 javax.servlet.ServletContextEvent 인스턴스로 이 인스턴스를 통해 이벤트를 전달한다.

, 이 웹애플리케이션(context) 는 이제 요청을 받을 모든 준비가 되었다 는 이벤트를 전달하는 것이다.

또한 리스너에서는 event 인스턴스의 getServletContext() 메소드를 통해 웹 애플리케이션의 ServletContext 객체에 접근할수 있다.

 

 

javax.servlet.ServletContextAttributeListner

attributeAdded(event)  - 새 애플리케이션 속성에 값이 대입되었음을 알린다.

attributeReplaced(event)  - 이미 있는 애플리케이션 속성에 새 값이 대입되었음을 알린다.

AttributeRemove(event)  - 애플리케이션 속성이 제거되었음을 알린다.

 

눈치빠른 독자는 HttpSessionAttributeListner와 비슷함을 알것이다.

애플리케이션의 ServletContext 인스턴스또한 속성을 꺼내고 저장하는 것은 동일하는 것이다.

사용법은 HttpSessionAttributeListner와 동일하다.

이벤트 전달시 매개변수는 ServletContextAttributeEvent 이다.

HttpSessionAttributeListner에서는 HttpSessionBindingEvent 객체가 전달되는 반면, ServletContextAttributeListner에는 ServletContextAttributeEvent 가 전달되는 것이다.

 

ServletContextAttributeEvent 는 ServletContextEvent의 서브 클래스이므로,

getServletContext() 메소드 또한 사용할수 있다.

getName() 메소드는 새로 추가,제거,바뀐 속성의 이름 반환

getValue() 메소드는 새속성에 대입된 값을 반환한다. 하지만 attributeRemove() 메소드가 호출되었을 경우에는 속성이 제거되기 전에 가장 마지막으로 남아 있던 값을 반환하고 attributeReplace() 가 호출된 후에는 바뀌기전의 속성값을 반환한다.

 

DEV.WON-Comment)

애플리케이션 리스너 클래스는 앞에서 얘기한 네가지의 세션 리스너 인터페이스를 동시에 구현할수있다.

+ Recent posts