[Spring 기본] Bean Scope

2022. 10. 19. 17:36·Spring/Spring 기본
728x90
반응형

우리는 지금까지 스프링 빈이 스프링 컨테이너의 시작과 함께 생성되어서 스프링 컨테이너가 종료될 때까지 유지된다고 배웠습니다. 이는 스프링 빈들이 기본적으로 싱글톤 객체로 형성되어 관리되기 때문입니다. 여기서 Bean Scope 의 개념에 대해서 살펴볼 필요가 있습니다. Bean Scope 란 말 그대로 빈이 존재할 수 있는 범위를 말합니다. 

 

우선 지정해줄 수 있는 Bean 들의 Scope 종류에 대해서 살펴보겠습니다. (물론 기본은 Singleton 이며, 특수한 경우를 제외하고는 모두 싱글톤으로 제어해주는게 맞습니다)

 

Singleton : 가장 긴 생명주기를 가진 기본 스코프. IOC 컨테이너에서 관리하며, 컨테이너의 시작과 함께 종료까지 유지된다
Prototype : IOC 컨테이너에서는 Bean 의 생성과 의존관계 주입까지만 처리 후 Bean을 요청한 Client에 반환만 해준다. 더 이상은 IOC 컨테이너에서 관리하지 않는다
Request : Requset가 들어오고 Response가 나갈 때까지 IOC 컨테이너에서 관리해준다
Session : Session 이 형성되고 종료될 때까지 유지된다. 
Application : Servlet Context 의 범위에 있어서 유지된다.

 

Request, Session, Application 은 웹 관련된 Scope로 구분지어줍니다. Singleton 외로 Prototype, Request Scope 들이 그나마 사용된다고 할 수 있으며, Session, Application Scope 들은 크게 사용할 일이 없다고 보셔되 됩니다. 하지만 물론 알아두는게 좋겠죠? (특히 여기서 등장하는 용어들 중 Session, Servlet Context 등이 뭐지 싶으시다면, 반드시 이해하고 넘어가셔야 합니다.)

 

 

Prototype Scope

 

 

[빈 스코프 - 프로토타입 스코프 강의 그림들 참고]

 

> 기억 : Singleton 빈은 항상 같은 인스턴스ㅇ의 Spring Bean 을 반환하게 되어 있다. (반면에 Prototype 은 항상 새로운 객체를 만들어서 반환을 해주게 된다. Container 에서 관리를 안하기 때문) 

 

 

**** Prototype

1:25 그림

 

앱이 처음 시작될 때, Spring Container 는 PrototypeBean01 에 대해서 객체를 생성 및 싱글톤 등록을 진행하지 않습니다. 그리고 추후 A의 요청이 진행되는 중 해당 Bean 을 요청하게 되면, 그 때 PrototypeBean 을 생성하고 DI를 진행합니다. 그리고 그 요청이 종료되면 해당 Bean 을 없애고, 더 이상 관리를 하지 않습니다. 동일하게, B가 요청을 하면, C가 요청을 하면 각각 작업을 해주게 됩니다. 즉, 어떠한 요청이든 항상 새로운 객체를 사용하게 됩니다.

 

가장 중요한 점은, Spring Container 는 여기서 빈을 생성하고, 의존관계 주입, 초기화 까지만 담당한다는 것입니다. 그 이후의 책임은 받은 클라이언트에게 있기 때문에, 그 클라이언트가 종료를 담당해야 합니다. 따라서, 서버 입장에서 @PreDestroy 같은 것도 실행시키지 않습니다. 종료를 컨테이너에서 관리하지 않기 때문입니다.

 

 

************ 싱글톤 빈, 프로토 ㅏ입 빈과 함께 사용시 문제점. 

 

그렇다면 이 Prototype Bean 을 같이 사용하게 될 경우, 어떤 점들을 주의해야 할까요? 다음과 같은 Prototype Bean 이 있다고 가정해봅시다.

 

[시작시 그림]

 

