스프링 @Bean 의 LifeCycle 주기에 대해서

Spring & Spring Boot 2021. 1. 19. 23:36

우리가 개발을 할때 사용하는 JAVA나 Spring @Bean 에 대해서 많이 들어봣을 것이다.

우리가 사용하는 Spring boot 에서는 처음 어플리케이션을 시작을 할때 @Bean 을 컨테이너에 사용하기 좋게 미리 넣어둔다. 

우리는 스프링이 DI컨테이너에 넣어둔 Bean을 꺼내어 사용하는것을 잘 알고 있을 것이다.

그렇다면 Bean은 언제 생성이 되고 언제 소멸이 되는지 궁금해 졋다.

◈ Spring Bean 이벤트 처리 

컨테이너 생성 

              ☞ 빈 생성

                          ☞ 외존관계 주입

                                              ☞ 초기화 콜백

                                                                  ☞ 실제 사용

                                                                                    ☞ 소멸되전 콜백

                                                                                                          ☞ 종료

 

 여기서 초기화 콜백소멸되기 전 콜백은 무엇을 말하는 것일까?

 

초기화 콜백 : 빈이 생성된 후 의존관계 주입이 일어난다. 의존관계 주입이 끝나면 호출

소멸되기 전 콜백 : 빈이 소멸되기 직전에 호출된다.

간단하게 Bean의 LifeCycle 생명 주기에 대해서 알아보았습니다.

설정

트랙백

댓글

@ComponentScan 이란?

Spring & Spring Boot 2021. 1. 15. 23:45

스프링 부트에서 공부를 하다보면은 @ComponentScan 이라는 어노테이션을 본적이 있을 것이다.

@ComponentScan 은 어떤 역할을 해주는가?

특정 어노테이션들을 자동으로 스캔을 해주는 아주 유용한 어노테이션이다.

기본적으로 @ComponentScan 어노테이션이 스캔해주는 대상은 5가지로 나뉠수 있다.

  1. @Component
  2. @Controller
  3. @Service
  4. @Repository
  5. @Configuration

5가지로 나뉘어 진다. 

 

그리고 @ConponentScan 은 자기가 위치하고 있는곳부터 스캔을 시작한다.

무슨말이냐면은 프로젝트 파일구조가 

java / com / spring / boot 라고 가정했을때 @ComponentScan 어노테이션을 가지고 있는 파일 현 위치가 com폴더에 존재고 있다고 하면은 com 위치부터 @Componet 가 붙어있는 녀석들을 찾아주는 것이다.

하지만 스프링 부트에서는 @ComponetScan 의 위치를 조절해야 하는 것들은 기본적으로 제공을 해주고 있다.

어떻게 제공을 해주고 있는가?

 

스프링 부트에서는

스프링 부트를 시작해주는 메인 메소드가 있다. 사진에 보이는 @SpringbootApplication 해당 어노테이션을 들어가 보면은

스프링 부트를 시작해주는 어노테이션에 우리가 알고싶어 하던 @ConponentScan 어노테이션이 정의 되어 있는 것을 확인 할 수 있다. 

그렇다면 당연히 부트를 시작 Run을 하게되면은 우리가 @ComponentScan 으로 하나하나 조절해가야 하는것을 자연스럽게 스프링 부트가 기능을 대신 해주는 것을 확인 할 수 가 있을 것이다.

설정

트랙백

댓글

@Configuration 과 싱글톤의 원리

Spring & Spring Boot 2021. 1. 10. 14:20

스프링을 사용하다보면은 @Configuration 과 싱글톤이라는 말을 많이 듣게 될 것이다.

※ 싱글톤은 무엇인가?

☞ 우리가 new 연산자로 객체를 생성하는 것은 잘 알고 있을 것이다. 그렇다면 똑같은 객체를 여러번 new 연산자로 

생성을 하게된다면 당연히 생성하는 것마다의 레퍼런스가 다를 것이다. 

여기서 문제점은 똑같은 객체를 100번 1000번 그이상으로 계속 사용할때마다 생성을 하고된다면 당연히 과부하가 걸릴 것이 뻔하다.

그렇다면 이러한 방법을 어떻게 해결할 수 있을까? 

싱글톤을 사용하는 것이다. 처음 최초로 사용할때 1번 객체를 생성하고 그 후 에 사용할때는 최초 생성한 것을 사용하는 것이 싱글톤이다.

아래 그림으로 확인해 보자.

@Configuration
public class ConfigApp {

