멀티캠퍼스

[2026.06.17] - TIL 53일차 Spring Bean 설정 심화 복습 정리

buckwheat 2026. 6. 18. 17:33

 

 

목차
1 오늘 학습 범위
2 p namespace
3 c namespace
4 p namespace와 c namespace 비교
5 Bean 참조 주입
6 직접 만든 BeanFactory
7 인터페이스 기반 객체 교체
8 lazy-init
9 autowire
10 외부 클래스 Bean 등록
11 상속 구조와 Bean 등록
12 오늘 학습한 핵심 정리

1 오늘 학습 범위

1) Spring03 test06 ~ test08

 

    (1) test06

    test06에서는 p namespace와 c namespace를 사용해 Bean 설정을 간단하게 작성하는 방법을 학습했다.

    기존의 property 태그와 constructor-arg 태그를 더 짧은 속성 형태로 표현할 수 있었다.

 

    (2) test07

    test07에서는 TV 인터페이스, LgTV, SamsungTV, 직접 만든 BeanFactory 구조를 통해 객체 생성 책임을 분리하는 흐름을 학습했다.

    이를 통해 Spring 컨테이너가 왜 필요한지 이해할 수 있었다.

 

    (3) test08

    test08에서는 lazy-init 속성을 통해 Bean의 생성 시점을 조절하는 방법을 학습했다.

    Bean이 컨테이너 생성 시점에 만들어지는지, getBean 호출 시점에 만들어지는지 확인할 수 있었다.

 

2) Spring04 test01 ~ test03

 

    (1) test01

    test01에서는 Product, TV, Phone 구조를 통해 상속 관계에 있는 클래스도 Bean으로 등록할 수 있음을 확인했다.

 

    (2) test02

    test02에서는 java.util.Date 같은 외부 클래스도 Bean으로 등록하고, 다른 Bean에 주입할 수 있음을 학습했다.

 

    (3) test03

    test03에서는 Food Bean 여러 개를 만들고, MyFood Bean이 해당 Food Bean들을 참조하는 구조를 실습했다.

    이를 통해 단순 값 주입, Bean 참조 주입, 자동 주입의 차이를 복습했다.


2 p namespace

1) p namespace의 의미

 

    (1) p namespace

    p namespace는 property를 짧게 작성하기 위한 XML 문법이다.

    setter 주입을 사용할 때 기존 property 태그 대신 사용할 수 있다.

 

    (2) 기존 방식

    원래 setter 주입은 property 태그를 사용한다.

   <property name="name" value="홍길동"/>

 

    (3) p namespace 방식

    p namespace를 사용하면 bean 태그 안에 속성처럼 작성할 수 있다.

   p:name="홍길동"

 

    (4) 핵심

    p namespace는 새로운 주입 방식이 아니다.

    기존 setter 주입을 더 짧게 표현하는 문법이다.

 

2) p namespace 사용 조건

 

    (1) setter 필요

    p namespace는 setter 주입이기 때문에 클래스 안에 setter 메소드가 있어야 한다.

    예를 들어 p:name을 사용하려면 setName 메소드가 있어야 한다.

 

    (2) 필드명 기준

    p:name에서 name은 필드명처럼 보이지만 실제로는 setter 메소드와 연결된다.

    Spring은 name이라는 이름을 보고 setName 메소드를 찾아 값을 넣는다.

 

3) p namespace 사용 예

 

    (1) 단순 값 주입

    문자열, 숫자 같은 값은 다음처럼 작성할 수 있다.

p:name="홍길동"
p:age="20"

 

    (2) Bean 참조 주입

    다른 Bean을 주입할 때는 -ref를 붙인다.

p:emp-ref="emp"

 

    (3) 의미

    p:emp-ref="emp"는 emp라는 id를 가진 Bean을 찾아 현재 Bean의 emp 속성에 넣겠다는 의미이다.


3 c namespace

1) c namespace의 의미

 

    (1) c namespace

    c namespace는 constructor를 짧게 작성하기 위한 XML 문법이다.

    생성자 주입을 사용할 때 기존 constructor-arg 태그 대신 사용할 수 있다.

 

    (2) 기존 방식

    원래 생성자 주입은 constructor-arg 태그를 사용한다.

