반응형

 

 

[ 정렬의 종류 ]

재귀를 이용하지 않는 정렬

1) Selection Sort(선택정렬)

2) Bubble Sort(버블정렬)

3) Insertion Sort(삽입정렬)

 

재귀를 이용하는 정렬

4) Merge Sort

5) Quick Sort

 

 

 

 

 

1. Selection Sort

가장 큰 값을 찾아 맨 오른쪽으로 보낸다.

 

 

ex) 학생의 성적을 정렬하는 프로그램

학생은 학번, 영어, 수학, 국어 성적을 가지고 있음

국어 성적을 기준으로 내림차순 정렬 (selection sort)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct Student {
    int stu_id;
    int eng;
    int math;
    int korean;
};

struct Student* selectSort(struct Student *arr_std, int n){
    
    int i, j, max, maxId;
    struct Student tmp;
    
    for(j=0; j<n-1; j++){
        max = arr_std[0].eng;
        maxId = 0;
        for(i=0; i<n-j; i++){
            if(arr_std[i].eng > max){
                max = arr_std[i].eng;
                maxId = i;
            }
        }
        tmp = arr_std[n-1-j];
        arr_std[n-1-j] = arr_std[maxId];
        arr_std[maxId] = tmp;
    }
    
    return arr_std;
}

int main(void) {
    
    int n, i;
    scanf("%d", &n);

    struct Student *arr_std = (struct Student *)malloc(sizeof(struct Student) * n);

    int stu_id_first = 20210001;
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr_std[i].stu_id = stu_id_first + i;
        arr_std[i].eng = rand() % 101;
        arr_std[i].math = rand() % 101;
        arr_std[i].korean = rand() % 101;
    }
    
    arr_std = selectSort(arr_std, n);
    
    for(i=0; i<n; i++){
        printf("%d %d %d %d\n", arr_std[i].stu_id, arr_std[i].eng, arr_std[i].math, arr_std[i].korean);
    }
    
    return 0;
}

 

 

 

 

2. Bubble Sort

두 개 중에 큰 값을 오른쪽에 배치한다.

 

 

 

 

 

 

3. Insertion Sort (삽입정렬)

왼쪽부터 한 숫자씩 선택하면서 자리를 찾고 바꾼다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int* insertSort(int *arr, int n){
    int i,j,tmp;
    
    for(i=1; i<n; i++){
        for(j=0; j<i; j++){
            if(arr[j] > arr[i]){
                tmp = arr[j];
                arr[j] = arr[i];
                arr[i] = tmp;
                continue;
            }
        }
    }
    return arr;
}

int main(void) {
    
    int i,n;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    srand((unsigned)time(NULL));
    
    
    for(i=0; i<n; i++){
        arr[i] = rand() % 100;
        printf("%d ",arr[i]);
    }
    printf("\n");
 
    arr = insertSort(arr, n);
    
    for(i=0; i<n; i++){
        printf("%d ",arr[i]);
    }
    printf("\n");
    return 0;
}

 

 

 

 

4. Quick Sort

평균 수행시간 : nlogn

최악 수행시간 : n^2

 

 

1) j는 0부터 n-1까지 돈다.

2) 값이 젤 오른쪽 값보다(pivot) 작으면 i와 j 위치의 값을 서로 바꿔준다. i++

3) j loop가 끝나면 i와 pivot 자리의 값을 바꾼다.

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int partition(int *arr, int s, int e){
    
    int i, j, tmp;
    
    i = s;
    for(j=s; j<e; j++){
        if(arr[j] < arr[e]){
            tmp = arr[j];
            arr[j] = arr[i];
            arr[i] = tmp;
            i++;
        }
    }
    
    tmp = arr[e];
    arr[e] = arr[i];
    arr[i] = tmp;
    
    return i;
}


void quickSort(int *arr, int p, int r){
    int q;
    
    if(p < r){
        q = partition(arr, p, r);
        quickSort(arr, q+1, r);
        quickSort(arr, p, q-1);
    }
}

