Tech

SpringBoot - 어플리케이션 로딩이 완료된 시점에 호출되는 함수

Jamsun2 2022. 12. 15. 19:50

개요

웹서버를 개발하다 보면, 귀찮은 일중 하나가 테스트 페이지를 띄우는 일입니다.

 

  • http://localhost:8080/test

이 url을 웹페이지로 띄우려면 크롬에서 즐겨찾기 해 놓으면 되지만, 포트 번호 혹은 페이지 주소가 자주 바뀌면,

일일이 즐겨찾기하기에는 귀찮아지죠. 그래서, 프로그램이 실행될때, 콘솔 로그에 이동 링크가 제공 되도록 만들어보겠습니다.

추가로, SpringBoot에서 어플리케이션 로딩이 완료된 후에 호출되는 함수들(ApplicationRunner, CommandLineRunner, @EventListener(ApplicationReadyEvent.class))에 이동 링크를 적용해보겠습니다.

 

웹서버 구성

SpringBoot를 이용하여 간단한 웹 서버를 구성하겠습니다.

IntelliJ IDEA에서 직접 웹 서버를 구성할 수 도 있으며, 예제와 같이 스프링 웹페이지를 이용할 수 도 있습니다.

https://start.spring.io 접속 후, 웹서버 구성을 만든 후, GENERATE를 통해 프로젝트 파일을 생성합니다.

그림 1. start.spring.id에서 기본 웹서버 구성 다운로드

로컬에 DemoServer.zip 파일이 생성 되었습니다. 이제 압축을 풀고 IntelliJ IDEA를 이용하여 프로젝트를 실행하겠습니다.

그림 2. DemoServer를 IntelliJ IDEA에서 실행

기본적인 8080 포트로 서버가 실행 되었습니다. http://localhost:8080 으로 접속이 가능합니다.

아직 페이지가 구성되지 않아서, 404(Not Found) 에러가 발생합니다.

그림 3. 로컬 호스트로 접속

/test에 대한 간단한 응답 매핑을 해주겠습니다.

//com.example.ds.DemoController.java 파일
@RestController
public class DemoController {
    @GetMapping("/test")
    public ResponseEntity<String> test(HttpServletRequest request){
        return new ResponseEntity<>("Success", HttpStatus.OK);
    }
}

그림 4. /test 요청 성공

 

콘솔창에서 URL 호출

네. 이것으로 웹서버의 기본 구성이 완성되었습니다.

이제 콘솔창에서 url 호출하는 부분을 만들어볼까요? 제일 간단한 방법은 main 함수에 로그를 찍는 것입니다.

@SpringBootApplication
public class DemoServerApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
		System.out.println("main :: http://localhost:8080/test");
	}

}

이제 실행해보면, 콘솔창에 링크가 걸린 로그가 확인되실 것입니다.

그림 5. 콘솔창에 링크 로그 남기기

콘솔창에 남겨진 로그는 자동으로, 링크가 걸린 상태가 됩니다.

해당 링크를 클릭하면, 바로 웹페이지가 열리면서, 원하는 링크로 이동할 수 있게 됩니다.

여기서 생각을 좀 확장해서 main 함수말고 따로 함수로 뺄수는 없을까 하는 생각이 들게 됩니다.

@SpringBootApplication
public class DemoServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
		System.out.println("main :: http://localhost:8080/test");
	}

	@PostConstruct
	public void init(){
		System.out.println("init :: http://localhost:8080/test");
	}
}

그림 6. PostConstruct를 사용하여 로그 찍기

로그는 잘 나오는데, 해당 DemoServerApplication 클래스가 생성완료되는 시점에 로그가 찍히게 되고, 아직 객체 로딩이 완료된 상태는 아닙니다.

모든 컴포넌트 객체가 로딩이 끝나는 시점에 함수를 호출 할 수 있는 방법을 찾아보게 되었습니다.

 

객체 로딩에 사용할 호출 클래스 만들기

일단, DemoDataManager 컴포넌트를 생성합니다.

해당 컴포넌트의 select 함수를 불러보도록 하겠습니다.

//DemoDataManager.java, com.example.ds에 생성
@Component
public class DemoDataManager {

    public DemoDataManager() {
           System.out.println("Create DemoDataManager");
    }
    public List<?> select (){
        System.out.println("Call DemoDataManager::select");
        return new ArrayList<>();
    }
}

