Spring 프레임워크에서 쓰이는 디자인패턴

devdo·2022년 1월 8일
0

Spring

목록 보기
6/11
post-thumbnail

전에는 GOf의 디자인패턴 정리로 블로그를 정리해보았는데,

이번에는 스프링 프레임워크 중심으로 디자인패턴이 무엇이 있는지 확인해볼려고 한다.

스프링 프레임워크는 좋은 웹 개발 플랫폼이지만, 내부 구현도 학습가치가 있을정도로 디자인 패턴을 사용해 잘 작성되어있다.

스프링 프레임워크안에서 어떻게 디자인 패턴이 사용되었는지 확인해 보자.

1) Proxy 패턴

스프링에서는 AOP(Aspect Oriented Programming)에 기반해 수많은 로깅처리, 트랜잭션 처리를 고통 모듈화시켜 따로 작성해둔다. Spring의 AOP는 CGLIB이라는 런타임 프록시 생성 라이브러리를 사용해, AOP를 위한 프록시 객체를 생성한다.

너무 어려운 말이지만... 중요한 건 Proxy는 대리로서 대신 기능을 호출하는 정도로만 이해해두자!

xml과 AspectJ 스크립트를 사용해 대상객체들에 대한 프록시를 생성하므로 코드로 적을수는 없다.

참고로 CGLIB을 사용하면 프록시의 대상이 되는 객체가 인터페이스를 구현 안했더라도 프록시 방식으로 대상 객체의 메소드를 사용할수 있다.


2) Singleton 패턴

스프링의 XML및 configuration파일안에 설정된 Bean들은 기본적으로 싱글톤 패턴이다.

✅ 싱글톤 패턴을 사용하는 이유
만약 우리가 만들었던 DI 컨테이너인 요청을 할 때마다 새로운 객체를 생성한다고 하자. 요청이 엄청나게 많은 트래픽 사이트에서는, 계속 객체를 생성하게 되면 메모리 낭비가 심해진다! 스프링 프레임워크는 기본적으로 빈 객체 인스턴스를 생성하고 이를 어플리케이션 내에서 공유하여 사용한다!

싱글톤 패턴 구현

public class Singleton {
	static Singleton singletonObject; // 정적 참조 변수
	
	private Singleton() {}; // private 생성자
	
	// 객체 반환 정적 메서드
	public static Singleton getInstance() {
		if(singletonObject == null) {
			singletonObject = new Singleton();
		}
		return singletonObject;
	}
}

public class Client {
	public static void main(String[] args) {
		// private 생성자이므로 new를 통해 인스턴스를 생성할 수 없음
		// Singleton s = new Singleton();
		// 싱글톤으로 객체 생성없이 미리 가져올 수 있음!
		Singleton s1 = Singleton.getInstance();
  }

💥 그러나 싱글톤 패턴의 문제점

  • 싱글턴 패턴을 구현하는 코드 자체가 많다.
  • 의존관계상 클라이언트가 구체 클래스에 의존한다.
  • 테스트하기 어렵다.
  • 내부 속성을 변경하거나 초기화 하기 어렵다.
  • private 생성자로 자식 클래스를 만들기 어렵다.
  • 싱글톤 컨테이너

즉, 싱글턴 패턴을 사용하게 되면 유연성이 떨어지게 된다는 것이다.

하지만, 스프링에서 위에 단점들을 모두 해결해준다.

스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도 객체 인스턴스를 싱글톤으로 관리한다. 이러한 기능 덕분에 싱글톤 패턴의 모든 단점을 해결하고 객체를 싱글톤으로 유지할 수 있다. 어떻게 이 단점을 해결하는지는 아래에 적어두었다!

싱글턴 방식의 주의점 ✨

싱글톤 패턴이든, 스프링에서 객체 인스턴스를 하나만 생성해서 공유하는 상황에서 객체 인스턴스를 공유하기 때문에 객체 상태를 유지(stateful)하게 설계하면 안된다.

