퍼사드 패턴을 설명하기 앞서 이전의 다른 패턴을 기억해 보자.

    패턴                                                 용도
----------------------------------------------------------------------
데코레이터        한 인터페이스를 다른 인터페이스로 변환

어댑터              인터페스는 바꾸지 않고 책임(기능)만 추가

퍼사드              인터페이스를 간단하게 바꿈

1. 컨텍스트

Facade 패턴은 복잡한 서브 시스템에 통일된 인터페이스를 제공함으로써 복잡한 API를 단순화 시켜준다. 시스템을 서브 시스템 단위로 나누어 구성하는 것은 시스템의 복잡도를 낮춰주지만, 동시에 서브 시스템 사이에서의 통신 부하와 결합도가 증가하게 된다. 이러한 서브 시스템 사이의 의존도를 낮추고, 서브 시스템의 사용자 입장에서 사용하기 편리한 인터페이스를 제공하고자 하는 것이 facade 객체이다.

 

 

 

 

 

 

Facade 객체는 실생활에서의 고객 서비스 센터와 유사하다. 가령, 어떤 상품을 구매하는 과정에서 문제가 생겼다고 가정할 때, 고객이 문제의 성격에 따라 해당 부서에 직접 연락하는 것이 아니라 고객 서비스 센터를 통하는 것은 Facade 패턴에 대한 좋은 유추 사례가 될 수 있다.

2. 적용 영역

■ 복잡한 서브 시스템에 대해 간단한 인터페이스를 제공하기를 원하는 경우
■ 클라이언트와 인터페이스의 구현 클래스 사이에 의존도가 높은 경우
■ 서브 시스템을 레이어(layer)로 구분하고자 하는 경우

3. 구조




 

 

 

 




4. 적용 결과

■ 서브 시스템의 컴포넌트로부터 클라이언트를 격리하여, 클라이언트가 쉽게 서브 시스템을 이용할 수 있다.
■ 서브 시스템과 클라이언트 사이의 의존성을 낮춘다.
■ Facade 패턴을 사용한다고 해도, 필요한 경우 서브 시스템의 클래스에 직접 접근할 수도 있다. 즉, 일반화 정도(generality)와 개발의 편의성 사이에서의 적당한 합의점을 찾아야 한다.

5. 관련 패턴

■ Abstract Factory는 Facade와 함께 사용되어 서브 시스템에 독립적으로 서브 시스템의 객체를 생성하는 인터페이스를 제공한다. 또한, 특정 플랫폼에 국한된 클래스를 숨기기 위해 Facade 대신 사용할 수도 있다.
■ Mediator는 기존의 클래스의 기능을 추상화한다는 의미에서 Facade와 유사하다. 그러나, Mediator의 목적은 서로 직접적인 연관을 갖는 객체(colleague object) 사이에서의 커뮤니케이션을 추상화하는 것인데 반해, Facade는 서브 시스템의 인터페이스를 추상화하는 것이다.
■ 하나의 Facade 객체만이 요구되는 경우에는 Facade 객체가 Singleton 형태를 취하기도 한다.

'Design Pattern' 카테고리의 다른 글

Strategy Pattern  (0) 2013.08.12
abstract factory pattern  (0) 2013.07.09

java mail API를 이용하여 메일 발송하는 자료를 모으고자 한다.

내용은 추가적으로 계속 업데이트 할 예정임 .. !!!!



Spring 3 환경에서 메일을 발송하는 방법을 조사해봤다. 간단하게 Oracle에서 제공하는JavaMail API를 사용하면 된다. 현재 최신 버전은 1.4.7이며 maven javamail로 구글링하면 mail-1.4.7.jar 파일을 다운로드받을 수 있다.


* 다운로드받은 mail-1.4.7.jar 파일을 프로젝트의 CLASSPATH에 추가한다. 웹 애플리케이션의 경우 /WebContent/WEB-INF/lib 디렉토리에 복사하면 간단하게 끝난다.


* 메일 발송 정보를 저장할 mail.xml 파일을 작성한다.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bean="http://www.springframework.org/schema/bean"