@Scope("prototype")
static class PrototypeBean{
    private int cnt = 0;

    public void addCnt(){
        this.cnt ++;
    }
}

각각 프로토 타입 빈을 객체 한명씩 요청하고, addCnt 를 수행하면 각자 반환값은 1이 됩니다. 해당 빈은 한 요청당 한번 쓰고 버리기 때문입니다. (참고로, 그렇다면 싱글톤 빈도 뭐가 요청당 따로 수행하지 않나? 하시는 분들은 싱글톤 빈 생성시 주의사항을 한번 다시 읽고 오시면 좋을 것 같습니다)

 

 

[5분 17초 대역 그림]

 

 

 위 그림처럼, client Bean 이라는 싱글톤 빈이 있는데, 여기서 의존관계 주입을 통해 Prototype Bean 을 주입받을 것입니다. 일단요청대로 Prototype Bean 은 빈을 생성해서 Client Bean 에게 반환을 해주게 됩니다. 자, 말씀드렸듯이 Spring Container 에서는 이를 절대 관리하지 않고, 이제 관리 대상은 ClientBean 이게 되고, Client Bean 은 클래스로서 내부 필드에 프로토타입 빈을 보관합니다.

 

static class ClientBean{

    private final PrototypeBean prototypeBean;

    @Autowired
    public ClientBean(PrototypeBean prototypeBean) {
        this.prototypeBean = prototypeBean;
    }

    public int logic(){
        prototypeBean.addCnt();
        return prototypeBean.getCnt();
    }
}

 

자 이제 ClientBean 을 통한 로직을 수행하라는 요청이 날라옵니다. Request 는 Client Bean 이 대상이므로, 관리중인 Prototype Bean 의 addCnt 를 수행하라고 하고, getCnt 를 통해서 Cnt 값을 반환받습니다. 당연히 Client A 는 1을 받게 되겠죠? 

 

문제는 다음입니다. 동일한 Request 가 또 날라옵니다. 똑같이 로직을 수행해서 addCnt, getCnt 를 하게 되는데, 이 때의 Cnt 반환값은 2가 됩니다. 읽으시면서 왜 그런지 당연히 이해가 되셨을 겁니다. 

 

Clien Bean 이 내부에 가지고 있는 Prototype Bean 은 옛날에 이미 주입이 끝난 빈으로, 그 빈을 계속 쓰게 됩니다. 일반 Prototype Bean 처럼 사용 할 때마다 새로 생성되는게 아니기 때문에 1을 반환하지 않습니다. 어디서 본 듯한 패턴이죠? 즉, 싱글톤 빈과 아무런 차이가 없게 됩니다. 관리 중인 대상이 Spring Container 가 아니라 Client Bean 일 뿐입니다.

 

@Test
@DisplayName("Client Bean이 Prototype Bean 을 주입받으면, 상태를 유지하며 관리한다")
void test2(){

    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
    
    ClientBean bean1 = ac.getBean(ClientBean.class);
    int cnt1 = bean1.logic();
    Assertions.assertThat(cnt1).isSameAs(1);

    ClientBean bean2 = ac.getBean(ClientBean.class);
    int cnt2 = bean2.logic();
    Assertions.assertThat(cnt2).isEqualTo(2);

}

 

ClientBean bean2 가 Bean 을 가지고 왔을 때 Prototype Bean 을 사용하는 이유는 아마 Prototype의 객체, 즉 매번 새로 생성되는 객체를 반환받길 원했을 것입니다. 즉, logic() 을 수행 후 1의 cnt 값을 반환하길 원했을 것입니다. 하지만, ClientBean 이 관리 대상이 되어버렸기 때문에 상태를 유지시키게 되어 2를 반환받게 되는 문제가 발생하게 됩니다.

 

static class ClientBean{

    @Autowired private ApplicationContext ac;

    public int logic(){
    	PrototypeBean pb = ac.getBean(PrototypeBean.class);
        prototypeBean.addCnt();
        return prototypeBean.getCnt();
    }
}

 

