자바 프로그래밍

Self-Study: Filter

2012. 8. 17. 11:03

필터(Filter)는 요청(Request)을 서블릿에 앞서 중간에서 가로채서 처리한 후 서블릿으로 넘겨주어 서블릿의 수정없이 필요한 처리를 할 수 있다.

필터 적용 대상들

Request 필터:

  • 보안 체크
  • 요청 헤더와 바디 포맷팅 수정
  • 요청 감시와 로그 처리

Response 필터

  • 응답 스트림 압축
  • 응답 스트림 내용 추가 혹은 수정
  • 새로운 응답 스트림 생성

필터의 설정

체인(Chain)식으로 연결하여 사용이 가능하다. 필터는 하나의 완전한 컴포넌트로써 필터간 전처리가 필요없다. 실행 순서를 지정할 수 있다.

필터는 서블릿과 비슷하다.

컨테이너에 선언하고 컨테이너에 의해 호출된다.

컨테이너가 생명주기를 관리한다.

배포기술자(DD)에 설정한다.

필터의 생명주기

  1. init() 메서드 - 컨테이너가 필터를 인스턴스화할 때 호출하므로 필터의 호출 전에 전처리로 설정할 내용을 기술.   FilterConfig 객체 참조를 나중에 쓰기 위하여 지역변수에 저장하는 코드 작성.
  2. doFilter() 메서드 - 컨테이너가 현재 요청에 필터를 적용할 경우 호출. 다음 3개의 인자 사용.
    • ServletRequest 객체
    • ServletResponse 객체
    • FilterChain 객체 - 필터 간의 처리순서를 지정하는 용도. 배포기술자에 지정한 다음 처리 순서의 필터 참조 저장.
  3. destory() 메서드 - 컨터이너가 필터 인스턴스를 제거할 때 호출. 필터 인스턴스 제거전 후처리할 내용 기술.

public class ExampleFilter implements Filter {
	private FilterConfig fg;
	
	/**
	 * 필수 구현 메서드로 일반적으로
	 * FilterConfig 객체 참조를 로컬에 저장하는 용도
	 */
	public void init(FilterConfig config) throws ServletException {
		this.fc = config;
	}
	
	public void doFilter(
			ServletRequst requset,
			ServletResponse response,
			FilterChain chain // 다음 실행해야할 필터 참조
			) throws ServletException, IOException {
		...
		처리할 내용
		...
		
		/* 다음 실행될 필터나 서블릿을 호출. */
		chain.doFilter(request, response);
	}
	
	public void destory() {
		...
		후처리 내용
		...
	}
}

스택에 쌓이는 필터들

다 수의 필터들을 순서대로 처리하기 위해 컨테이너 내에 스택을 두어 처리한다.

필터의 선언 및 실행 순서

배포기술자(DD)에 선언된 매핑 순서를 따른다.



	필터선언명
	필터클래스 패키지 경로
	
		변수명
		
	




	필터선언명
	URL 패턴이나 필터 실행경로




	필터선언명
	서블릿 선언명

※ 컨테이너가 필터 실행 순서를 정하는 규칙

  1. URL 패턴으로 적용되는 필터가 최우선 순위로 체인에 등록된다. 배포기술자에 정의된 순서를 따른다.
  2. URL 패턴으로 일치하는 필터들이 체인에 순서대로 등록되고 난 다음 <servlet-name>으로 일치하는 필터를 찾아 정의된 순서대로 체인에 등록한다.

요청디스패처로 들어오는 요청에 필터 적용(Servlet 2.4 이상)



	필터선언명 
	URL 패턴이나 필터 실행경로 
	
	REQUEST
			AND/OR
	
	INCLUDE
			AND/OR
	
	FORWARD
			AND/OR
	
	ERROR

MyBatis의 Cache 설정

2012. 8. 2. 16:31

MyBatis의 캐시를 적용해보니 Mapper 단위로 캐시가 사용되어 insert, update, delete 명령을 실행할 때,  flush가 실행되지 않으면 select 명령을 실행할 때 변경전 캐시 내용이 출력되는 문제점이 있었다. 물론 CRUD 단위로 작성된 Mapper 라면 문제가 없겠지만, 조인한 결과를 읽기 위한 Mapper의 경우 select 명령을 실행할 경우에도 flush를 해줘야 하므로 캐시 이용의 이점을 얻을 수 없었다.

캐시의 사용은 CRUD가 한 세트로 작성되는 mapper에서만 사용해야 할 것 같다.

Cache

MyBatis는 쉽게 설정 가능하고 변경 가능한 강력한 트랜젝션 쿼리 캐싱을 포함하고 있다. MyBatis 3 구현체는 더 강력하고 훨씨 쉽게 설정할 수 있도록 많은 변화가 있었다.