xsi:schemaLocation="

        http://www.springframework.org/schema/beans 

        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

<bean id="mailSender"

class="org.springframework.mail.javamail.JavaMailSenderImpl">

<property name="host" value="smtp.somemailhost.com" />

<property name="port" value="25" />

<property name="username" value="someuser" />

<property name="password" value="somepassword" />

<prop key="mail.transport.protocol">smtp</prop>

<prop key="mail.smtp.auth">true</prop>

<prop key="mail.smtp.starttls.enable">true</prop>

<prop key="mail.debug">true</prop>

</property>

</bean>

</beans>


* DispatcherServlet 역할을 하는 XML 파일에 아래 내용을 추가한다.

<import resource="mail.xml" />


* 애플리케이션의 @Service 오브젝트에서 사용될 MailService 클래스를 작성한다. 아래는 간단한 예로 첨부 파일 발송, HTML 템플릿 등을 적용하려면 살을 더 붙여야 한다.

@Service("mailService")

public class MailService {

  @Autowired

  private MailSender mailSender;

  

  public void sendMail(String from, String to, String subject, String text) {

    SimpleMailMessage message = new SimpleMailMessage();

    message.setFrom(from);

    message.setTo(to);

    messate.setSubject(subject);

    message.setText(text);

    mailSender.send(message);

  }  

}


* 메일 발송 비즈니스 로직을 수행할 @Service 클래스에서는 아래와 같이 작성한다.

@Service("someService")

public class someService {

  @Autowired

  private MailService mailService;

  

  public void sendMail() {

    mailService.sendMail("from@MailAddress.com", "to@MailAddress.com", "someSubject", "someText");

  }

}


<참고자료>

Send Mail with Spring : JavaMailSenderImpl Example (by Lokesh Gupta)

http://howtodoinjava.com/2013/05/27/send-email-with-spring-javamailsenderimpl-example/


Spring Framework 3.2 Reference Documentation: 26. Email

http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mail.html


'Spring' 카테고리의 다른 글

Spring Transaction #2  (0) 2014.10.01
Spring Transaction #1  (0) 2014.10.01
VO, DTO, DAO  (0) 2013.07.08
domain object에 대한...  (0) 2013.07.08
Spring MultipartResolver  (0) 2013.07.02
자바 1.2 버전부터 제공되고 있지만 아직 다수의 개발자들이 잘 몰라서 활용을 잘 못하는 기능이 하나 있는데, 그 기능이 바로 쓰레드 단위로 로컬 변수를 할당하는 기능이다. 이 기능은 ThreadLocal 클래스를 통해서 제공되는데, 본 글에서는 ThreadLocal 클래스의 기본적인 사용방법과 활용 방법을 살펴보도록 하겠다.

ThreadLocal이란?

일반 변수의 수명은 특정 코드 블록(예, 메서드 범위, for 블록 범위 등) 범위 내에서만 유효하다.

{
    int a = 10;
    ...
   // 블록 내에서 a 변수 사용 가능
}
// 변수 a는 위 코드 블록이 끝나면 더 이상 유효하지 않다. (즉, 수명을 다한다.)

반면에 ThreadLocal을 이용하면 쓰레드 영역에 변수를 설정할 수 있기 때문에, 특정 쓰레드가 실행하는 모든 코드에서 그 쓰레드에 설정된 변수 값을 사용할 수 있게 된다. 아래 그림은 쓰레드 로컬 변수가 어떻게 동작하는 지를 간단하게 보여주고 있다.


위 그림에서 주목할 점은 동일한 코드를 실행하는 데, 쓰레드1에서 실행할 경우 관련 값이 쓰레드1에 저장되고 쓰레드2에서 실행할 경우 쓰레드2에 저장된다는 점이다.


ThreadLocal의 기본 사용법