<constructor-arg value="홍길동"/>

 

    (3) c namespace 방식

    c namespace를 사용하면 bean 태그 안에 속성처럼 작성할 수 있다.

c:name="홍길동"

 

    또는 생성자 매개변수 순서를 기준으로 작성할 수도 있다.

c:_0="홍길동"
c:_1="90"

 

    (4) 핵심

    c namespace도 새로운 주입 방식이 아니다.

    기존 생성자 주입을 더 짧게 표현하는 문법이다.

 

2) c namespace 사용 조건

 

    (1) 생성자 필요

    c namespace는 생성자 주입이므로 해당 값을 받을 수 있는 생성자가 클래스 안에 있어야 한다.

 

    (2) 매개변수 이름 또는 순서

    생성자의 매개변수 이름을 기준으로 값을 넣거나, index 순서를 기준으로 값을 넣을 수 있다.

    실습에서는 생성자에 맞춰 값을 전달하는 구조를 확인했다.

 

3) c namespace 사용 예

 

    (1) 단순 값 주입

    생성자로 단순 값을 넣을 때 다음처럼 작성할 수 있다.

c:name="홍길동"
c:salary="300"

 

    (2) Bean 참조 주입

    생성자로 다른 Bean을 넣을 때는 -ref를 붙인다.

c:emp-ref="emp"

 

    (3) 의미

    c:emp-ref="emp"는 emp라는 Bean을 생성자 매개변수로 전달하겠다는 의미이다.


4 p namespace와 c namespace 비교

1) 공통점

 

    (1) XML 간소화

    p namespace와 c namespace는 XML 설정을 짧게 작성하기 위한 문법이다.

    둘 다 Spring의 DI 설정을 간결하게 만든다.

 

    (2) value와 ref 사용 가능

    둘 다 단순 값을 넣을 수도 있고, 다른 Bean을 참조해서 넣을 수도 있다.

    단순 값은 일반 속성으로 작성하고, Bean 참조는 -ref를 붙인다.

 

2) 차이점

 

    (1) p namespace

    p namespace는 setter 주입이다.

    객체가 생성된 후 setter 메소드를 통해 값이 들어간다.

 

    (2) c namespace

    c namespace는 생성자 주입이다.

    객체가 생성되는 순간 생성자 매개변수로 값이 들어간다.

 

    (3) 선택 기준

    객체 생성 시 반드시 필요한 값이면 c namespace를 사용하는 것이 자연스럽다.

    객체 생성 후 변경 가능하거나 선택적인 값이면 p namespace를 사용할 수 있다.

 

3) 한눈에 비교

 

    (1) property 태그 대체

    p namespace는 property 태그를 대체한다.

 

    (2) constructor-arg 태그 대체

    c namespace는 constructor-arg 태그를 대체한다.

 

    (3) setter 필요 여부

    p namespace는 setter가 필요하다.

    c namespace는 해당 생성자가 필요하다.


5 Bean 참조 주입

1) 단순 값과 객체 참조

 

    (1) 단순 값

    이름, 가격, 점수, 부서명 같은 값은 단순 값이다.

    이런 값은 value 또는 p:name, c:name 같은 방식으로 주입한다.

 

    (2) 객체 참조

    어떤 객체 안에 다른 객체가 들어가야 하는 경우가 있다.

    예를 들어 MyFood 객체가 favoriteFood, unFavoriteFood라는 Food 객체를 가지는 경우이다.

 

    (3) ref

    다른 Bean 객체를 주입할 때는 ref를 사용한다.

    p namespace와 c namespace에서는 -ref를 붙여 표현한다.

 

2) Bean 참조 주입의 흐름

 

    (1) 먼저 참조될 Bean을 등록한다

    예를 들어 Food 객체를 favoriteFood라는 id로 등록한다.

 

    (2) 참조하는 Bean에서 ref로 연결한다

    MyFood 객체를 등록하면서 favoriteFood Bean을 ref로 연결한다.

 

    (3) Spring이 객체를 연결한다

    개발자가 직접 new Food()를 해서 MyFood에 넣는 것이 아니다.

    Spring 컨테이너가 Food Bean을 찾아 MyFood Bean에 넣어준다.

 