int main(void) {
    
    int n;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    
    int i;
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand()%100;
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    quickSort(arr, 0, n-1);
    
    
    
    for(i=0; i<n; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    return 0;
}

 

 

 

 

 

 

 

5. Merge Sort

1) 반으로 반으로 끝까지 나눈다.

2) 나눠진 두 그룹을 합치면서 정렬한다.

3) 나눴던 것들을 계속 합치면서 정렬한다.

 

합할 때는 i = s, j = q + 1, t = s 로 시작해서 

arr[i] 와 arr[j] 중에 더 작은 것을 새로운 배열에 넣는다. 이 때 새로운 배열의 인덱스는 t이다.

 

 

 

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

void merge(int *arr, int s, int q, int e, int n){
    int *new_arr = (int *)malloc(sizeof(int) * n);
    
    int i = s, j = q+1, k = s;
    
    while(i <= q && j <= e){
        if(arr[i] > arr[j]){
            new_arr[k++] = arr[j++];
        } else {
            new_arr[k++] = arr[i++];
        }
    }
    
    while(i <= q){
        new_arr[k++] = arr[i++];
    }
    while(j <= e){
        new_arr[k++] = arr[j++];
    }
    
    for(i=s; i<=e; i++){
        arr[i] = new_arr[i];
    }
}

void mergeSort(int *arr, int s, int e, int n){
    int q;
    if (s < e){
        q = (s + e) / 2;
        mergeSort(arr, s, q, n);
        mergeSort(arr, q+1, e, n);
        merge(arr, s, q, e, n);
    }
}

int main(void) {
    int n;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    int i;
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand()%100;
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    mergeSort(arr, 0, n-1, n);
    
    
    for(i=0; i<n; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    
    return 0;
}

 

 

* 퀵 소트는 먼저 정렬을 하고 나서 나눠가는 방식인데 비해, 머지 소트는 먼저 나누고 정렬을 해 나간다.

 

반응형
반응형

 

 

 

1. 개념

- 정적 할당 : 변수 선언을 통해 필요한 메모리 할당

- 동적 할당 : 실행 중에 운영체제로부터 할당 받음 (by Heap)

 

2. 사용법

malloc() / free()

* stdlib.h 을 include 해야 함

 

 

1) 기본 타입 메모리

int *pInt = (int *)malloc(sizeof(int));
char *pChar = (char *)malloc(sizeof(char));

 

 

2) 배열 타입 메모리

int *p = (int *)malloc(sizeof(int) * 5);

 

 

 

 

3. 예시 문제

1) 임의의 정수 n개를 입력받아 n개의 난수를 만들어(0~999) 이를 오름차순을 정렬하는 프로그램

(동적할당 + 선택정렬)


#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    
    int n, i;
    
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand() % 1000;
        printf("%d ", arr[i]);
    }
    printf("\n\n");
    
    
    // selection sort
    int j, k, max, maxIdx, tmp;
    
    for(k=0; k<n-1; k++){
        max = arr[0];
        maxIdx = 0;
        for(j=0; j<n-k; j++){
            if(max < arr[j]){
                max = arr[j];
                maxIdx = j;
            }
        }
        
        // 젤 뒤로 보내기
        tmp = arr[n-1-k];
        arr[n-1-k] = arr[maxIdx];
        arr[maxIdx] = tmp;
    }
    
    for(i=0; i<n; i++){
        printf("%d ", arr[i]);
    }
    printf("\n");
    
    
    return 0;
}

 

 

(동적할당 + 버블정렬)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    
    int n, i;
    scanf("%d", &n);
    
    int *arr = (int *)malloc(sizeof(int) * n);
    srand((unsigned)time(NULL));
    
    for(i=0; i<n; i++){
        arr[i] = rand() % 1000;
        printf("%d ",arr[i]);
    }
    printf("\n");
    
    // bubble sort
    int j, k, tmp;
    
    for(k=0; k<n-1; k++){
        for(j=0; j<n-1-k; j++){
            if(arr[j] > arr[j+1]){
                tmp = arr[j+1];
                arr[j+1] = arr[j];
                arr[j] = tmp;
            }
        }
    }
    
    for(i=0; i<n; i++){
        printf("%d ",arr[i]);
    }
    printf("\n");
    
    return 0;
}

 

 

 

 

 

 

 

 

 

 

