티스토리 뷰

Springboot를 성능개선하는 방법에 대해 지난번에 글을 쓴 적이 있었다. 

 

Springboot 속도 개선 방법

어떻게 하면 Springboot을 조금 더 빠릿빠릿하게 만들 수 있을까 찾아보았다. 지금 사용하고 있는 최신버전(2.5.4)도 만족스럽게 사용하고 있지만 찾아보면 자료가 있을것 같았다. 마침 좋은 자료가

oingdaddy.tistory.com

그중 Lazy Initialization을 하는 방법과 효과에 대해 테스트를 해봤다. 일단 Lazy Init이라고 하는건 bean을 기동시점에 생성하는것이 아닌 실제 사용시에 호출을 하는 방법이다. 그렇기 때문에 당연히 기동시간은 단축된다. 그리고 최초 호출 시점에는 느리다. 어떻게 보면 조삼모사같지만 그래도 bean의 개수가 늘어나면 늘어날수록 기동시간이 늘기 때문에 덩치가 큰 프로젝트에서는 요긴하게 사용될 수 있다. 


Eager Init (Lazy Init의 반대말, 일반적인 bean 생성방식) 일 경우

일단 우리가 일반적으로 bean을 생성하는 것과 기동할때의 로그를 살펴보자. 

TestComponent.java

@Component
public class TestComponent {

    @Bean
    public void bean1() {
        System.out.println("bean1 created");
    }
}

이런식으로 아무 bean이나 생성하고 springboot project를 기동해보겠다. 

 

기동 로그 

[11:03:57.582][DEBUG]26808[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'demoApplication'
[11:03:57.582][DEBUG]26808[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'testComponent'
[11:03:57.582][DEBUG]26808[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'bean1'
bean1 created

이런식으로 내가 정의한 bean이 기동하는 시점에 생성이 되는것을 확인할 수 있다. 이렇게 생성이 되는걸 로그로 확인하려면 org package에 대해 log level을 debug로 해야지 확인 가능하다. 


Lazy Init 일 경우 

그럼 이제 Lazy Init을 적용해보고 테스트를 해보도록 하겠다. Lazy Init을 적용하는 방법에는 두가지가 있는데 전체를 다 Lazy init을 할건지 아니면 내가 원하는 부분만 할건지에 대한 방법이다. 

 

1. 원하는 부분만 Lazy Init 하는 방법

원하는 부분만 기동시에는 bean 생성하지 않고 호출시점에 생성하는 방법이다. 방법은 간단하다. @Bean 생성시 @Lazy 만 붙여주면 된다

TestComponent.java

@Component
public class TestComponent {

    @Lazy
    @Bean
    public void bean1() {
        System.out.println("bean1");
    }
}

기동 로그

[11:50:15.509][DEBUG]8004[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'demoApplication'
[11:50:15.517][DEBUG]8004[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'testComponent'
[11:50:15.517][DEBUG]8004[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'org.springframework.boot.autoconfigure.AutoConfigurationPackages'

아까와는 다르게 로그에 bean1을 생성하는 부분이 없어졌다. 기동시에 bean1이라는 bean이 생성이 되지 않은 것이다. 

 

2. 전체 Lazy Init 하는 방법

모든 bean을 다 Lazy Init으로 생성하고 싶을땐 @Lazy를 모든 bean 생성시 붙여줘야 하나? 아니다. 이것도 다 훌륭하신 위인분이 편하게 사용할 수 있도록 만들어 놓으신 코드가 있다. 

 

LazyInitBeanFactoryPostProcessor.java

@Configuration
public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            beanFactory.getBeanDefinition(beanName).setLazyInit(true);
        }
    }
}

component-scan이 가능한 곳에 위와 같은 클래스를 생성한다. bean에 @Lazy는 붙일 필요 없다. 그리고 기동해본다. 

기동 로그

[11:56:41.464][DEBUG]17476[org.springframework.context.annotation.ClassPathBeanDefinitionScanner.scanCandidateComponents:line435] - Identified candidate component class: file [C:\project\workspace-git\demo\target\classes\com\example\demo\LazyInitBeanFactoryPostProcessor.class]
[11:56:41.472][DEBUG]17476[org.springframework.context.annotation.ClassPathBeanDefinitionScanner.scanCandidateComponents:line435] - Identified candidate component class: file [C:\project\workspace-git\demo\target\classes\com\example\demo\TestComponent.class]
[11:56:41.848][DEBUG]17476[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'propertySourcesPlaceholderConfigurer'

springboot 내부 클래스들은 bean 생성이 되는것을 확인할 수 있지만 내가 정의한 클래스들은 인식만 해 놓는다. 나중에 써먹기 위해서 후보군만 뽑아 놓는거라고 보면 된다. 


테스트

위와 같이 Lazy Init으로 기동을 하고 bean이 호출이 되면 생성이 되는 것을 테스트해보겠다. 

TestController.java

@RestController
public class TestController {

    @Autowired
    private TestComponent testComponent;
	
    @GetMapping("/bean1")
    public void callBean() {
        testComponent.bean1();
    }
}

아까 만든 bean을 호출하는 Controller를 만들었다. 서버를 기동한 후에 /bean1 을 호출해보도록 하자. 

 

호출 로그

[12:08:21.141][DEBUG]11544[org.springframework.web.servlet.DispatcherServlet.traceDebug:line91] - GET "/bean1", parameters={}
[12:08:21.145][DEBUG]11544[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'testController'
[12:08:21.149][DEBUG]11544[org.springframework.beans.factory.support.DefaultListableBeanFactory.getSingleton:line225] - Creating shared instance of singleton bean 'testComponent'
[12:08:21.151][DEBUG]11544[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.getHandler:line522] - Mapped to com.example.demo.TestController#callBean()
bean1 created

Controller에서 정의한 /bean1 이라는 주소로 호출을 하면 위와 같이 호출하는 시점에 Creating shared instance 를 하는것을 확인할 수 있다. 

 

프로젝트가 커지면 커질수록, bean이 많아지면 많아질수록 Lazy Init은 진가를 발휘할 것이다. 물론 호출시점에는 조금은 느려지겠지만 개발시점에서 개발생산성은 괜찮아지리라 본다. 

 

끝!

댓글
최근에 올라온 글
최근에 달린 댓글
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31