3) 실습에서의 의미

 

    (1) Food

    Food는 음식 이름과 가격 같은 단순 값을 가진 Bean이다.

 

    (2) MyFood

    MyFood는 Food 객체를 필드로 가지는 Bean이다.

 

    (3) 핵심

    Food에는 value로 단순 값을 넣고, MyFood에는 ref로 Food Bean을 연결한다.

    이 차이를 이해하면 Spring XML 설정을 읽기가 쉬워진다.


6 직접 만든 BeanFactory

1) 직접 만든 BeanFactory의 목적

 

    (1) 객체 생성 분리

    test07에서는 직접 BeanFactory 클래스를 만들어 객체 생성 책임을 main에서 분리했다.

    main이 직접 LgTV나 SamsungTV를 생성하지 않고, BeanFactory에게 객체 생성을 맡겼다.

 

    (2) Spring 컨테이너 이해를 위한 연습

    직접 만든 BeanFactory는 Spring 컨테이너의 원리를 단순하게 흉내 낸 구조이다.

    실제 Spring 컨테이너처럼 복잡한 기능은 없지만, 객체 생성을 외부에서 담당한다는 흐름을 이해하기 좋다.

 

2) 직접 만든 BeanFactory의 동작

 

    (1) 문자열 입력

    BeanFactory는 lg, samsung 같은 문자열을 받는다.

 

    (2) 객체 선택

    입력된 문자열에 따라 LgTV 또는 SamsungTV 객체를 생성한다.

 

    (3) 객체 반환

    생성된 객체를 TV 타입으로 반환한다.

 

3) 한계

 

    (1) 코드 수정 필요

    새로운 TV 클래스가 추가되면 BeanFactory 내부의 조건문을 수정해야 한다.

 

    (2) 유연성 부족

    객체 생성 기준이 코드 안에 박혀 있기 때문에 설정 파일만으로 객체를 바꾸기 어렵다.

 

    (3) Spring과의 차이

    Spring은 이런 객체 생성 정보를 XML이나 어노테이션으로 관리한다.

    그래서 Java 코드를 직접 수정하지 않고도 객체 생성과 연결 구조를 바꿀 수 있다.


7 인터페이스 기반 객체 교체

1) TV 인터페이스

 

    (1) 공통 기능 정의

    TV 인터페이스는 TV들이 공통으로 가져야 할 기능을 정의한다.

    LgTV와 SamsungTV는 TV 인터페이스를 구현한다.

 

    (2) 공통 타입

    LgTV와 SamsungTV는 서로 다른 클래스이지만 TV 타입으로 다룰 수 있다.

    이렇게 하면 사용하는 쪽에서는 구체적인 클래스보다 공통 타입에 의존하게 된다.

 

2) 인터페이스를 사용하는 이유

 

    (1) 구현체 교체

    TV 타입으로 받아두면 실제 객체를 LgTV에서 SamsungTV로 바꿔도 사용하는 코드는 크게 바뀌지 않는다.

 

    (2) 결합도 감소

    main 코드가 SamsungTV에 직접 의존하면 SamsungTV를 바꿀 때 main 코드도 수정될 가능성이 높다.

    하지만 TV 인터페이스에 의존하면 구체적인 구현체 변경에 덜 영향을 받는다.

 

    (3) Spring DI와 연결

    Spring에서는 인터페이스 타입에 실제 구현 Bean을 주입할 수 있다.

    이 구조는 나중에 Controller, Service, DAO 구조에서도 중요하게 사용된다.

 

3) 실습의 의미

 

    (1) 직접 new를 줄인다

    main 코드가 특정 구현 클래스를 직접 생성하지 않도록 한다.

 

    (2) 객체 선택을 외부로 뺀다

    어떤 구현체를 사용할지는 BeanFactory나 Spring 설정에서 결정한다.

 

    (3) 유지보수에 유리하다

    객체 교체가 쉬운 구조가 된다.


8 lazy-init

1) lazy-init의 의미

 

    (1) 생성 시점 조절

    lazy-init은 Bean의 생성 시점을 조절하는 설정이다.

 

    (2) 기본 생성 방식

    일반적으로 singleton Bean은 Spring 컨테이너가 시작될 때 미리 생성된다.

    그래서 getBean을 호출하지 않아도 생성자가 먼저 실행될 수 있다.

 

    (3) lazy-init="true"

    lazy-init="true"를 설정하면 컨테이너 시작 시점에는 Bean을 만들지 않는다.

    실제로 getBean을 호출해서 Bean이 필요해지는 순간 객체를 생성한다.

 