반응형
반응형

 

1. 개념 정리

조합 : 순서가 상관없음

순열 : 순서가 상관있음

중복 : 같은 아이템을 여러 번 뽑을 수 있는지 (중복조합 / 중복순열)

 

 

 

2. 문제 해결 방법

- k : 앞으로 뽑아야 할 크기

- Trivial Case : k가 0일 때

- Recursive Case (if k > 0) : 앞으로 K 개를 더 뽑아야 하므로 일단 1개를 뽑고 같은 함수를 이용해 k-1개를 더 뽑는다.

 

 

3. 예시

1) 공뽑기 : A, B, C, D, E, F,G가 적혀 있는 공 7개에서 3개를 뽑는 경우를 구하라

=> 순서가 상관없고 중복이 없으므로 "조합" 문제이다.


#include <stdio.h>

void pick(int n, int* bucket, int bucketSize, int k, char* balls){
    int i, lastIndex,smallest, item;
    if(k == 0){
        for(i=0; i<bucketSize; i++){
            printf("%c ", balls[bucket[i]]);
        }
        printf("\n");
        return;
    }
    
    lastIndex = bucketSize - k - 1;
    
    if(bucketSize == k){
        smallest = 0;
    } else {
        smallest = bucket[lastIndex] + 1;
    }
    
    for(item=smallest; item<n; item++){
        bucket[lastIndex+1] = item;
        pick(n, bucket, bucketSize, k-1, balls);
    }
}

int main(void) {
    
    int n = 7;
    char balls[7] = {'A','B','C','D','E','F','G'};
    int bucket[3];
    
    pick(n, bucket, 3, 3, balls);
    
    
    return 0;
}

 

 

 

 

2) 배우들 중 n명을 뽑아서 최우수, 우수상을 수여하기로 한다. 1명은 단 하나의 상만 받을 수 있다.

배우는 공유, 김수현, 송중기, 지성, 현빈 5명 중에서 선택한다고 하자. 어떤 경우가 가능한가?

=> 순서가 중요하고, 중복이 허용되지 않으므로 "순열" 문제이다.

 


#include <stdio.h>

int isIn(int* bucket, int size, int num){
    int i;
    for(i=0; i<size; i++){
        if(bucket[i] == num)
            return 1;
    }
    return 0;
}

void pick(int n, int* bucket, int bucketSize, int k, char balls[][10]){
    int i, lastIndex, item;
    if(k == 0){
        for(i=0; i<bucketSize; i++){
            printf("%10s", balls[bucket[i]]);
        }
        printf("\n");
        return;
    }
    
    lastIndex = bucketSize - k - 1;
    
    for(item=0; item<n; item++){
        if(!isIn(bucket, lastIndex+1, item)){
            bucket[lastIndex+1] = item;
            pick(n, bucket, bucketSize, k-1, balls);
        }
    }
}

int main(void) {
    
    int n = 5;
    char actors[5][10] = {"공유", "김수현", "송중기","지성", "현빈"};
    
    
    int bucket[2];
    
    pick(n, bucket, 2, 2, actors);
    
    
    return 0;
}

 

 

 

3) 4진법으로 만들 수 있는 n자리 수를 모두 나열하는 프로그램 작성하시오

입력 : 3  (3자리 수)

출력 : 000, 001, ..., 333 으로 나오면 된다.

=> 순서가 중요하고, 중복이 가능하므로 "중복순열" 문제이다. 

#include <stdio.h>