기본적으로, 세션 주기 동안 캐시 데이터가 전적으로 사용될 수 있도록 로컬 세션 캐싱만 활성화 되어 있다. Global level caching을 활성화 하기 위해 SQL Mapping 파일에 간단하게 한 줄만 추가하면 된다.

<cache/>

이 한 문장이 다음과 같은 영향을 준다:

  • 맵핑 구문 파일 내의 모든 select 구문의 결과는 캐싱될 것이다.
  • 매핑 구문 파일 내의 모든 insert, update, delete 구문은 캐시에서 비워질(flush) 것이다.
  • 캐시에서 내보내기 위해 LRU(Least Recently Used; 최빈값 이용) 알고리즘을 사용할 것이다.
  • 캐시는 시간 기반 스케줄로 캐시를 비우지 않을 것이다.(캐시를 비우는 간격이 없다.)
  • 캐시는 1,024개의 쿼리 결과를 담은 리스트나 객체들의 참조를 저장할 것이다.
  • 캐시는 읽기/쓰기 캐시처럼 취급할 것이다. 검색된 객체들은 다른 호출자나 스레드에 의해 잠재적인 수정이 없도록 공유되지 않고 안전하게 호출자에 의해 수정된다는 의미이다.
이 모든 속성들은 캐시 엘리먼트의 어트리뷰트들을 통해 수정될 수 있다. 예들 들어:
<cache eviction="FIFO" flushinterval="60000"
        size="500" readonly="true"/>

여기 더 발전된 설정은 60초마다 캐시를 FIFO(선입선출) 방식으로 비우고, 512개까지의 객체나 리스트들의 결과값을 저장하며, 객체는 읽기전용으로 사용된다. 따라서  스레드 안의 두 호출자 사이에서 수정하는 것은 충돌을 일으킬 수 있다.

가능한 캐시 내보내기 정책은 4가지가 가능하다:

  • LRU
  • FIFO
  • SOFT - Soft Reference: 가비지 컬렉터의 상태와 Soft Reference 규칙에 의해 삭제된다.
  • WEAK - Weak Reference: 가비지 컬렉터의 상태와 Weak Reference 규칙에 의해 더 적극적으로 삭제된다.


스트럿츠2에서 리소스 번들을 이용하여 문자열을 출력하기 위해서는 ActionSupport를 상속받아 Action 클래스를 작성하여야 하며 방법은 다음과 같이 다양합니다.

  1. Action 클래스에서 출력
    ...
    public class MyAction extends ActionSupport {
        ...
        public void valid() {
            ...
            addFieldError("username", getText("username.required"));
        }
        ...
    }
    
  2. Property 액션 태그의 사용
    <s:property value="getText('username.required')"/>
    
  3. Text 액션 태그의 사용
    <s:text name="username.required"/>
  4. 액션 태그내의 Key 속성 사용
    <s:textfield key="username.required"/>
    
  5. i18n 액션 태그의 사용
    
        <s:text name="username.required"/>
    

리소스 번들은 다음과 같은 순서로 적용됩니다.

  1. ActionClass.propertie
  2. Interface.properties
  3. BaseClass.properties
  4. ModelDriven's model
  5. package.properti
  6. i18n message key로 검색
  7. Global resource properties


Struts2는 Struts1과 달리 필터 기반으로 동작하기 때문에 Struts1과는 배포기술자(DD) 설정이 다릅니다. 특히 Struts 2.1.3 이후 버전부터는 기본 필터인 디스패처도 달라졌습니다.

...
...
    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    

    


만일 Struts 2.1.3 버전이나 이전 버전으로 개발하기 위해서는 다음과 같이 디스패처를 지정합니다.(2.1.3이후 버전도 이전 버전과의 호환을 위해 지원하고 있습니다.)

...

    Struts2
    org.apache.struts2.dispatcher.FilterDispatcher
...

DB에 저장된 텍스트 중 개행(줄바꿈)문자를 <br> 태그로 바꿔야 할 필요가 있을 때가 종종 있습니다. 입력시에는 텍스트 박스를 이용하지만 브라우저에 텍스트를 뿌릴 때는 개행 위치마다 <br> 태그를 채워넣어야 하죠. 이럴 때, JSTL과 스크립틀릿을 사용하면 간단히 처리할 수 있습니다.

<% pageContext.setAttribute("LF", "\n"); %>

<c:cout> 액션 태그의 escapeXML 속성은 브라우저가 HTML 태그를 해석하여 브라우징할 수 있도록 해주며, fn:replace() 함수를 이용하여 개행문자를 <br> 태그로 바꿔줍니다. 이때 개행문자와 같은 이스케이프 문자는 액션태그가 해석을 할 수 없기 때문에 pageContext를 이용하여 page 생존범위에 LF라는 이름의 변수에 개행문자를 저장하고 fn:replace() 함수에서 사용할 수 있게 해줍니다.

+ Recent posts