	@Bean
	public MemberService memberService() {
		return new MemberServiceImpl( memberRepository());
	}

	@Bean
	public OrderService orderService() {
		
		return new OrderServiceImpl(  
				memberRepository(),
			    discountService()
			 );
	}

 

※ 싱글톤 전 

※ 싱글톤 적용 

 

그렇다면 과연 어떻게 처음 생성한 것을 사용할 수 있게 만들어 줄까? 제목에서 언급한 @Configuration 이라는 어노테이션이 DI컨테이너에 생성한 Bean을 관리해준다.

 

※ @Configuration

원리는 이러하다 처음 최초로 생성할때 는 위에 코드에서 우리가 작성한 코드로 객체를 생성한다. 

◈ 주의점 

실제 DI컨테이너에는 우리가 생성한 객체가 들어가는 것이 아니다. CGLIB 이라는 라이브러리를 사용하여 이 라이브러리가 생선한 객체를 DI컨테이너에 주입을 시켜주는 것이다.

그 후에 요청이 오면은 @Configuration DI컨테이너에 생성되어 있는 객체를 응답해주는 것이다.

설정

트랙백

댓글

#2 알고리즘 문제 풀기

코딩테스트 2021. 1. 3. 20:38

해당문제는 2016년 1월1일이 금요일이라고 가정했을 때 입력받은 month , day 의 요일을 구하는 문제입니다.

※ #1 달마다의 마지막 일수 , 요일 구하기 

☞ day에서 FRI 가 맨앞에 있는 이유는 1월1일이 금요일이기에 이순서로 지정을 한 것입니다.

☞ 2개의 배열을 사용하여 해당 몇월/몇일 은 무슨요일인기 어떻게 구하는 것인가?

 

※ #2 배열을 활용하여 요일 구하기 

☞ 1번째 해당 월의 일수를 total 변수에 모두 더한다.

 

☞ 2번째 일수를 total 변수에 더한다.

- 일수를 더할때 -1을 해주는 이유는 배열의 index는 0부터 시작이기때문에 -1을 해준 것입니다.

 

☞ total 일수의 더해진 것을 total % 7  연산자를 사용하면은 해당 주의 무슨 요일인지 나올 것입니다.

 

※ #3 전체 코드 

 

'코딩테스트' 카테고리의 다른 글

#3 알고리즘 문제 풀기  (0) 2021.01.05
#1 알고리즘 문제 풀기  (0) 2021.01.03

설정

트랙백

댓글

#1 알고리즘 문제 풀기

코딩테스트 2021. 1. 3. 03:46

오늘은 해당 문제를 풀어볼 것이다. 

 이라고 가정을 하고 진행을 해봅시다.

내가 생각한 방법은 HashSet으로 중복을 제거된 상태의 객체를 만든 후 그 set을 List에 담고 그것을 배열에 담아서 리턴해주는 방식으로 진행을 하였다.

 

 

※ #1 HashSet에 서로 다른 index의 값을 넣어주기 

   HashSet<Integer> set = new HashSet<Integer>();
	        
       for(int i=0; i<numbers.length;i++){
	       for(int i2=0; i2<numbers.length; i2++){
	           if(i == i2) {
	               continue;
	           }
	           set.add(numbers[i] + numbers[i2]);
	       }  
	   }  
	   return test(set);

☞ 이중for문을 돌면서 서로 다른 index에 있는 값들을 set에 넣어준다.

☞ HashSet은 중복된 값을 넣을 수 없기때문에 중복이 제거된 수만 넣어지게 된다.

☞ 리턴을 test 라는 함수에 인자값으로 던져준다.

 

※ #2 HashSet의 인자값을 배열형식으로 변환하기

  public static int[] test(HashSet set) {
			
	    	System.out.println(set);
	    	List<Integer> list = new ArrayList<Integer>(set);
			Collections.sort(list);
            
	    	int[] arr = new int[list.size()];
	    	
	    	for(int i=0; i<list.size(); i++) {
	    		arr[i] = list.get(i);
	    	}
	    	return arr;
	    }

☞ HashSet 을 List로 변환하기

☞ List에 있는 값들을 배열으로 변환하여 리턴시키기

방법은 간단합니다. 

변환된 List를 for문을 돌면서 배열에 넣어주고 그 배열을 리턴시켜주면 끝입니다.

 

※ #3 전체 코드 