void pick(int n, int* bucket, int bucketSize, int k, int* balls){
    int i, lastIndex, item;
    if(k == 0){
        for(i=0; i<bucketSize; i++){
            printf("%d", balls[bucket[i]]);
        }
        printf("\n");
        return;
    }
    
    lastIndex = bucketSize - k - 1;
    
    for(item=0; item<n; item++){

        bucket[lastIndex+1] = item;
        pick(n, bucket, bucketSize, k-1, balls);
    
    }
}

int main(void) {
    
    int n = 4;
    int num[4] = {0,1,2,3};
    
    int bucket[3];
    
    pick(n, bucket, 3, 3, num);
    
    
    return 0;
}

 

 

 

4) 1부터 n까지의 연속되어 있는 수와 +/-를 이용해서 만들 수 있는 모든 수식을 그 결과와 함께 나열하시오

- 입력 : 2

- 출력:

 + 1 + 2 = 3

+ 1 -2 = -1

-1 + 2 = 1

-1 -2 = -3

 

=> 1과 2는 그대로 있고, +와 -를 이용해 중복순열을 처리하는 문제이다.

#include <stdio.h>

int charToInt(char x, int sum, int n){
    if(x == '+'){
        sum += n;
    } else {
        sum -= n;
    }
    return sum;
}

void func(int n, char bucket[2], int bucketSize, int k, char *balls){
    
    int i, j;
    int balls_idx = bucketSize - k;
    
    if(k == 0){
        int sum = 0;
        for(j=0; j<bucketSize; j++){
           
            printf("%c", balls[j]);
            printf("%d", j+1);
            sum = charToInt(balls[j], sum, j+1);
            
        }
        printf("=%d\n", sum);
        return;
    }
    
    for(i=0; i<bucketSize; i++){
        balls[balls_idx] = bucket[i];
        func(n, bucket, bucketSize, k-1, balls);
    }
}

int main(void) {
    
    char bucket[2] = {'+','-'};
    
    char answer[2];
    
    int n;
    
    scanf("%d", &n);
    
    func(n, bucket, 2, n, answer);
    
    
    return 0;
}

 

 

 

 

 

5) 1000,5000,10000원 짜리 지폐로 입력값을 만들 수 있는 모든 방법을 출력하시오

입력 : 6000

출력 :

- 1000 1000 1000 1000 1000 1000

- 5000 1000

 

=> 순서가 중요하지 않고, 중복을 허용하므로 "중복조합"이다. 

#include <stdio.h>

int sumBalls(int *balls, int ballSize){
    int i, sum = 0;
    for(i=0; i<ballSize; i++){
        sum += balls[i];
    }
    return sum;
}

void func(int input, int *bucket, int bucketSize, int k, int *balls, int ballSize){
    int i, j;
    
    int sum_balls;
    sum_balls = sumBalls(balls, ballSize);
    
    if(sum_balls == input){
        for(j=0; j<ballSize; j++){
            printf("%d ", balls[j]);
        }
        printf("\n");
        return;
    } else if(sum_balls > input){
        return;
    }
    
    for(i=k; i<bucketSize; i++){
        balls[ballSize] = bucket[i];
        func(input, bucket, bucketSize, i, balls, ballSize+1);
    }
    
}

int main(void) {
    
    int moneys[3] = {1000,5000,10000};
    int answer[1000];
    int input;
    
    scanf("%d", &input);
    
    func(input, moneys, 3, 0,  answer, 0);
    
    return 0;
}

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

1. MVC Pattern

Model : 결과 데이터

View : UI

Controller : Request 처리, Request/Response 데이터 전달

 

 

 

2. Spring MVC 

: MVC Framework(spring-webmvc)

-> Spring DI, AOP 이용가능

 

🔑 MVC 모델

1. MVC 모델 1과 MVC 모델 2의 차이점에 대해 설명하시오.

👉🏻 MVC 모델 정리 포스팅

