본문 바로가기
  • think normal
새로워지기/서른의 생활코딩

스프링 부트에서 토비 3.1 따라하기 : 1장 - 1.6 싱글톤 레지스트리와 오브젝트 스코프

by 청춘만화 2019. 2. 27.

스프링 부트에서 토비 3.1 따라하기 

1장 오브젝트와 의존관계 - 1.6 싱글톤 레지스트리와 오브젝트 스코프

개발환경 

- OS : mac

- STS : 4.0.1

- MySQL : Server version: 8.0.13 Homebrew

- Frame-Work : 일단 최대한 의존성 없이 운영될 수 있도록 jar로 만 진행


관련 링크 

- 스프링 사용자 모임_홈페이지     http://www.ksug.org/

- 스프링 사용자 모임 질의응답     https://groups.google.com/forum/#!topic/ksug/13vB4tCFqrI

- 2017 스프링캠프                       https://www.youtube.com/playlist?list=PLdHtZnJh1KdZ6NDO9zc9hF4tONDLTSEUV



1장 오브젝트와 의존관계 

1.6 싱글톤 레지스트리와 오브젝트 스코프

이전 예제까지는 같은 결과를 도출하는 다른 방법이었지만 아래 프리비어슬리의 실행결과를 비교하면 각각의 결과가 서로 다르게 나온다. 그 원인을 이해하고 해결방안을 마련해보자 라는 취지의 단원입니다.


1.6.0  previously 프리비어슬리두가지 방식으로 IoC 구현 했습니다요 ;D 

1. 그냥 자바 코딩        - DaoFactory(오브젝트 팩토리)를 직접 만들어서 그 안에서 직접 사용

2. 스프링 자바코딩      - @Configuration 을 추가해서 애플리케이션 컨텍스트를 통해 사용 

userDao 라는 Bean 이름을 요청하면 DaoFactory 에서  userDao() 메소드를 호출해서 실행, 결과 회신 


* 테스트를 위해 IoCObjectTest 라는 이름으로 class를 새로 만들었습니다.

package springbook.user.dao;

import java.sql.SQLException;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IoCObjectTest {
	public static void main(String[] args) throws ClassNotFoundException, SQLException{
		
		//1. 그냥 자바 IoC 코딩
		DaoFactory factory = new DaoFactory();
		UserDao dao1 = factory.userDao();
		UserDao dao2 = factory.userDao();
		
		System.out.println(dao1);
		System.out.println(dao2);
		
		
		//2. 자바 스프링 IoC 코딩
		ApplicationContext context1 = new AnnotationConfigApplicationContext(DaoFactory.class);
		
		UserDao dao3 = context1.getBean("userDao",UserDao.class);
		UserDao dao4 = context1.getBean("userDao",UserDao.class);
		
		System.out.println(dao3);
		System.out.println(dao4);
	}
}

결과는 아래와 같이 팩토리로 생성된 객체는 서로 값이 다르고 어플리케이션 컨텍스트의 경우에는 값이 동일하게 나왔습니다.


아, 그런데 위  달리 에러가 날 수 있습니다 !!! 

Caused by: java.lang.IncompatibleClassChangeError: class org.springframework.core.type.classreading.ClassMetadataReadingVisitor has interface org.springframework.asm.ClassVisitor as super class


지난번에 추가한 jar 중에서 asm 파일이 문제인데요, 

asm.jar 파일을 지우시면 됩니다 ~ 


지우는 방법은 해당 프로젝트를 선택한 후 오른쪽 마우스 클릭~ 빌드패스 클릭~ 파일 선택 후 리무브 버튼 클릭~ 입니다

     ->     


구체적인 원인은 spring asm이 의존성 충돌해서 그렇습니다. 3.2버전 이후 부터는 spring-asm 라이브러리가 spring-core에 기본 포함되어 있어서 이런 충돌이 일어나는 거라고 합니다.


구글링 출처 

1) https://kooremo.tistory.com/entry/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B2%84%EC%A0%84-%EB%B3%80%EA%B2%BD%EC%8B%9C-%EC%97%90%EB%9F%AC-%EC%82%AC%ED%95%AD311321

2) https://choong0121.tistory.com/entry/orgspringframeworkasmClassVisitor-as-super-class


이는 오브젝트의 동일성과 동등성에 대한 이슈입니다.