  1. price는 공유되는 필드이기 때문에 특정 클라이언트가 값을 변경한다.
  2. 실무에서 이런 경우를 종종 보는데, 이로인해 정말 해결하기 어려운 큰 문제들이 터진다.(몇년에 한번씩 꼭 만난다.)

@Configuration @Bean

@Configuration @Bean을 붙인 객체는 스프링이 cglib 라이브러리로 만든 프록시 클래스다.

프록시 클래스 내에서 @Bean 이 붙은 메서드 마다 이미 빈이 존재하면 존재하는 빈을 반환하고, 빈이 없다면 생성해서 빈으로 등록하고 반환하는 코드가 동적으로 만들어 지는 것이다.

이렇게 스프링 컨테이너를 사용하면 싱글톤 빈을 보장받을 수 있다.


3) 전략(Strategy) 패턴

DI(Dependecy InJection)를 사용할 때 이 전략 패턴을 사용한다.
파라미터로 사용하여 그 컨텍스트에 주입하는 방식이다.


4) Template Method 패턴

jdbc를 사용할때 사용하는 jdbcTemplate, jmx 사용시에 사용되는 jmxTemplate, jpa를 사용할때 사용하는 jpaTemplate등의 클래스, 라이브러리들은 템플릿 메소드 패턴방식으로 구현되어있다.

템플릿 메소드 패턴이란 핵심로직처리부분은 부모 클래스에 대부분 구현되어있고, 상속받은 자식 클래스는 최종적인 부분만 각기 다르게 구현하는 패턴이다. 일종의 인터페이스 형식인 것이다.

jdbcTemplate 는 커넥션 완전히 정리하기, 결과반복, 예외처리, 트랜잭션 처리등의 복잡하고 세부적인 사항들을 스프링 내부에서 알아서 처리해주는 코드가 미리 들어가 있고, 또한 다양한 generic 를 지원한다.

최종적인 db binding( SELECT, UPDATE, INSERT, DELETE등의 쿼리를 전달하는 부분)을 jdbcTemplate이 템플릿이 호출한다. 물론 db는 oracle 혹은 mysql 어느것이라도 될수 있다.



그외 패턴들 In 스프링 프레임워크

요즘에 나타나고 있는 디자인 패턴 트렌드는 기존의 독립적인 GoF 디자인 패턴과는 사뭇다르게, 서비스나 프레임웍과 조합된 디자인 패턴들이 많이 나오고 있는 것이 특징이다. 대표적인 것들은 다음과 같다.

1) Dependency Injection

프레임웍(주로 서블릿컨테이너)에서 사용자가 사용하는 객체를 생성하고 관리해주는 방식이다.


2) MVC(Model View Controller) 패턴

Spring MVC에서는 유저가 작성한 Controller가 하나의 웹서버에 의존적인 서블릿 방식으로 작성하고 동작하는 것이 아니라, POJO방식으로 구현된다.

이렇게 하면 Url Controller에 대한 테스팅이 더욱 독립적이고 간편해지게 된다. 또한 Controller의 역할을 논리적인 view의 이름 (예를 들어 home.jsp)

으로 한정해주고, 실제 UI구성은 View Resolver (JSP나 Velocity같은 템플릿 처리엔진)에게 맞기기 때문에, 컨트롤러의 독립성과 재사용성을 높어주게 된다.


3) Front Controller(DispatcherServlet)

스프링은 DispatcherServlet 이라는 Front Controller방식을 채택하고 있다. 이 Front Controller는 모든 User Controller 바로앞에서 들어오는 모든 리퀘스트를 일단처리해서 User Controller로 전달해 주고, User Controller로부터 결과를 받는 역할을 한다.

이러한 방식을 통해 예외처리나 쿠키처리, 브라우저로부터의 파일전송등 복잡하고 까다로운 역할은 DispatcherServlet이 하고, 유저는 순수 로직에만 집중할수 있게 도와준다.


4) View Helper

스프링은 매우 많은 자체 JSP tag들과 Velocity macro등을 가지고 있다. 그렇기 떄문에 JSP나 Velocity 로 서버쪽 UI를 구성한경우, 스프링기반 컨트롤러와 자연스럽게 연동할수 있다. Apache Tile와 SiteMesh등이 대표적이다.




참고

스프링 프레임워크 안의 디자인 패턴 (Design Patterns in Spring Framework)|작성자 IDEO

profile
배운 것을 기록합니다.

0개의 댓글