해당 문제를 해결하려면 단순하게 위처럼 ApplicationContext 를 Bean 화해서 주입시켜도 됩니다. 사용할 때마다 새로 가져오는 것이지요. 하지만 그건 너무 스프링 종속적인 코드 (Container 를 직접 요청) 가 되고, 단위 테스트도 어려워지게 됩니다 (다양한 Bean Test 가 어려워집니다). 참고로, 위 코드와 같이 DI 를 받는 것이 아니라,  소스 코드 내에서 직접 컨테이너에서 관리중인 Bean 을 찾는 것을 Dependency Lookup (DL) 이라고 합니다. 

 

그렇다면 이렇게 싱글톤, 프로토타입을 병행해서 사용할 경우, 어떻게 해야 할까요?

 

 

ObjectProvider

 

 

특수한 케이스가 아니라면 실질적으로 위와 같이 제어할 일은 거의 없겠지만, Prototype Bean 을 활용해야하고 싱글톤 빈에서 이를 활용해야하는 케이스가 있다면,  Provider 들을 통해서 해결할 수 있습니다.

 

static class ClientBean {

        @Autowired
        private ObjectProvider<PrototypeBean> prototypeBeansProvider;

        public int logic() {
            PrototypeBean prototypeBean = prototypeBeansProvider.getObject();
            prototypeBean.addCnt();
            return prototypeBean.getCnt();
        }
}

 

ObjectProvider 는 Spring 에서 제공해주는 Provider 로, 일종의 의존성을 대신해서 수행해주는 역할을 한다고 볼 수 있습니다. 싱글톤 Bean 인 ClientBean 에서 위와 같이 사용한다면, ClientBean 내에서도 필요 logic 을 수행할 때 PrototypeBean 을 그 필요한 때에 해당 객체를 생성해서 반환해주는 역할을 합니다. ObjectProvider 는 실용성이 있으나, Spring 의존성이 상당히 크다고 볼 수 있기 때문에, Java 표준 Provider 를 사용하는 것을 권장하기도 합니다.

 

 

JSR-330 Provider 

 

gradle 파일에 다음과 같은 Library 를 추가해준 후, 기존 클래스를 다음과 같이 수정해줍니다

implementation 'javax.inject:javax.inject:1'

 

static class ClientBean {

    @Autowired
    private Provider<PrototypeBean> prototypeBeanProvider;

    public int logic() {
        PrototypeBean prototypeBean = prototypeBeanProvider.get();
        prototypeBean.addCnt();
        return prototypeBean.getCnt();
    }
}

 

ObjectProvider 와 똑같이, JSR-Provider 의 get() 함수를 호출하면 내부적으로 Spring Container 를 통해서 해당 빈을 찾아서 반환해 줌으로써 항상 새로운 프로토 타입 빈이 생성되는 것을 확인할 수 있습니다 (수행 결과 자체는 동일합니다). Java 표준 Provider 는 문서에 들어가보면 Injector 라는 표현을 사용합니다. 즉, 스프링에 종속되지 않고 어떤 컨테이너를 사용하든지, 동일한 수행을 할 수 있다는 점에서 차이가 있다고 보시면 될 것 같습니다 (그렇게 중요한 부분 아니니, 그냥 이렇게 하는구나 하면 되는 것 같습니다..)

 

실무에서는 사실 Prototype 을 직접적으로 사용하는 경우는 매우 드물다고 합니다. 왜냐하면 보통 필요한 객체를 그 때 그 때 그냥 생성해서 사용해도 되기 때문입니다. 혹시 남의 코드를 보게 될 때 이게 뭐였지 할 때를 위해 Prototype Scope에 대해서 알아만 두면 될 것 같습니다. 

 

저 같은 경우 회사에서 사내 SSO 자동 로그인 시스템을 구축해야 할 일이 있었는데, 정확하진 않았지만 다음과 같은 근거들을 토대로 Prototype Bean 을 사용해서 구현을 하였습니다.

 