자바에서는 두 개의 오브젝트가 완전히 같은 동일한 identical 오브젝트라고 말하는 것과 동일한 정보를 담고 있는 equivalent 오브젝트라고 불리는 오브젝트가 있습니다. 전자를 동일성 비교라고 하고 후자를 동등성 비교하고 한다. 

사족을 붙이자면 java는 변수에 값이 담기는 데 그 각각의 변수는 서로 다른 고유한 주소를 가지고 있다. 주소와 값 모두가 같으면 동일, 값만 같으면 동등 비교가 되겠다.

아.. 얼마 전에 TDD에서도 비슷한 예제가 있었던 것 같군요~ 링크를 걸어두겠습니다~  

스프링 부트에서 테스트 주도 개발 실습 - 3장. 모두를 위한 평등  


자 그럼 위 예제의 결과를 해석하면 Daofactory를 통해 userDao() 직접 호출한 오브젝트는 매번 호출 할때마다 새롭게(new) 생성된 오브젝트가 불려진다는 것을 알 수 있고 반면에 애플리케이션 컨텍스트를 이용하는 경우 (매번 new로 생성하지 않고) getBean() 메소드로 호출되어 가져온 오브젝트는 서로 동일하다는 것을 알 수 있다. 

따라서 애플리케이션 컨텍스트를 활용한 스프링 방식은 여러 번에 걸쳐 빈을 요청하더라도 매번 동일한 오브젝트를 돌려준다.



1.6.1 싱글톤 레지스트리와 오브젝트 스코프 

1. 그 이유는 

스프링에서 제공하는 애플리케이션 컨텍스트는 IoC 컨테이너 역할을 수행하기도 하지만 싱글톤을 저장하고 관리하는 싱글톤 레지스트리 이기도 하다. 때문에 별다른 설정을 하지 않으면 내부에서 생성하는 빈 오브젝트를 모두 싱글톤으로 만든다. 다만 디자인 패턴에서의 싱글톤과 개념은 비슷하지만 구현 방법은 확연히 다르다. 

1) 싱글톤 개념 : 어플리케이션 안에 제한된 수, 보통 한 개의 오브젝트만 만들어서 사용하는 것으로써 서버환경에서 적극 활용된다.

2) 결론부터 말하면 그냥 java로 디자인패턴 방식으로 싱글톤을 만드는 경우 여러 이슈가 발생할 수 있다. 따라서 스프링 컨테이너는 싱글톤을 생성, 관리, 공급하는 싱글톤 컨테이너 역할을 수행한다. 이것이 바로 싱글톤 레지스트리 이다. 스프링이 직접 싱글톤 형태의 오브젝트를 만들고 관히하는 기능을 제공한다.

3) 싱글톤 생성방식 비교

싱글톤 생성방식 비교


> 예약 <        나만의 예제 - 그냥 java에서 디자인 패턴으로 싱글톤 구현하기 


    " 아직 예정 대기 중.."

  



2. 자 그럼 왜 스프링은 싱글톤으로 빈을 만드는 것일까? 에 주목해보자 

1) 스프링은 서버용 프레임워크 

먼저 스프링은 독립형 프로그램 개발 전용이 아닌 엔터프라이즈 시스템을 사용하는 서버환경을 위한 기술이다. 엔터프라이즈 서버 환경은 많은 요청과 처리가 이뤄진다.또한 하나의 요청을 처리하기 위해 데이터 엑세스 로직, 서비스 로직, 비지니스 로직, 프리젠테이션 로직 등 다양한 기능을 담당하는 오브젝트들이 참여하는 계층형 구조로 이뤄진 경우가 많다. 

이때마다 각 로직을 담당하는 오브젝트를 만들어서 사용할 수가 없지않은가- 


2) 서블릿의 등장 

그래서 엔터프라이즈 분야에서는 서블릿과 같은 서비스 오브젝트라는 개념을 일찍부터 사용해왔다. 

대부분의 멀티스레드 환경에서 싱글톤으로 동작한다. 서블릿 클래스당 하나의 오브젝트만 만들어 두고 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용한다.

.. 아...! 그래서 각각의 이름을 다르게 하고 중복되면 에러 퓽퓽 발생하고 했었구나- 