👉🏻 MVC란 Model, View, Controller의 줄임말로써, MVC는 사용자와 상호작용하는 S/W를 디자인함에 있어 세가지 요소로 쪼개어 하는 것을 의미합니다. MVC 모델 1은 웹 브라우저의 요청을 JSP 페이지가 받아서 처리 하는 구조입니다. JSP 페이지 안에서 모든 정보를 표현(view)하고 저장(model)하고 처리(control)되므로 재사용이 힘들고, 읽기도 힘들어 가독성이 떨어집니다. 주로 중소형 프로젝트에 적합한 모델입니다. MVC 모델 2는 모델 1과 달리 웹 브라우저의 요청을 하나의 서블릿이 받게 됩니다. 서블릿은 웹 브라우저의 요청을 알맞게 처리한 뒤, 그 결과를 JSP로 포워딩 합니다. 처리 작업의 모듈화로 유지보수가 쉬워지는 반면 개발 시간이 늘어난다는 단점을 가지고 있습니다. 

(+) Spring MVC 모델 2

👉🏻 스프링 MVC 프레임워크는 스프링이 제공하는 트랜잭션 처리, DI, AOP를 손쉽게 사용할 수 있습니다.
다른 MVC 프레임워크와 마찬가지로 컨트롤러를 사용하여 요청을 처리합니다. 스프링에서는 DispatcherServlet이 MVC에서의 컨트롤러(Controller)부분을 처리합니다. 

 

💡 구성 요소

구성 요소 설명
DispatcherServlet 클라이언트의 요청을 전달받아 요청에 맞는 컨트롤러가 리턴한 결과값을
View에 전달하여 알맞은 응답을 생성한다.
HandlerMapping 클라이언트의 요청 URL을 어떤 컨트롤러가 처리할지 결정한다.
Controller 클라이언트의 요청을 처리한 뒤, 결과를 DispatcherServlet에 리턴한다.
ModelAndView 컨트롤러가 처리한 결과 정보 및 뷰 선택에 필요한 정보를 담는다.
ViewResolver 컨트롤러의 처리 결과를 생성할 뷰를 결정한다.
View 컨트롤러의 처리 결과 화면을 생성, JSP 또는 Velocity 템플릿 파일 등을 뷰로 사용한다.

출처 : 동덕여자대학교 소프트웨어시스템개발 수업

 

 

 

3. 개발 과정

step 1) DispatcherServlet 설정

: Client로부터 request를 전달받는 servlet 객체(front controller)

: web.xml 설정 

 

 

step 2) HandlerMapping 설정

: Request를 처리할 handler(controller and method) 선택

[디폴트] /WEB-INF/[name]-servlet.xml

 

 

Step 3) Controller 구현 및 설정

- Annotation 기반 controller

: @Controller (자동 bean scan 대상)

: @RequestMapping (사용자 정의 메소드를 특정 request URL에 대한 handler method로 지정)

 

 

 

step 4) ViewResolver 

: 논리적인 view 이름에 대해 물리적인 view 객체 생성

 

 

 

step 5) View 구현

: JSP 등을 사용하여 View page 작성

 

 

 

 

 

 

4.  Javacode 기반 설정

 

 

 

 

 

 

5. ContextLoaderListener

- Root container

 

 

 

 

 

6. HandleMapping

: Request를 처리할 handler(controller) 객체 선택

- RequestMappingHandler : @Controller and @RequestMapping 어노테이션 이용하여 handler 객체 선택

 

- URL matching pattern

* Ant pattern

? (한 개의 문자), * (0개 이상의 문자와 매칭), ** (0개 이상의 디렉토리와 매칭)

 

 

 

7. Controller 구현 : HTTP 전송 방식 지정

1) method 속성

 

 

 

 

2) @GetMapping, @PostMapping 이용

 

 

 

 

8. Request Param 추출 

 

1) HttpServletRequest 이용

 

 

 

2) @RequestParam

 

 

3) @PathVariable

 

 

3) @RequestHeader

4) @CookieValue

 

 

5) Servlet API

 

 

 

 

 

9. Command 객체를 통한 Form 입력 처리

: HTML Form 에 입력된 데이터를 자바빈 객체를 통해 입력 받음

 