1. 사내 SSO API 제공 하는 쪽에서 로그인을 처리하는 객체의 초기화 등을 통해서 제공해주는 방식이였음 (SSO Controller 에서 DIP 를 지키기 위해서 SSO 처리 빈을 만들어야 겠다고 판단)
2. 내부적으로는 SSO 를 통해서 받은 DB 를 사용하지 않고, SSO 를 통해서 받은 사내 ID 를 통해서 웹 시스템이 돌아갔기 때문에, SSO 를 위해 사용되었던 것들이 다 관리되고 있을 필요가 없었음
3. 초기화 및 파기에 용이, 요청별로 다른 URL 생성 (요청 유저의 사내 정보에 따른) 이 필요했어서, 통합적으로 보았을 때 Prototype Bean 을 사용해봐도 되겠다고 판단함.

 

 

 

Web Scope  (Request Scope)

 - (Web Scope 는 Spring Boot Web 패키지가 Gradle Import 되어야 활용 가능합니다) 

 

웹 스코프도 Spring 에서 제공하는 Bean Type 중 하나로, 싱글톤과 마찬가지로 앱 종료시점까지 컨테이너가 관리를 해주긴  합니다 (다만, 일단 싱글톤은 아닙니다). 하지만 Prototype 과 마찬가지로 각각ㄱ의 요청마다 별도의 Bean Instance 가 생성되어서 사용되는데, 바로 Http 요청 하나가 들어오고 나갈때까지 유지되는 Scope 입니다. 즉, Singleton 적인 측면과 Prototype 적인 측면이 모두 있는 Scope 를 말합니다.

 

[Web Scope 그림]

 

위 그림처럼 Clien A 가 요청을 전송한다고 합시다. 해당 요청은 필터들을 통과하여 Controller 에 들어올 것이고, Controller 는 싱글톤으로 관리되고 있는 Bean Instance 일 것입니다. 이 때, 해당 Controller 에서 자신 요청 전용으로 Request Scope Bean A를 형성할 수 있습니다. 동일한 Controller 로 다른 종류의 요청이 발생하면 같은 Bean 클래스로부터 다른 Bean B를 따로 발급받게 되는 것입니다. (한 요청 내에서는 또 요청하면 같은 Bean 을 가져옵니다) 

 

여기서 Prototype Bean 과의 차이점을 확인할 수 있는데, 바로 같은 요청 내에서 또 해당 Bean 을 요청하게 되면, Controller 때 주입시켜줬던 똑같은 Bean 을 반환해준다는 점입니다. Prototype 은 요청할 때마다 새 Bean 을 반환하지만, Web Scope Bean 은 해당 요청 내에서는 동일한 객체를 유지시키고, 그 이후에는 파기됩니다.

 

Web Scope 에 대해 더 자세히 살펴보기 위해 다음과 같은 예제를 살펴보겠습니다.

 

@Component
@Scope(value = "request")
public class MyLogger {

    private String uuid;
    private String requestUrl;

    public void setRequestUrl(String requestUrl){
        this.requestUrl =  requestUrl;
    }

    public void log(String msg) {
        System.out.println("[" + uuid + "]" + "[" + requestUrl + "] " + msg);
    }

    @PostConstruct
    public void postConstruct() { // 고객 요청이 들어올 때 bean 생성하기에 앞서 uuid 를 박아둠
        uuid = UUID.randomUUID().toString();
        System.out.println("["+ uuid + "] request scope created: " + this);
    }

    @PreDestroy
    public void close(){
        System.out.println("[" + uuid + "] has been destroyed: " + this);
    }
}

 