    public static int[] solution(int[] numbers) {

	        HashSet<Integer> set = new HashSet<Integer>();
	        
	        for(int i=0; i<numbers.length;i++){
	            for(int i2=0; i2<numbers.length; i2++){
	                if(i == i2) {
	                    continue;
	                }
	                set.add(numbers[i] + numbers[i2]);
	            }  
	        }  
	        return test(set);
	    }
	
	    public static int[] test(HashSet set) {
			
	    	System.out.println(set);
	    	List<Integer> list = new ArrayList<Integer>(set);
	    	
	    	int[] arr = new int[list.size()];
	    	
	    	for(int i=0; i<list.size(); i++) {
	    		arr[i] = list.get(i);
	    	}
	    	return arr;
	    }

 

◈ 햇갈렷던 부분 

  1. 서로다른 index를 더하면 수많은 더한 값들은 어떻게 처리를 해야하는가?
  2.  
  3. 중복된 값들은 어떻게 중복제거를 할 것인가?
  4.  
  5. HashSet 을 어떻게 배열형식으로 리턴을 해주도록 할것인가?

위의 3개의 관점에서 햇갈렷던거 같습니다.

사람마다의 생각하는 것과 처리하는 것을 수많가지 이므로 이보다 더 좋은 처리방법or다른처리방법 댓글로 남겨주시면 감사하겠습니다.

 

'코딩테스트' 카테고리의 다른 글

#3 알고리즘 문제 풀기  (0) 2021.01.05
#2 알고리즘 문제 풀기  (0) 2021.01.03

설정

트랙백

댓글

Oracle (+) 연산자는 무슨 의미인가?

Oracle 2020. 12. 27. 23:05

오늘은 Oracle 에서 통영되는 질의문인 (+) 연산자에 대해서 기록을 해봅니다.

(+) 연산자는 어떠한 역할을 가지고 있는가? Mysql 에서는 OUTER JOIN 와 같은 의미라고 해도 무방하다고 생각합니다.

 

예시를 통하여 (+) 연산자를 알아보시다.

SELECT * FROM TEST A LEFT OUTER JOIN rank_test B ON A.NAME = B.NAME;
SELECT * FROM TEST A, rank_test B WHERE A.NAME = B.NAME(+);

위의 2개의 쿼리문으로만 봣을때는 결과가 동일하게 나옵니다. 여기서 (+) 연산자에 대해서 눈치 채셨나요?

▲해당 위의 테이블을 참조하여 생각해보자.

 

 SELECT * FROM TEST A LEFT OUTER JOIN rank_test B ON A.NAME = B.NAME;

해당 코드는 TEST 테이블 RANK_TEST 테이블OUTER JOIN을 하는데 LEFT 명칭을 붙여서 TEST 테이블을 다 출력되도록 OUTER JOIN 을 걸은 것을 볼 수 있다.

 

SELECT * FROM TEST A, rank_test B WHERE A.NAME = B.NAME(+);

이 쿼리문은 어떠한 의미를 가지고 있을까? 일단 결과는 위에서 말했다 시피 같다.

왜??? 같은 결과가 나오는 것인가?

쿼리문에서 보면은 B.NAME(+) 에 (+) 연산자를 사용할 것을 확인 할 수 있다.

아~ 그럼 A.NAME = B.NAME(+) 해당 조건에서 A 라는 별칭을 사용하고 있는 TEST 테이블이 OUTER JOIN이 걸리는걸 확인 가능하다.

반대로 A.NAME(+) =B.NAME 이렇게 사용한다면 B별칭을 사용하고 있는 RANK_TEST 테이블이 OUTER JOIN 이 걸릴 것이다.

 

※ 간단하게 (+) 연산자에 대해서 알아보았습니다.

'Oracle' 카테고리의 다른 글

Oracle 순위함수의 사용,간단한 사용예제  (0) 2020.12.27

설정

트랙백

댓글

Oracle 순위함수의 사용,간단한 사용예제

Oracle 2020. 12. 27. 17:33

오늘은 Oracle 에서 순위함수에 대해서 알아봅시다.

  • ROW_NUMBER()
  • RANK()
  • DENSE_RANK()

위의 3개의 함수를 사용하면서 개념을 알아봅시다.

아래는 예제로 사용할 테이블 컬럼들 입니다.

 