3) 스프링이 빈을 싱글톤으로 만드는 것은 결국 오브젝트의 생성 방법을 제어하는 IoC의 역할이다.



1.6.2 
싱글톤과 오브젝트의 상태

멀티 스레드 환경이라면 여러 스레드가 동시에 접근해서 사용할 수 있으니 서비스 형태의 오브젝트를 사용하는 경우, 오브젝트에 상태 정보가 담겨있지 않은 무상태 stateless 형태로 만들어야 한다. 

따라서 싱글톤은 기본적으로 인스턴스 필드의 값을 변경하고 유지하는 상태유지 stateful 방식으로 만들지 않는다. 

.. 용어들이 쏟아져 나온다.. private과 같은 전역변수를 지향하라는 말로 이해해버렸다. 나쁘지 않은거 같다. 뒤에보니 

따라서 싱글톤을 멀티 스레드 환경에서 사용되는 경우 기존의 UserDao 처럼 개별적으로 바뀌는 정보는 로컬변수로 정의하거나 파라미터로 주고 받으면서 사용해야한다.


물론 인스턴스 변수를 사용이 불가능 한 것은 아니다. 

.. 인스턴스 변수가 전역 변수의 다른 이름인가보다... 이제라도 알아서 다행이다...

앞서 사용한 ConnectMaker의 경우 읽기 전용 정보 이기때문에 사용해도 좋다. 물론 단순한 읽기 전용이라면 static final이난 final로 선언하여 자유롭게 사용해도 좋다.



1.6.3 
스프링 빈의 스코프 

자.. 까먹지 말자. 

스프링 빈 = 스프링에서 관리하는 오브젝트 

그러면 본론으로 와서 빈 스코프 Bean Scope 는 빈이 생성되고 존재하고 적용되는 범위를 말한다.


그리고 스프링에서 만들어지는 대부분은 싱글톤 스코프를 갖는다.

= 컨테이너 내에 한 개의 오브젝트만 만들어져서, 스프링 컨테이너를 강제로 제거하지 않는 한 계속해서 유지된다.


구글에 찾아보니 다른 스코프들이 나와 있었다. 

그냥 지나치려고 하다가.. 아.. 내가 엄청 섰던 것들이 나왔다... 스프링 MVC 애플리케이션! 으흐흐 이제야 알고 쓸 수 있을 것 같다... 

라는 생각에 펌 해서 정리해본다.

스프링 빈 스코프의 종류 

스프링에서 Bean으로 지정된 객체는 기본적으로 싱글톤 객체로 관리된다. 하지만 요구사항 과 구현기능 등의 필요에 따라서 비싱글톤이 필요한 경우도 많다. 

스프링에서는 이를 명시적으로 구분하기 위해서 scope라는 키워드를 제공한다. 

빈 스코프(scope) 별도의 scope를 지정하지 않으면 스프링에서 default는 singleton 이다. 


스프링 일반 애플리케이션 

singleton : 기본 싱글톤 스코프 prototype : 어플리케이션에서 요청시 (getBean()) 마다 스프링이 새 인스턴스를 생성 

thred : 새 스레드에서 요청하면 새로운 bean 인스턴스를 생성, 같은 스레드에 대해서는 항상 같은 bean 인스턴스가 반환 

custom : org.pringframework.beans.factory.config.Scope를 구현하고 커스텀 스코프를 스프링의 설정에 등록하여 사용 


스프링 MVC 애플리케이션 

request : HTTP 요청별로 인스턴스화 되며 요청이 끝나면 소멸 (spring mvc webapplication 용도) 

session : HTTP 세션별로 인스턴스화되며 세션이 끝나며 소멸 (spring mvc webapplication 용도) 

global session : 포틀릿 기반의 웹 어플리케이션 용도. 전역 세션 스코프의 빈은 같은 스프링 MVC를 사용한 포탈 어플리케이션 내의 모든 포틀릿 사이에서 공유할 수 있다 


출처: https://javaslave.tistory.com/45 [전산쟁이 블로그]


더불어 스코프와 관련하여 

각각의 스코프를 사용한 사례가 나온 블로그 링크도 엮어둔다

                                 [Spring] Spring Bean Scope 종류    


     으헉.. 소름... 앞의 주소는 /45 인데 뒤에 주소는 /54 네...




끄읏 ~ 


댓글