특수 요청에 따른 요청을 분석하기 위한 로그를 서버에 남기기 위해 출력한다고 가정해보고, 다음과 같은 Sample Bean 을 만들었습니다. Bean 이 생성될 시점에 UUID 를 랜덤으로 생성해 주입을 시키고, 매 요청마다 별개로 관리될 수 있도록 @Scope("request") 로 지정해주었습니다. 참고로 requestUrl 은 논리적으로 Bean 생성 시점에 알 수 있는 정보가 아니므로, 요청이 오면 그 때 해당 Url 에 맞춰 주입할 수 있도록 setter injection 방식을 선택하였습니다.

 

해당 Logger 를 통해서 요청을 분석할 Service 와 Controller 를 다음과 같이 생성해주어서, Request Scope 에 대한 Test를 해보려 합니다. 

 

@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logService;
    private final MyLogger logger;

    @RequestMapping("log-demo")
    @ResponseBody
    public String logDemo(HttpServletRequest request) {

        logger.setRequestUrl(request.getRequestURL().toString());
        logger.log("Received In Controller");

        logService.logic("TESTING");

        return "OK";
    }
}

 

@Service
public class LogDemoService {

    private final MyLogger myLogger;

    public LogDemoService(MyLogger myLogger) {
        this.myLogger = myLogger;
    }
    public void logic(String id) {
        myLogger.log("Service received: " + id);
    }
}

 

실행을 해보면, 다음과 같은 에러가 발생해야 정상입니다. 

 

...
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? ... 
...

 

위아래로 쭉 읽어보면, Controller 와 Service 모두 Bean 생성을 실패했다고 합니다. 여기서 포스트를 내리시기 전에 왜 이런 오류가 발생했을까를 생각해본다면 정말 좋은 공부입니다. 지금까지 배운 내용으로 알 수 있는 내용입니다. 실무에서는 별의 별 에러를 다 겪고 발생하자마자 보통 구글 검색 조지기 때문에, 공부할 때라도 이런 에러가 왜 났을까를 생각하는게 진짜 좋은 공부인 것 같습니다. (저는 조금 생각하다가 "아, 더 들어야 알 수 있는 건가보다" 하면서 들었다가 후회했습니다)

 

..... 생각해봅시다

 

 

 

바로 MyLogger 가 아직 Bean 생성이 되지 않았기 때문입니다. 지금은 앱 생성 시점으로, Controller 와 Service 모두 생성자 주입을 받고 Bean 등록이 되어야 하는데, 현재 MyLogger.class 를 구현 객체로 의존하고 있습니다. 하지만 MyLogger는 Bean 등록이 App 생성 시점에 등록되는 것이 아닙니다. Request 가 들어와야 Container 에서 Bean 등록을 하게되며,   Request 가 유지되는 동안 관리를 해주고, Request 가 끝나면 Container 가 해당 Bean 을 폐기시키는 과정을 거칩니다. 현재 Request 가 들어오지도 않은 상태에서 Request Scope 빈을 주입시키려 하니까 Spring Container 에 없는 Bean 을 주입시키려 했기 때문에, 당연히 Fail 날 수 밖에 없습니다. 

 

그렇다면 어떻게 사용해야 할까요? 

 

 

1. 위에서 배운 ObjectProvider 사용 

 

ObjectProvider Library 를 사용하면 해당 Bean 이 필요할 때 등록을 해주게 됩니다. 

 

 

2. Proxy 사용

 

위에 까지 해봤을 때, 저는 의문점이 들었습니다. Provider 를 사용하면 "getObject() 를 하는 시점에 소스코드들을 훑어서 해당 Bean Class에 대한 bean 을 생성시켜 Container 에 등록시킨다" 라고 이해를 했습니다. 하지만 Object Provider 가 필요 시점에 소스코드들을 쭉 훑어서 해당 Bean Class 를 반환해준다고 생각하니, 이미 Component Scan 으로 패키지를 뒤졌는데 필요 시점에 또 훑지 말고, "그냥 싱글톤 빈에 Web Scope 를 주입할 때는 얘는 Request Scope 니까 나중에 주입된다"라고 등록해 놓을 수는 없는걸까? 라는 의문점이 들었습니다. 

 