- View 에서 command 객체 접근

 

- @ModelAttribute로 객체 이름 지정

 

- 여러 개

 

반응형
반응형

 

 

 

 

Spring Container의 bean 관리

- bean 객체의 생성, 의존 객체 주입 및 초기화, 객체 삭제 등 객체 life-cycle에 관련된 작업을 수행한다.

- 각 bean에 대해 callback method를 호출하여 실행함(호출의 주체가 '시스템')

* bean 클래스에 life-cycle 관련된 callback method가 구현된 경우, container가 적절한 시점에 메소드를 호출함

ex) BeanNameAware#setBeanName(String beanName), InitializingBean#afterPropertiesSet()

 

* 자체적으로 정의된 custom init/destroy method 호출

<bean>의 init-method, destroy-method 속성으로 지정된 메소드

@Bean의 initMethod, destroyMethod 속성으로 지정된 메소드

@PostConstruct, @PreDestroy가 적용된 메소드

 

 

 

전체 life-cyle process

 

 

ApplicationContext container의 수행 절차

 

 

 

 

 

Life-cycle 관련 interfaces 및 callback methods

- BeanNameAware

void setBeanName(String beanName) ; id/name 속성을 전달

- BeanFactoryAware

void setBeanFactory(BeanFactory factory) : 자신을 관리하는 beanFactory 객체를 전달

- ApplicationContextAware

void setApplicationContext(Application context) : 자신을 관리하는 applicationContext 객체를 전달

 

예시)

 

 

 

Custom init-method

- Bean 객체 생성 및 DI 수행 후에 호출되는 메소드

- Bean 객체를 삭제하기 전에 호출되는 메소드

 

 

 

- Spring interfaces

 

 

- <bean> @Bean 설정 

 

 

 

 

 

 

 

Bean Scoping

Spring container는 기본적으로 한 개의 bean instance만을 생성(singleton)

Scope 지정 방법 : <bean>의 scope 속성 또는 @Scope annotaion 사용

 

 

Singleton vs Prototype

 

 

 

@Scope annotation 사용 예

 

 

 

 

외부 설정 Property

설정 정보의 외부화

Spring에서 bean 설정에 사용되는 설정 값을 외부의 환경변수나 파일 등에 별도의 property로 저장하고 사용하는 방법

ex) 데이터베이스 구성 정보 등

 

외부에 정의된 property 이용 방법

1) PropertyPlaceholderConfigurer 

-> <context:property-placeholder />

2) Environment 및 PropertySource 이용

 

 

 

PropertyPlaceholderConfigurer 

객체를 통해 외부에 존재하는 property file을 읽어들임(loading)

 

 

XML 기반 설정

- PropertyPlaceholderConfigurer 타입의 객체를 bean으로 생성

- property file의 목록을 location 또는 locations 속성의 값으로 제공

- property file에 정의된 각 property는 ${property-name} 형식으로 참조

 

 

 

 

- 주의사항 : <context:pro...> 가 두 번 이상 사용될 경우 먼저 처리된 설정만 적용됨

- 해결방법

 

 

 

 

JavaConfig 기반 설정

@PropertySource, @PropertySources annotation 이용

 

 

 

Environment를 통한 property 이용

 

 

 

Bean에서 Environment 클래스 이용하는 방법

방법 1) EnvironmentAware interface 구현

 

 

 

방법 2) @Autowired 를 통한 Environment 객체 자동 주입

 

 

 

 

 

 

 

Message Source 

텍스트 메시지들을 프로그램 내에 직접 작성하지 않고 외부 property file에 저장 후 참조

 

Message bundle 정의 및 활용

 

 

 

ApplicationContext 가 위의 인터페이스를 상속하고 AbstractApplicationContext 클래스가 구현

 

 

 

 

 

 

Bean 객체에서 Message 참조 방법

방법 1) MessageSourceAware 인터페이스 구현

 

 