ThreadLocal의 사용방법은 너무 쉽다. 단지 다음의 네 가지만 해 주면 된다.
  1. ThreadLocal 객체를 생성한다.
  2. ThreadLocal.set() 메서드를 이용해서 현재 쓰레드의 로컬 변수에 값을 저장한다.
  3. ThreadLocal.get() 메서드를 이용해서 현재 쓰레드의 로컬 변수 값을 읽어온다.
  4. ThreadLocal.remove() 메서드를 이용해서 현재 쓰레드의 로컬 변수 값을 삭제한다.
  5. 아래 코드는 ThreadLocal의 기본적인 사용방법을 보여주고 있다.

// 현재 쓰레드와 관련된 로컬 변수를 하나 생성한다.
ThreadLocal<UserInfo> local = new ThreadLocal<UserInfo>();

// 로컬 변수에 값 할당
local.set(currentUser);

// 이후 실행되는 코드는 쓰레드 로컬 변수 값을 사용
UserInfo userInfo = local.get();

위 코드만으로는 ThreadLocal이 어떻게 동작하는 지 잘 이해가 되지 않을테니, 구체적인 예제를 이용해서 ThreadLocal의 동작 방식을 살펴보도록 하겠다. 먼저 ThreadLocal 타입의 static 필드를 갖는 클래스를 하나 작성해보자.

public class Context {
    public static ThreadLocal<Date> local = new ThreadLocal<Date>();
}

이제 Context 클래스를 사용해서 쓰레드 로컬 변수를 설정하고 사용하는 코드를 작성할 차례이다. 아래는 코드의 예이다.

class A {
    public void a() {
        Context.local.set(new Date());
       
        B b = new B();
        b.b();

        Context.local.remove();
    }
}

class B {
    public void b() {
        Date date = Context.local.get();

        C c = new C();
        c.c();
    }
}

class C {
    public void c() {
        Date date = Context.local.get();
    }
}

위 코드를 보면 A, B, C 세 개의 클래스가 존재하는데, A.a() 메서드를 호출하면 다음 그림과 같은 순서로 메서드가 실행된다.


위 그림에서 1~10은 모두 하나의 쓰레드에서 실행된다. ThreadLocal과 관련된 부분을 정리하면 다음과 같다.
  • 2 - A.a() 메서드에서 현재 쓰레드의 로컬 변수에 Date 객체를 저장한다.
  • 4 - B.b() 메서드에서 현재 쓰레드의 로컬 변수에 저장된 Date 객체를 읽어와 사용한다.
  • 6 - C.c() 메서드에서 현재 쓰레드의 로컬 변수에 저장된 Date 객체를 읽어와 사용한다.
  • 9 - A.a() 메서드에서 현재 쓰레드의 로컬 변수를 삭제한다.
위 코드에서 중요한 건 A.a()에서 생성한 Date 객체를 B.b() 메서드나 C.c() 메서드에 파라미터로 전달하지 않는다는 것이다. 즉, 파라미터로 객체를 전달하지 않아도 한 쓰레드로 실행되는 코드가 동일한 객체를 참조할 수 있게 된다.

ThreadLocal의 활용

ThreadLocal은 한 쓰레드에서 실행되는 코드가 동일한 객체를 사용할 수 있도록 해 주기 때문에 쓰레드와 관련된 코드에서 파라미터를 사용하지 않고 객체를 전파하기 위한 용도로 주로 사용되며, 주요 용도는 다음과 같다.

  • 사용자 인증정보 전파 - Spring Security에서는 ThreadLocal을 이용해서 사용자 인증 정보를 전파한다.
  • 트랜잭션 컨텍스트 전파 - 트랜잭션 매니저는 트랜잭션 컨텍스트를 전파하는 데 ThreadLocal을 사용한다.
  • 쓰레드에 안전해야 하는 데이터 보관

이 외에도 쓰레드 기준으로 동작해야 하는 기능을 구현할 때 ThreadLocal을 유용하게 사용할 수 있다.

ThreadLocal 사용시 주의 사항

쓰레드 풀 환경에서 ThreadLocal을 사용하는 경우 ThreadLocal 변수에 보관된 데이터의 사용이 끝나면 반드시 해당 데이터를 삭제해 주어야 한다. 그렇지 않을 경우 재사용되는 쓰레드가 올바르지 않은 데이터를 참조할 수 있다.

 

+ Recent posts