main 함수에 직접 넣으면, static 함수에 일반 객체를 부를 수 없다는 오류가 발생합니다.

그림 7. main 함수에서 demoDataManager 호출

init 함수에서 호출은 가능하지만, 모든 컴포넌트가 다 로딩 된 상태는 아닙니다.

@SpringBootApplication
public class DemoServerApplication {
	@Autowired
	DemoDataManager demoDataManager;

	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}
	@PostConstruct
	public void init(){
		demoDataManager.select();
	}
}

그림 8. init 함수에서 demoDataManager 호출

SpringBoot에서 최초 로딩 시 호출 할 수 있는 함수들에 대하여, 하나씩 알아보도록 하겠습니다.

가장 대표적으로 많이 사용되는 함수는 CommandLineRunner, ApplicationRunner이며, 최근에 새로 생긴 방법은 EventListener를 등록하는 방법입니다.

 

CommandLineRunner, ApplicationRunner - 전통적인 방법

가장 오래된 방법은 각 Runner의 실행 객체를 상속 받는 방법입니다.

@SpringBootApplication
public class DemoServerApplication  implements CommandLineRunner {
	@Autowired
	DemoDataManager demoDataManager;
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		demoDataManager.select();
	}
}
@SpringBootApplication
public class DemoServerApplication  implements ApplicationRunner {
	@Autowired
	DemoDataManager demoDataManager;
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}

	@Override
	public void run(ApplicationArguments args) throws Exception {
		demoDataManager.select();
	}
}

원래 존재하던 메인 클래스의 모양이 좀 이상하기는 하지만 동작은 잘합니다.

메인 클래스의 안쪽에 Bean 어노테이션을 이용하여, 객체로 등록할 수 도 있습니다.

 

CommandLineRunner, ApplicationRunner - @Bean 등록

@SpringBootApplication
public class DemoServerApplication {
	@Autowired
	DemoDataManager demoDataManager;
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}
	@Bean
	ApplicationRunner myApplicationRunner() {
		return new ApplicationRunner() {
			@Override
			public void run(ApplicationArguments args) throws Exception {
				demoDataManager.select();
			}
		};
	}
}
@SpringBootApplication
public class DemoServerApplication {
	@Autowired
	DemoDataManager demoDataManager;
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}
	@Bean
	CommandLineRunner myCommandLineRunner() {
		return new CommandLineRunner() {
			@Override
			public void run(String... args) throws Exception {
				demoDataManager.select();
			}
		};
	}
}

 

Bean으로 등록되는 부분은 축약해서 적용할 수 있습니다.

 

@Bean 등록 간소화

@SpringBootApplication
public class DemoServerApplication {
	@Autowired
	DemoDataManager demoDataManager;
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}
	@Bean
	CommandLineRunner myCommandLineRunner() {
		return args -> demoDataManager.select();
	}

	@Bean
	ApplicationRunner myApplicationRunner(){
		return args -> {
			demoDataManager.select();
			System.out.println("myApplicationRunner :: http://localhost:8080/test");
		};
	}
}

최근에 나왔다는 eventListener 등록에 대하여 알아보겠습니다.

 

@EventListener(ApplicationReadyEvent.class)

SpringBoot에서 어플리케이션 로딩이 완료되면, 이벤트 하나(ApplicationReadyEvent) 발생합니다.

해당 이벤트를 받을 수 있는 리스너를 등록하면, 어플리케이션 로딩이 완료된 시점에 호출되는 함수를 생성할 수 있습니다.

@SpringBootApplication
public class DemoServerApplication {
	@Autowired
	DemoDataManager demoDataManager;
	public static void main(String[] args) {
		SpringApplication.run(DemoServerApplication.class, args);
	}
	@EventListener(ApplicationReadyEvent.class)
	public void initialize(ApplicationReadyEvent event){
		System.out.println("ApplicationReadyEvent :: http://localhost:8082/test");
		demoDataManager.select();
	}
}

그림 9. EventListener 등록하여 사용

이러한 방법들을 사용하여, 어플리케이션 로딩이 완료된 시점에 함수 호출을 할 수 있으며, 해당 함수를 사용하여, 콘솔 로그 창에 원하는 페이지 링크를 로그로 찍는 간단한 방법에 대하여 설명했습니다.

 

-- written by tech.po@tg360tech.com --