2) lazy-init을 사용하는 이유

 

    (1) 불필요한 객체 생성 방지

    프로그램 실행 중 사용하지 않을 수도 있는 Bean을 처음부터 만들 필요가 없다.

    필요한 시점까지 생성을 미룰 수 있다.

 

    (2) 생성 시점 확인

    생성자에 출력문이 있으면 lazy-init 설정에 따라 생성자 실행 시점이 달라지는 것을 확인할 수 있다.

 

3) 주의할 점

 

    (1) 오류 발견 시점이 늦어진다

    lazy-init이 true이면 컨테이너 시작 시점에는 Bean 생성 오류가 드러나지 않을 수 있다.

    실제 getBean을 호출할 때 오류가 발생할 수 있다.

 

    (2) 모든 Bean에 무조건 적용하는 것은 아니다

    자주 사용하는 핵심 Bean은 미리 생성하는 것이 나을 수 있다.

    사용 빈도가 낮거나 생성 비용이 큰 Bean에 선택적으로 적용하는 것이 좋다.


9 autowire

1) autowire의 의미

 

    (1) autowire

    autowire는 의존성 주입을 개발자가 직접 명시하지 않고, Spring이 자동으로 처리하도록 설정하는 기능이다.

    원래는 property나 constructor-arg를 사용해서 어떤 Bean을 주입할지 직접 작성해야 한다.

    하지만 autowire를 사용하면 Spring이 Bean의 이름이나 타입을 기준으로 알맞은 Bean을 찾아 자동으로 연결해준다.

 

    (2) 사용하는 이유

    XML에서 property나 constructor-arg를 계속 작성하면 설정 코드가 길어질 수 있다.

    autowire를 사용하면 반복되는 의존성 주입 설정을 줄일 수 있다.

 

    (3) 주의할 점

    autowire는 편리하지만, 어떤 Bean이 자동으로 연결되는지 한눈에 보이지 않을 수 있다.

    그래서 처음에는 property, constructor-arg, ref를 직접 작성하면서 의존 관계를 명확히 이해하는 것이 좋다.

 

2) autowire="default"

 

    (1) default

    default는 자동 주입을 사용하지 않는 기본값이다.

    즉, Spring이 알아서 의존성을 연결하지 않는다.

 

    (2) 의미

    개발자가 property나 constructor-arg를 사용해 어떤 값을 넣을지 직접 작성해야 한다.

 

3) autowire="byName"

 

    (1) byName

    byName은 setter 이름과 같은 Bean id를 찾아 주입하는 방식이다.

    정확히는 setter에서 사용하는 property 이름과 Bean의 id가 같으면 자동으로 연결된다.

 

    (2) 예시

    클래스에 setFavoriteFood()라는 setter가 있으면 Spring은 favoriteFood라는 id를 가진 Bean을 찾는다.

    해당 Bean이 있으면 자동으로 주입한다.

 

    (3) 핵심

    byName은 이름이 중요하다.

    필드명 또는 setter 기준 이름과 Bean id가 맞아야 자동 주입된다.

 

4) autowire="byType"

 

    (1) byType

    byType은 setter의 파라미터 타입과 같은 타입의 Bean을 찾아 주입하는 방식이다.

    이름이 아니라 자료형을 기준으로 Bean을 찾는다.

 

    (2) 예시

    setFavoriteFood(Food food)라는 setter가 있으면 Spring은 Food 타입의 Bean을 찾는다.

    Food 타입 Bean이 하나만 있으면 자동으로 주입된다.

 

    (3) 주의할 점

    같은 타입의 Bean이 2개 이상 있으면 Spring이 어떤 Bean을 넣어야 할지 판단하기 어렵다.

    예를 들어 Food 타입 Bean이 favoriteFood, unFavoriteFood 두 개라면 byType만으로는 구분이 안 될 수 있다.

 