바로 다음 내용에서 의문점이 해결이 되었는데, Scope Proxy 를 사용하는 것이였습니다. 기존 MyLogger.class 에 다음과 같이 추가하면 해당 클래스는 Request Scope로, Proxy 관리가 필요하다고 등록이 됩니다. 

 

@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class MyLogger {

    private String uuid;
    private String requestUrl;
    ...
}

 

그렇게 되면 기존 클래스를 ObjectProvider 없는 원래상태로 원복시킬 수 있습니다. 

 

@Controller
@RequiredArgsConstructor
public class LogDemoController {

    private final LogDemoService logService;
    private final MyLogger logger;
//    private final ObjectProvider<MyLogger> myLoggerProvider;
    ...
}

 

@Service
@RequiredArgsConstructor
public class LogDemoService {

    private final MyLogger myLogger;
    //private final ObjectProvider<MyLogger> myLoggerProvider;

    ....
}

 

Proxy 를 통해서 작동시킬 수 있는 이유는 다음과 같습니다. 

 

 

[프록시 강의 그림]

 

 

Proxy 클래스로 등록이 된다면, 해당 클래스는 CGLIB라는 바이트 코드 라이브러리를 통해서 가짜 프록시 객체를 만들어서 필요한 Bean 들에게 주입을 시켜놓게 됩니다. 즉, 가짜 Web Scope Bean 객체를 만들어서 이 객체를 Client 에 주입시켜 두는 원리로 보면 될 것 같습니다 (사실 프록시의 원리가 다 이런 것 같지 않나요?)

 

이 가짜 프록시는 요청이 들어오면 그 때 내부에서 진짜 Bean 을 요청하는 위임 로직이 들어있습니다. 따라서 Controller 클래스와 Service 클래스가 둘다 MyLogger.class 를 주입 받는 시점에는 가짜 객체를, 그리고 각자 자기만 사용할 전용 MyLogger.class 가짜 객체를 주입받게 됩니다. 그리고 각 클래스에서 logger.logic() 을 호출한다면, 이 역시 가짜 메소드를 호출하는 것입니다. 

 

그리고 실제 Request 가 들어오면 등록되어 있던 프록시 MyLogger 가 진짜 MyLogger.class Bean 을 생성하고, 이를 Bean Container 에 등록하게 됩니다. 클라이언트 입장에서는 이 My Logger 가 진짜인지 가짜인지 모르고 관리를 해주고 있는 상태입니다. Proxy 객체는 실 객체를 어떻게 가져올 수 있는지 알고 있고, 사용시점에 실 객체를 만들어줘서 사용하는 클라이언트에 주입시켜주므로, 다형성의 원리도 잘 지킨다고 볼 수 있습니다.

 

지금까지 Bean 의 Scope 종류에 대해서 살펴보았습니다. 사실 Provider 든, Proxy 든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점입니다. 이런 것이 DI 컨테이너의 큰 장점입니다. 

 

이런 다양한 빈들은 백그라운드에서 앱의 기능들을 보조해주기 위한 기능들로 많이 사용되나, 비즈니스 코드 구성에는 잘 사용되지 않습니다. (제가 사용했던 SSO 통신 담당 Bean, 실제로 쓴 예제 Logger 같은 Bean 들도 실제로는 Scope 범위를 사용하기도 합니다)

 

 

 

아우.. 어려워 .. 저도 또 읽고 찾아보고 하면서 더 공부해야겠습니다 ...

 

 

 