 SELECT ROWNUM ,rank_test.* FROM rank_test ORDER BY BOARD_CNT DESC;

위의명령어로 실행을 하였을때 우리의 생각과 다른 문제점이 1개가 발생합니다.

ROWNUM 시스템의 순번을 메기는 함수입니다. 하지만 ORDER BY 를 사용하는 순간

ROWNUM 의 순번이 뒤죽박죽으로 나오는 것을 확인할 수 있습니다.

분명히 ROWNUM 은 순번을 메기는 거라고 알고 있엇는데 왜 뒤죽박죽으로 나온것일까?

 

그 이유는 쿼리가 실행되는 순서에 관련이 있습니다.

지금 저 쿼리문에서 실행순서는 FROM -> ORDER BY -> SELECT  이 순서대로 실행되고 있기때문에 당현히 ORDER BY 된 후 SELECT 되기에 순서가 뒤죽박죽으로 나오는 것입니다.

 

자 그럼 어떻게 저 쿼리문을 사용하되 ROWNUM이 순서대로 나오게 할수 있을까?

이때 사용하는 함수가 ROW_NUMBER() 라는 함수 입니다.

SELECT  ROW_NUMBER() OVER (ORDER BY BOARD_CNT) AS SEQ ,rank_test.* FROM rank_test;

바뀐점은 ROWNUM => ROW_NUMBER() OVER ( ORDER BY 문 ) ROW_NUM() 함수를 사용하면서 ORDER BY 를 함수 () 안에 넣을 것입니다.

결과가 어떻게 나올까요?

SEQ 순번으로 지정한것이 순서대로 바르게 나오는 것을 확인할 수 있습니다.

 

SELECT RANK() OVER (ORDER BY BOARD_CNT) AS SEQ ,rank_test.* FROM rank_test;

RANK() 함수를 사용하면은 결과가 어떻게 나올까요?

결과창에서 이상한점이 보이시나요? SEQ 컬럼이 분명 1 다음 2가 나와야 할텐데 어째서 해당컬럼만큼 건너뛰어서 6이 나올까요?

어떻게 하면은 정상적으로 순번이 나오도록 할수 있을까?

SELECT DENSE_RANK() OVER (ORDER BY BOARD_CNT) AS SEQ ,rank_test.* FROM rank_test;

해당 쿼리문의 결과▼

정상적으로 1 - 2 - 3 으로 출력되는 것을 확인 할 수 있습니다.

추가적으로 지역별로 랭킹을 알고 싶을때는 PARTITION BY  라는 것을 사용하면 보다 편리하게 지역별 랭킹을 알 수있습니다.

 

SELECT DENSE_RANK() OVER ( PARTITION BY ADDRESS ORDER BY BOARD_CNT DESC) AS SEQ ,rank_test.* FROM rank_test;

해당 쿼리문의 결과

경기도/광주/서울 에서의 랭킹을 한눈에 볼 수 있습니다.

상황에 따라서 PARTITION BY 을 사용하면 보다 편리하게 사용할 수 있을거 같은 생각이 듭니다.

 

'Oracle' 카테고리의 다른 글

Oracle (+) 연산자는 무슨 의미인가?  (0) 2020.12.27

설정

트랙백

댓글

Spring @Bean 등록과 사용

Spring & Spring Boot 2020. 12. 20. 13:28

스프링에서는 DI컨테이너라는 핵심기술이 있다. DI컨테이너는 무엇일까?

DI컨테이너는 @Bean으로 등록한 객체들을 관리해주는 컨테이너 라고 생각해도 좋다.

그렇다면 @Bean 으로 DI컨테이너에 어떻게 등록을 할까?

기존 외부에서 관리해주는 ConfigApp 이라는 클래스에 @Configuration 이라는 어노테이션을 등록을 해준다.

그렇다면 그 클래스안에 있는 메소드들을 @Bean이라는 어노테이션을 작성하여 DI컨테이너에 Bean으로 등록을 할 수 있다.

 

그렇다면 @Bean 으로 등록을 한 객체들을 어떻게 사용을 하는 것 인가?

 

 

위 사진의 에서 주석이 된 코드를 보면은 개발자가 직접 객체를 생성하고 사용을 하는 것을 확인할 수 있다.

하지만 아래 코드에서는 DI컨테이너에 등록된 Bean을 Bean의 이름과 타입을 지정해서 사용하는 것을 볼 수 있다.

 

설정

트랙백

댓글

Spring 관심사의 분리 (의존관계 주입 개념)

Spring & Spring Boot 2020. 12. 17. 23:26

관심사의 분리란 무엇일까?

말그대로 서로의 관심사를 따로따로 향하도록 분리를 시키는 것이다.

예로 들어 한 식당의 주방장이 요리를 하면서 서빙을 하는 것 VS 주방장은 요리만 서빙은 알바만 하도록 하는 것

코드로 예시로 이해해보자.

1번째 주방장이 요리를 하면서 서빙도 같이 한다는 것을 코드로 하는게 어떤식일까? 

여기서 보면은 해당 A라는 클래스에는 MemberService와 구현클래스인 MemberServiceImpl 을 둘다 의존하고 있다.

이러한 경우에는 DIP(Dependercy Inversion Principle) 을 위반하는 것과 같다고 생각한다.

※ 위같은 경우 문제점은 해당 인터페이스의 다른 로직을 수행해야 할 경우 MemberServiceImpl의 클래스에서 수정이 이루어 져야 한다. 수정이 이루어 지는 순간 OCP (Open / Close Principle) 원칙을 위반 하게 된다.

그러하면 DIP원칙,OCP원칙을 지키게 하기위해서는 어떻게 코드를 해야하는 것일까?

위 사진에서는 [ 인터페이스 변수명 = new 구현체; ]  이런식이지만 오로지 인터페이스만 의존하도록 코드를 바꾸면

이렇게 코드를 수정을 하게 된다면? 구현체가 아닌 오로지 Only 인터페이스만 의존하게 되는 것이다.

그렇다면 ConfigApp 이라는 클래스를 만들어서 의존관계 주입 개념을 도입을 하게 되면 더욱 DIP,OCP 원칙을 지키면서 개발을 할 수 있게 된다.

 

MemberSericeImpl 클래스에는 MemberRepository 라는 인터페이를 의존하고 있다.

그와동시에 MemberRepository 의 구현체는 생성자를 통해서 받아오고 있다.

ConfigApp 이라는 클래스에서 리턴해주는것이 MemberServiceImpl 과 위 사진에서 생성자로 받을 수 있게 해둔 MemberRepository 구현체를 리턴해주는 것이다.

한마디로 MemberServiceImpl 과 MemoryMemberRepository 를 리턴해주는 것이다.

 

그렇다면 ConfigApp 클래스를 어떻게 사용하여야 하는 것일까?

 

아래 사진은맨 처음 사진과 같은 메인 클래스 이다.

일단 첫번째로 ConfigApp을 인스턴스화를 해야한다.

아래코드를 보면 처음 코드방식과 조금 다를것이다. 처음사진은 바로 new MemberServiceImpl 을 했엇지만

이 사진은 config.MemberService() 를 사용하였다.

config에서는 2가지 역할이 있다.

1번째 MemberService의 구현체인 Impl을 생성한다.

2번째 생성자로 Impl에서 사용하는 인터페이스도 같이  생성을 하게 되면은 

Impl에서 사용하는 인터페이스에서 기능 추가/ 다른 기능 사용 등등 다양한 이유가 있지만 수정이 일어날 경우 Impl을 고칠 필요가 없다. 

오로지 interface에만 의존을 하고 있기 때문이다. 

그렇다면 메인 메소드에서는 오로지 무엇을 사용할지만 관심을 가지면 될 것이다.

 

아주 간단하면서도 복잡한 개념인거 같다.

 

※ 해당 블로그는 공부용/기록용으로 쓰입니다. 간단한 피드백 주시면 감사히 받겠습니다.

설정

트랙백

댓글

스프링 이란 무엇일까

Spring & Spring Boot 2020. 12. 11. 23:28

                                                  ◈ 스프링에 대해 간단하게 알아보자

스프링이란 첫번째 목표는 개발을 할때 더욱 편리하게 더욱 가속성 있게 개발을 하기위해 만들어 진 것이라고 생각합니다.

과연 어떻게 더욱 편리하게 개발을 지원을 해줄까? 라는 생각이 들겁니다.

스프링은 JAVA를 기반한 프레임 워크라고 해도 무방합니다.

JAVA가 무엇이 좋으냐? 라고 물어보면은 저는 당연하게 "객체지향에 특화되어 있어서요~" 라고 대답을 할 것입니다.

즉 스프링은 JAVA가 가진 "객체지향"을 더욱 극대화시켜주는 프레임 워크입니다.

정리하자면은 스프링은 객체지향을 극대화시켜서 개발을 편하게 지원도와주는 프레임 워크라고 생각합니다.

스프링에 대해 간단하게 알아 보았습니다.

 

☞ 저의 공부를 위한 용도이므로 더 많은 지식과 잘못된 것이 있으면 댓글로 공유 부탁드립니다.

 

설정

트랙백

댓글