5) autowire="constructor"

 

    (1) constructor

    constructor는 생성자의 파라미터 타입과 같은 타입의 Bean을 찾아 생성자에 자동으로 주입하는 방식이다.

    setter가 아니라 생성자를 기준으로 의존성을 주입한다.

 

    (2) 예시

    MyFood 생성자가 Food 타입을 매개변수로 받는다면 Spring은 Food 타입 Bean을 찾아 생성자로 넣어준다.

 

    (3) 같은 타입 Bean이 여러 개일 때

    같은 타입의 Bean이 2개 이상 있으면 Spring은 생성자 파라미터 이름을 기준으로 구분하려고 한다.

    하지만 상황에 따라 충돌이 날 수 있으므로, 이런 경우에는 직접 constructor-arg나 ref로 명시하는 것이 더 안전하다.

 

6) autowire 방식 비교

 

    (1) default

    자동 주입을 하지 않는다.

    개발자가 직접 property나 constructor-arg로 의존성을 명시한다.

 

    (2) byName

    Bean id와 property 이름을 기준으로 자동 주입한다.

    이름이 정확히 맞아야 한다.

 

    (3) byType

    Bean의 타입을 기준으로 자동 주입한다.

    같은 타입의 Bean이 하나만 있을 때 안전하다.

 

    (4) constructor

    생성자의 파라미터 타입을 기준으로 자동 주입한다.

    생성자 주입을 자동으로 처리하는 방식이다.

 

7) 실습에서의 의미

 

    (1) 기존 방식과의 차이

    기존에는 MyFood 안에 Food Bean을 넣으려면 property ref 또는 constructor-arg ref를 직접 작성해야 했다.

    autowire를 사용하면 Spring이 이름이나 타입을 기준으로 Food Bean을 찾아 자동으로 넣어줄 수 있다.

 

    (2) 핵심 이해

    autowire는 DI를 자동화하는 설정이다.

    DI 자체가 사라지는 것이 아니라, 의존성을 연결하는 작업을 개발자가 직접 쓰느냐 Spring이 자동으로 찾느냐의 차이이다.

 

    (3) 이후 학습과의 연결

    XML 기반 설정에서는 autowire 속성을 사용할 수 있다.

    이후 어노테이션 기반 Spring에서는 @Autowired를 사용해 비슷한 자동 주입 흐름을 더 자주 사용하게 된다.


10 외부 클래스 Bean 등록

1) 외부 클래스의 의미

 

    (1) 외부 클래스

    외부 클래스는 내가 직접 만든 클래스가 아니라 Java나 외부 라이브러리에서 제공하는 클래스이다.

    java.util.Date 같은 클래스가 대표적인 예이다.

 

    (2) Bean 등록 가능

    Spring은 내가 만든 클래스뿐만 아니라 외부 클래스도 Bean으로 등록할 수 있다.

    class 속성에 해당 클래스의 전체 경로를 작성하면 된다.

 

2) Date Bean 실습

 

    (1) Date 객체 등록

    java.util.Date를 Bean으로 등록했다.

    이를 통해 Spring이 Java 기본 라이브러리 클래스도 관리할 수 있음을 확인했다.

 

    (2) property 설정

    Date 객체에 필요한 값을 property로 설정했다.

    setter가 있는 외부 클래스라면 Spring이 setter를 통해 값을 넣을 수 있다.

 

    (3) 다른 Bean에 주입

    Date Bean을 BeanTest 같은 다른 Bean의 생성자에 ref로 주입했다.

    즉, 외부 클래스 Bean도 다른 Bean과 연결될 수 있다.


11 상속 구조와 Bean 등록

1) 상속 구조

 

    (1) 부모 클래스

    부모 클래스는 여러 클래스가 공통으로 가지는 필드와 기능을 모아둔 클래스이다.

    Product는 TV와 Phone의 공통 정보가 될 수 있다.

 

    (2) 자식 클래스

    자식 클래스는 부모 클래스의 필드와 메소드를 물려받고, 자신만의 기능을 추가할 수 있다.

    TV와 Phone은 Product를 상속받아 구체적인 제품 객체가 된다.

 