포스트 요약

 

  • 빈은 관리되는 범위에 따라 Scope 범위가 나뉘는데, 그 종류로는 Singleton, Prototype, Request (+Session,  Application) Scope 가 있다
  • Prototype 은 매 요청마다 다른 Bean 을 반환하며, IOC Container 에서 생성, 의존관계 주입, 초기화까지만 담당하고, 이후는 (종료) 사용하는 Client 객체에게 위임한다
  • Singleton Bean 내에서 Prototype Bean 을 사용할 때는 Provider 등을 사용하여 Prototype Bean 의 본 역할을 수행할 수 있도록 보조해줘야 한다
  • Web Scope 중 Request Scope 는 요청을 수행하는 과정에서만 IOC에서 관리해주는 반반의 성격을 가진 Scope이다
  • 일반 Bean 들과는 다르게 앱 실행 시점에 IOC Container 에 등록되는 것이 아니고 요청이 들어와야 Bean 생성, 의존성 주입 및 초기화가 이루어지기 때문에, Provider 혹은 Proxy 지정을 통해 앱 실행을 보조해줘야 한다 
  • 비즈니스 로직 구성에서는 많이 쓰이진 않지만, 실제로 여러 부가 기능들을 보조하는 Bean 들은 사용해주기도 한다. IOC Container 의 부하를 줄이기 위해서이다

 

 

 

출처

 

 

[스프링 기본]으로 엮인 모든 포스트들은 교육 사이트 인프런의 지식공유자이신 김영한님의 [스프링 핵심 원리] 강의를 기반으로 작성되었습니다. 열심히 정리하고 스스로 공부하기 위해 만든 포스트이지만, 제대로 공부하고 싶으시면 해당 강의를 꼭 들으시는 것을 추천드립니다. 

 

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

728x90
반응형

'Spring > Spring 기본' 카테고리의 다른 글

[Spring과 DB] 5-2 Spring 에서의 예외 추상화  (1) 2023.08.16
[Spring과 DB] 5-1 Spring 에서의 예외처리 지원  (0) 2023.08.15
[Spring 기본] Bean 생명주기 콜백  (0) 2022.10.18
[Spring 기본] 의존 관계 주입 전략 (DI Strategy)  (0) 2022.10.17
[Spring 기본] Component Scan을 통한 Bean 자동화 관리  (0) 2022.10.17
'Spring/Spring 기본' 카테고리의 다른 글
  • [Spring과 DB] 5-2 Spring 에서의 예외 추상화
  • [Spring과 DB] 5-1 Spring 에서의 예외처리 지원
  • [Spring 기본] Bean 생명주기 콜백
  • [Spring 기본] 의존 관계 주입 전략 (DI Strategy)
문케이크
문케이크
    반응형
  • 문케이크
    누구나 개발할 수 있다
    문케이크
  • 전체
    오늘
    어제
    • 전체 보기 (122)
      • CS 이론 (13)
        • 운영체제 (8)
        • 네트워크 (2)
        • 알고리즘 (0)
        • Storage (3)
      • Spring (26)
        • Spring 기본 (12)
        • Spring 심화 (0)
        • JPA (11)
        • Spring Security (3)
      • 리액티브 (0)
        • RxJava (0)
      • SW 설계 (14)
        • OOP (0)
        • UML (3)
        • OOAD (0)
        • Design Pattern (11)
      • Java (8)
      • 웹 운영 (17)
        • AWS (15)
        • 운영 구축 (2)
      • Testing (3)
        • Unit (3)
      • Extra (3)
        • API 적용 (1)
      • 인프라 기술 (5)
        • Kubernetes (2)
        • Elasticsearch (3)
      • Logging (7)
        • Spring (5)
        • 인프라 (2)
      • 일상 (2)
        • 음식점 리뷰 (2)
        • Extra (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 문케이크의 블로그
  • 인기 글

  • 태그

    elasticsearch
    SRP
    BEAN
    Java
    OOAD
    k8s
    composition
    di
    Composite
    spring container
    Setter
    lombok
    Spring
    spring boot
    단위테스트
    JPA
    lazy loading
    Configuration
    mockito
    runtime exception
    GoF
    OOP
    디자인 패턴
    n+1
    decorator
    객체지향
    junit
    analyzer
    김영한
    Design Pattern
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
문케이크
[Spring 기본] Bean Scope
상단으로

티스토리툴바