방법 2) ApplicationContextAware 인터페이스 구현 (MessageSourceAware 의 상위 클래스)

 

 

 

 

반응형

'Programming > Spring' 카테고리의 다른 글

06. Spring Boot  (0) 2021.05.27
05. Spring MVC  (0) 2021.04.18
03. Auto-wiring, Java code 기반 설정, annotation 기반 설정  (0) 2021.04.13
02. SpringDI / 생성자 * setter 방식 / SpEL  (0) 2021.04.06
01. Spring Framework 개요  (0) 2021.04.04
반응형

 

 

 

 

 

Auto-wiring

: DI를 명시적으로 설정하지 않아도 container가 bean의 타입이나 이름을 이용하여 DI를 자동으로 수행하는 기능

 

 

XML 기반 설정

예시)

 

- byName (setter-based injection)

: property와 같은 name(또는 id) 값을 갖는 bean을 찾아 주입한다.

 

 

- byType (setter-based injection)

: property와 같은 타입을 갖는 bean을 찾아 주입한다.

단, Instrument 객체가 하나만 존재할 경우에만 쓸 수 있다.

 

 

- Constructor (constructor-based injection)

: 생성자 호출 시, argument와 같은 타입을 갖는 bean을 찾아 전달한다.

단, 해당 객체가 유일하게 존재할 경우에만 쓸 수 있다.

 

 

 

 

 

 

Auto-wiring과 명시적 설정의 혼합

자동 설정을 이용하되, 일부 preperty에 대해 명시적으로 <property>나 <constructor-arg>를 이용해 DI 설정 가능하다.

주의) 명시적 설정이 자동 설정보다 우선적으로 적용된다.

 

 

 

 

 

주의할 점

- byName, byType 방식 : 주입 가능한 bean이 없을 경우, DI 수행을 안 함

- byType, constructor 방식 : 주입 가능한 bean이 여러 개일 경우, exception 발생

(NoUniqueBeanDefinitionException)

- constructor 방식 : 자동 주입에 사용 가능한 생성자가 여러 개일 경우 exception 발생

- Auto-wiring은 다양한 타입의 bean 객체들이 다수 존재하고, 특정 타입의 bean객체가 한 개씩만 존재할 때 효과적이다.

- 그러나 객체 간의 의존 관계를 명확히 파악하기 어렵고 부작용이 발생할 위험이 있다.

 

 

 

 

참고 : 부모 Bean을 통한 설정 재사용

Bean들 사이에 중복되는 설정이 많을 경우 추상 bean을 정의하고 그 설정을 재사용(상속)

- abstract : true값을 갖는 경우, 추상 bean 생성(객체 생성 불가)

 

예1)

 

예2)

 

 

 

 

 

Java Code 기반 설정

 

@Configuration, @Bean annotation 사용

@Configuration : 이 클래스를 Spring bean의 설정 정보로 사용한다.

@Bean : 이 메서드가 생성 및 반환하는 객체를 bean 객체로 등록한다. method 이름을 bean의 id로 사용한다.

         or name 속성을 통해 bean의 id를 지정 가능하다.

 

- 생성자 기반 의존 관계 설정 (DI)

 

 

- Setter-method 기반 의존 관계 설정 (DI)

 

 

Collection Wiring

: Collection(List, Set, Map, Properties, ...) 객체 생성 및 주입

 

 

주의! 생성되는 bean들은 기본적으로 singleton 객체이다.

같은 메서드를 여러 번 호출해도 객체는 내부적으로 한 번만 생성되고 호출된다.

 

 

 

Java code 기반 설정 사용 방법

AnnotationConfigApplicationContext class를 container로 사용한다.

 

 

여러 개의 JavaConfig 클래스 사용

방법 1 :@Autowired를 이용해 설정 클래스의 객체를 주입한다.

 

 

방법 2 : @Autowired를 통해 필요한 의존 객체들을 자동 주입한다.

 

방법 3 : 모든 설정 클래스를 파라미터로 전달

 