2) Spring에서 상속 클래스 사용

 

    (1) 자식 클래스 Bean 등록

    상속 관계에 있는 자식 클래스도 bean 태그로 등록할 수 있다.

    Spring은 class 속성에 적힌 실제 클래스를 기준으로 객체를 생성한다.

 

    (2) 부모 타입으로 받기

    자식 객체는 부모 타입으로 받을 수 있다.

    예를 들어 TV와 Phone 객체를 Product 타입으로 다룰 수 있다.

 

    (3) 의미

    공통 부모 타입으로 여러 자식 객체를 다룰 수 있으면 코드가 더 유연해진다.

    이것은 인터페이스를 사용하는 이유와도 비슷하게, 구체적인 클래스 의존도를 줄이는 데 도움이 된다.


12 오늘 학습한 핵심 정리

1) p namespace

 

    (1) setter 주입을 짧게 쓰는 문법이다.

    (2) property 태그를 대신한다.

    (3) setter 메소드가 있어야 한다.

    (4) 다른 Bean을 넣을 때는 p:필드명-ref를 사용한다.

 

2) c namespace

 

    (1) 생성자 주입을 짧게 쓰는 문법이다.

    (2) constructor-arg 태그를 대신한다.

    (3) 해당 값을 받을 생성자가 있어야 한다.

    (4) 다른 Bean을 넣을 때는 c:필드명-ref를 사용한다.

 

3) Bean 참조 주입

 

    (1) 단순 값은 value를 사용한다.

    (2) 다른 Bean 객체는 ref를 사용한다.

    (3) 객체 안에 객체가 필요한 경우 Spring이 대신 연결해준다.

    (4) 이 구조가 DI의 실제 사용 모습이다.

 

4) 직접 만든 BeanFactory

 

    (1) 객체 생성을 main에서 분리하는 연습이다.

    (2) 문자열에 따라 다른 객체를 생성해서 반환한다.

    (3) Spring 컨테이너가 필요한 이유를 이해하기 위한 단계이다.

    (4) 실제 Spring BeanFactory는 Bean 생성, 조회, 생명주기 관리를 담당한다.

 

5) 인터페이스

 

    (1) 공통 기능을 약속하는 타입이다.

    (2) 여러 구현체를 하나의 타입으로 다룰 수 있다.

    (3) 구현 클래스에 대한 직접 의존을 줄일 수 있다.

    (4) Spring DI와 함께 사용하면 객체 교체가 쉬워진다.

 

6) lazy-init

 

    (1) Bean 생성 시점을 늦추는 설정이다.

    (2) true이면 getBean 호출 시점에 Bean이 생성된다.

    (3) 불필요한 객체 생성을 줄일 수 있다.

    (4) 대신 오류 발견 시점이 늦어질 수 있다.

 

7) autowire

 

    (1) 의존성 주입을 Spring이 자동으로 처리하게 하는 설정이다.

    (2) default는 자동 주입을 하지 않는다.

    (3) byName은 Bean id와 property 이름을 기준으로 주입한다.

    (4) byType은 Bean 타입을 기준으로 주입한다.

    (5) constructor는 생성자 파라미터 타입을 기준으로 주입한다.

    (6) 같은 타입 Bean이 여러 개일 때는 충돌이 날 수 있으므로 직접 명시하는 방식이 더 안전할 수 있다.

 

8) 외부 클래스 Bean 등록

 

    (1) java.util.Date 같은 외부 클래스도 Bean으로 등록할 수 있다.

    (2) setter나 생성자가 있으면 값을 주입할 수 있다.

    (3) 외부 클래스 Bean도 다른 Bean에 ref로 연결할 수 있다.

 

9) 상속 구조 Bean 등록

 

    (1) 부모 클래스를 상속한 자식 클래스도 Bean으로 등록할 수 있다.

    (2) 자식 객체를 부모 타입으로 다룰 수 있다.

    (3) 공통 타입을 사용하면 코드가 더 유연해진다.

 

10) 오늘 배운 한 문장 정리

 

    Spring은 XML 설정을 통해 객체를 생성하고, 값을 주입하고, 객체끼리 연결하며, 필요에 따라 생성 시점과 자동 주입 방식까지 조절할 수 있다.

 

    오늘 학습은 단순히 Bean 등록하는 단계를 넘어서, Spring 객체 관계를 유연하게 관리하는 방법을 복습한 과정이었다.