방법 4 : @import annotation를 이용한 설정정보 결합

 

 

 

 

 

 

Annotaion 기반 설정

 

 

 

- XML 설정을 해줘야 함 !!

 

 

 

@Required

: property에 대한 setter method 앞에 사용

 

 

 

 

@Autowired

- 생성자, property, method에 대해 적용 가능

: setter 뿐만 아니라 일반 메서드에도 적용 가능

- bean들 사이의 의존 관계를 type을 이용하여 자동 설정

* 만약 할당 가능한 타입의 bean 객체가 존재하지 않을 경우, NoSuchBeanDefinitionException

* 만약 하당 가능한 타입의 bean 객체가 여러 개일 경우, NoUniqueBeanDefinitionException

 

- required 속성

: 의존 객체 주입이 반드시 필요한지 여부를 나타낸다.

: required = false로 하면 할당가능한 bean이 존재하지 않더라도 exception을 발생시키지 않는다.

 

 

 

- XML 설정

 

 

 

- Java Code 기반 설정

 

 

 

Collection Type property

원소 타입의 모든 bean을 모아서 하나의 collection 객체를 생성 및 주입한다.

 

- 주의사항

1) autowired를 property에 직접 적용할 경우, setter method가 존재하지 않아도 DI가 실행된다.

2) @Autowired를 property나 setter method, 일반 method에 적용할 경우,

Default 생성자를 통해 객체가 생성되고, 의존 객체가 주입된다.

* Default 생성자가 없고 인자가 있는 생성자가 존재할 경우 exception 발생 !

 

 

 

@Nullable

: @Autowired + @Nullable 사용시 할당 가능한 Bean이 존재하지 않는 경우 null을 주입한다.

 

 

 

@Qualifier

자동 주입 가능한 bean이 여러 개일 때, 특정 bean에 대해 한정자를 붙이거나 특정 bean을 선택하기 위해 사용한다.

 

- XML 이용 시,

 

- Java Config 이용 시,

 

 

- Bean 클래스에서 정의 시,

 

 

 

 

 

@Value

int, boolean, float, String 등의 값을 전달함

 

 

 

@Resource

: @Autowired + @Qualifier

 

 

- 주의사항

: name 속성이 생략되면 property 이름을 사용한다.(autowiring by name)

만약 이름이 같은 bean을 찾지 못하면, autowiring by type으로 전환

만약 할당 가능한 bean이 없거나 여러 개이면 exception 발생 !

 

 

 

 

 

 

참고 : JSR - 330 Annotations

 

 

 

 

 

 

 

 

 

 

Bean Scan

Annotation을 이용한 자동 bean 탐색 및 등록

1) 특정 어노테이션이 붙은 클래스에 대해 자동으로 bean을 등록하는 기능

@Component, @Controller, @Service, @Repository, @Aspect, @Configuration

속성으로 bean의 id 지정 가능, 지정하지 않았다면 클래스 이름으로(첫글자소문자) 지정

 

2) XML 또는 JavaConfig 클래스에서 명시적인 Bean 설정 생략 가능하다.

 

예시)

 

 

XML 설정 방법

<context:component-scan />

 

 

 

JavaConfig 설정 방법 : @ComponentScan

 

 

참고) beanScan 범위 설정

include-filter : 포함시킬 클래스 

exclude-filter : 제외시킬 클래스

 

 

 

 

설정 방식의 장단점

XML

장점 : 클래스들과 설정 정보를 분리할 수 있고, 관심사의 분리

단점 : 값이 모두 String 타입이므로 type-safe 하지 않음(즉 오타가 있을 때 debugging의 어려움)

 

Annotation 기반 설정 + bean scan

장점 : Java code 설정하므로 type-safe하고, 적용이 빠름

단점 : 설정이 클래스들과 결합(분산)되어 관리나 관심사의 분리가 어려움

 

Java Code 기반 설정

장점 : 클래스들과 설정을 분리할 수 있고 관심사의 분리 가능, java code로 설정하므로 type-safe

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts