Toby Spring Boot

ํ† ๋น„๋‹˜์˜ ํ† ๋น„์˜ ์Šคํ”„๋ง ๋ถ€ํŠธ - ์ดํ•ด์™€ ์›๋ฆฌ ๊ฐ•์˜๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

Github

MY Project

Intro

Spring Boot Documentation

์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ์Šคํ”„๋ง ๊ธฐ๋ฐ˜์œผ๋กœ ์‹ค๋ฌด ํ™˜๊ฒฝ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ˆ˜์ค€์˜ ๋…๋ฆฝ์‹คํ–‰ํ˜• ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„

๋ณต์žกํ•œ ๊ณ ๋ฏผ ์—†์ด ๋น ๋ฅด๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋„๊ตฌ์˜ ๋ชจ์Œ

ํŠน์ง•

  • ๋…๋ฆฝํ˜• ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ

  • Tomcat, Jetty, Undertow ๋“ฑ์„ ํฌํ•จ(WAR ํŒŒ์ผ ๋ฐฐํฌ ๋ถˆํ•„์š”)

  • ๋นŒ๋“œ ๊ตฌ์„ฑ์„ ๋‹จ์ˆœํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๋…์ž์ ์ธ 'startor' ์ข…์†์„ฑ ์ œ๊ณต

  • ๊ฐ€๋Šฅํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์Šคํ”„๋ง ๋ฐ ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์„ฑ

  • ๋ฉ”ํŠธ๋ฆญ, ์ƒํƒœ ํ™•์ธ ๋ฐ ์™ธ๋ถ€ํ™”๋œ ๊ตฌ์„ฑ๊ณผ ๊ฐ™์€ ํ”„๋กœ๋•์…˜ ์ค€๋น„ ๊ธฐ๋Šฅ ์ œ๊ณต

  • ์ฝ”๋“œ ์ƒ์„ฑ ๋ฐ XML ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ ๋ถˆํ•„์š”

.

Containerless

  • ์Šคํ”„๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ์š”๊ตฌ๋˜๋Š” Servlet Container ๊ด€๋ จ ์„ค์ • ์ง€์›์„ ์œ„ํ•œ ๊ฐœ๋ฐœ ๋„๊ตฌ์™€ ์•„ํ‚คํ…์ฒ˜ ์ง€์›

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ์ด ์•„๋‹Œ ๋‹จ์ˆœ ๋ฐ˜๋ณต ์ž‘์—… ์ œ๊ฑฐ

    • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ์„ค์น˜, WAR ํด๋” ๊ตฌ์กฐ, web.xml, WAR ๋นŒ๋“œ, ์ปจํ…Œ์ด๋„ˆ๋กœ ๋ฐฐ์น˜, ํฌํŠธ ์„ค์ •, ํด๋ž˜์Šค ๋กœ๋”, ๋กœ๊น… ...

  • ๋…๋ฆฝ์‹คํ–‰ํ˜•(standalone) ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ๋™์ž‘

    • main ๋ฉ”์„œ๋“œ ์‹คํ–‰๋งŒ์œผ๋กœ Servlet Container ๊ด€๋ จ ๋ชจ๋“  ํ•„์š” ์ž‘์—…์ด ์ˆ˜ํ–‰

Result

.

Opinionated Tool

Spring

  • ๊ทน๋‹จ์  ์œ ์—ฐํ•จ์„ ์ถ”๊ตฌํ•˜๊ณ  ๋‹ค์–‘ํ•œ ๊ด€์ ์„ ์ˆ˜์šฉํ•˜๋Š” ๊ฒƒ์ด ์„ค๊ณ„ ์ฒ ํ•™์ด์—ˆ์ง€๋งŒ..

  • ๊ฐ์ข… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์˜์กด๊ด€๊ณ„์™€ ๋ฒ„์ „ ํ˜ธํ™˜์„ฑ์„ ์ฒดํฌํ•˜๋Š” ์ž‘์—…์€ ๊ณ ๋˜๊ณ  ์‰ฝ์ง€ ์•Š์€ ์ž‘์—…

Spring Boot

  • opinionated ์„ค๊ณ„: ์ž๊ธฐ ์ฃผ์žฅ์ด ๊ฐ•ํ•˜๊ณ  ์ž์‹ ์˜ ์˜๊ฒฌ์„ ๊ณ ์ง‘ํ•œ ์„ค๊ณ„ ์ฒ ํ•™

    • ์ผ๋‹จ ์ •ํ•ด์ฃผ๋Š” ๋Œ€๋กœ ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœํ•˜๊ณ  ๋‚˜์ค‘์— ๊ณ ๋ฏผ. ์Šคํ”„๋ง์„ ์ž˜ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• ์ œ๊ณต

  • ์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” ๊ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ฒ„์ „๋งˆ๋‹ค ์‚ฌ์šฉํ•  ๊ธฐ์ˆ ์˜ ์ข…๋ฅ˜ ์„ ์ •

    • ์‚ฌ์ „ ๊ฒ€์ฆ๋œ ์ถ”์ฒœ ๊ธฐ์ˆ , ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ตฌ์„ฑ, ์˜์กด ๊ด€๊ณ„์™€ ์ ์šฉ ๋ฒ„์ „, ์„ธ๋ถ€ ๊ตฌ์„ฑ(DI)๊ณผ ๋””ํดํŠธ ์„ค์ • ๋“ฑ ์ œ๊ณต

    • ๋””ํดํŠธ ๊ตฌ์„ฑ์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐํ•œ ๋ฐฉ๋ฒ• ์ œ๊ณต

Start to Develop

JDK

  • SDK-MAN(The Software Development Kit Manager)

    • Unix ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์—์„œ ์—ฌ๋Ÿฌ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ํ‚คํŠธ์˜ ๋ณ‘๋ ฌ ๋ฒ„์ „์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ

    • java ๋ฒ„์ „ ํ™•์ธ โž” sdk list java

    • ํŠน์ • identifier ์„ค์น˜ โž” sdk install java {id}

    • ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ํŠน์ • ๋ฒ„์ „์˜ java ์‚ฌ์šฉ โž” sdk use java {id}

  • jabba

    • Java ๋ฒ„์ „ ๊ด€๋ฆฌ์ž

.

API Test Method

  • ์›น ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž ๋„๊ตฌ - Network

  • curl

  • Intellij IDEA Ultimate- http request

  • JUnit Test

  • ...

.

HTTP Request and Response

โฏ http -v ":8080/hello?name=Spring"
GET /hello?name=Spring HTTP/1.1
Accept: */* --> ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ ํ˜ธํ•˜๋Š” ๋ฏธ๋””์–ด ํƒ€์ž…
Accept-Encoding: gzip, deflate --> ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„ ํ˜ธํ•˜๋Š” ์••์ถ• ์ธ์ฝ”๋”ฉ
Connection: keep-alive
Host: localhost:8080
User-Agent: HTTPie/3.2.1

HTTP/1.1 200
Connection: keep-alive
Content-Length: 12
Content-Type: text/plain;charset=UTF-8 --> ํ‘œํ˜„ ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹
Date: Thu, 01 Dec 2022 01:45:15 GMT
Keep-Alive: timeout=60
Hello Spring

Standalone Servlet Application

Start Servlet Container

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;

public class HellobootApplication {
	public static void main(String[] args) {
		ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
		WebServer webServer = serverFactory.getWebServer();
		webServer.start();
	}
}

.

Register Servlet in ServletContext

ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
		WebServer webServer = serverFactory.getWebServer(servletContext -> {
			servletContext.addServlet("hello", new HttpServlet() {
				@Override
				protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
					String name = req.getParameter("name");

					resp.setStatus(HttpStatus.OK.value());
					resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
					resp.getWriter().println("hello " + name);
				}
			}).addMapping("/servlet/hello");
		});
		webServer.start();

.

Front Controller Pattern

  • ์—ฌ๋Ÿฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋“ฑ์žฅํ•˜๋Š” ๊ณตํ†ต ์ž‘์—…์„ ํ•˜๋‚˜์˜ ์˜ค๋ธŒ์ ํŠธ์—์„œ ์ผ๊ด„์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ๋ฐฉ์‹

  • ๋ชจ๋“  ์š”์ฒญ, ํ˜น์€ ์ผ์ • ํŒจํ„ด์„ ๊ฐ€์ง„ ์š”์ฒญ์„ ํ•˜๋‚˜์˜ ์„œ๋ธ”๋ฆฟ์ด ๋‹ด๋‹นํ•˜๋„๋ก ๋งคํ•‘

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ์€ ๋งคํ•‘๊ณผ ๋ฐ”์ธ๋”ฉ

    • ๋งคํ•‘:ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ HTTP ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๊ฒฐ์ •ํ•˜๊ณ  ์—ฐ๋™ํ•˜๋Š” ์ž‘์—…

    • ๋ฐ”์ธ๋”ฉ: ํ•ธ๋“ค๋Ÿฌ์—๊ฒŒ ์›น ์š”์ฒญ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๊ณ  ์˜๋ฏธ์žˆ๋Š” ์˜ค๋ธŒ์ ํŠธ์— ๋‹ด์•„์„œ ์ „๋‹ฌํ•˜๋Š” ์ž‘์—…

  • ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ์ „ํ™˜

    ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
      	WebServer webServer = serverFactory.getWebServer(servletContext -> {
      		HelloController helloController = new HelloController();
    
      		servletContext.addServlet("frontController", new HttpServlet() {
      			@Override
      			protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      				// ์ธ์ฆ, ๋ณด์•ˆ, ๋‹ค๊ตญ์–ด, ๊ณตํ†ต ๊ธฐ๋Šฅ ..
      				if (req.getRequestURI().equals("/servlet/hello") && req.getMethod().equals(HttpMethod.GET.name())) {
      					String name = req.getParameter("name");
    
      					String ret = helloController.hello(name);
    
      					resp.setStatus(HttpStatus.OK.value());
      					resp.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
      					resp.getWriter().println(ret);
      				}
      				else if (req.getRequestURI().equals("/user")) {
      					// ...
      				}
      			 	else {
      					resp.setStatus(HttpStatus.NOT_FOUND.value());
      				}
    
      			}
      		}).addMapping("/*");
      	});
      	webServer.start();

Standalone Spring Application

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์ด ๋‹ด๊ธด ํ‰๋ฒ”ํ•œ ์ž๋ฐ” ์˜ค๋ธŒ์ ํŠธ(POJO)์™€ ๊ตฌ์„ฑ ์ •๋ณด(Configuration Metadata)๋ฅผ ๋Ÿฐํƒ€์ž„์— ์กฐํ•ฉํ•ด์„œ ๋™์ž‘ํ•˜๋Š” ์ตœ์ข… ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒ์„ฑ

// ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ
GenericApplicationContext applicationContext = new GenericApplicationContext(); 
// ๋นˆ ์˜ค๋ธŒ์ ํŠธ ํด๋ž˜์Šค ์ •๋ณด ๋“ฑ๋ก
applicationContext.registerBean(HelloController.class); 
// ๊ตฌ์„ฑ ์ •๋ณด๋กœ ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”(๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ง์ ‘ ์ƒ์„ฑ)
applicationContext.refresh(); 

...

// ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๋นˆ ์˜ค๋ธŒ์ ํŠธ ํš๋“
HelloController helloController = applicationContext.getBean(HelloController.class); 

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” ์‹ฑ๊ธ€ํ†ค ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ๋ผ๊ณ ๋„ ๋ถˆ๋ฆฐ๋‹ค.

  • ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋™์ž‘ํ•˜๋Š” ๋™์•ˆ ๋‹จ ํ•˜๋‚˜์˜ ์˜ค๋ธŒ์ ํŠธ๋งŒ์„ ๋งŒ๋“ค๊ณ  ์‚ฌ์šฉ๋˜๋„๋ก ์ง€์›

.

Dependency Injection

Result
  • DI๋ฅผ ์œ„ํ•ด N๊ฐœ์˜ ์˜ค๋ธŒ์ ํŠธ(์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด)๊ฐ€ ๋™์ ์œผ๋กœ ์˜์กด๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๋„๋ก ๋„์™€์ฃผ๋Š” ์–ด์…ˆ๋ธ”๋Ÿฌ๊ฐ€ ํ•„์š”

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ(์–ด์…ˆ๋ธ”๋Ÿฌ)๋Š” DI๋ฅผ ๊ฐ€๋Šฅํ•˜๋„๋ก ๋„์™€์ฃผ๋Š” ์–ด์…ˆ๋ธ”๋Ÿฌ๋กœ ๋™์ž‘

    • ์˜์กด๊ด€๊ณ„๊ฐ€ ์—†๋Š” ํด๋ž˜์Šค๋“ค์˜ ์˜ค๋ธŒ์ ํŠธ๋กœ ์„œ๋กœ ๊ด€๊ณ„๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

  • ์Šคํ”„๋ง ์ปจ๋ฐ์ด๋„ˆ๋Š” ๋ฉ”ํƒ€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ํด๋ž˜์Šค์— ์‹ฑ๊ธ€ํ†ค ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑ

    • ์ƒ์„ฑ๋œ ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์‚ฌ์šฉํ•  ๋‹ค๋ฅธ ์˜์กด ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์žˆ๋‹ค๋ฉด ์˜์กด์„ฑ ์ฃผ์ž…

    • ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์ƒ์„ฑ์ž ์ฃผ์ž…, ํŒฉํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ ๋“ฑ ์กด์žฌ

.

DispatcherServlet

  • ์Šคํ”„๋ง์€ ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์™€ ๊ฐ™์€ ์—ญํ• ์„ ๋‹ด๋‹นํ•˜๋Š” DispatcherServlet ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

  • DispatcherServlet ์€ ์„œ๋ธ”๋ฆฟ์œผ๋กœ ๋“ฑ๋ก๋˜์–ด์„œ ๋™์ž‘ํ•˜๋ฉด์„œ, ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ด์šฉํ•ด์„œ ์š”์ฒญ์„ ์ „๋‹ฌํ•  ํ•ธ๋“ค๋Ÿฌ์ธ ์ปจํŠธ๋กค๋Ÿฌ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉ

  • DispatcherServlet ์ด ์‚ฌ์šฉํ•˜๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋Š” GenericWebApplicationContext ๋ฅผ ์ด์šฉํ•ด์„œ ์ž‘์„ฑ

.

์• ๋…ธํ…Œ์ด์…˜ ๋งคํ•‘ ์ •๋ณด

  • DispatcherServlet ์€ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ๋นˆ ํด๋ž˜์Šค์— ์žˆ๋Š” ๋งคํ•‘ ์• ๋…ธํ…Œ์ด์…˜ ์ •๋ณด๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ์›น ์š”์ฒญ์„ ์ „๋‹ฌํ•  ์˜ค๋ธŒ์ ํŠธ์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ์„ ์ •

  • ํด๋ž˜์Šค ๋ ˆ๋ฒจ์˜ @RequestMapping ๊ณผ ๋ฉ”์†Œ๋“œ ๋ ˆ๋ฒจ์˜ @GetMapping ๋‘ ๊ฐ€์ง€์˜ ์ •๋ณด๋ฅผ ์กฐํ•ฉํ•ด์„œ ๋งคํ•‘์— ์‚ฌ์šฉํ•  ์ตœ์ข… ์ •๋ณด ์ƒ์„ฑ

  • ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์†Œ๋“œ์˜ ๋ฆฌํ„ด๊ฐ’์„ ์›น ์š”์ฒญ์˜ ๋ฐ”๋””์— ์ ์šฉํ•˜๋„๋ก @ResponseBody ์„ ์–ธ

    • ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด String ํƒ€์ž…์˜ ์‘๋‹ต์€ ๋ทฐ ์ด๋ฆ„์œผ๋กœ ํ•ด์„ํ•˜๊ณ  Thymeleaf ๊ฐ™์€ ๋ทฐ ํ…œํ”Œ๋ฆฟ์„ ํƒ์ƒ‰(์ด ๊ฒฝ์šฐ 404 ์—๋Ÿฌ ๋ฐœ์ƒ)

    • @RestController ๋Š” @ResponseBody ๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ฉ”์†Œ๋“œ ๋ ˆ๋ฒจ์˜ @ResponseBody ๋ฅผ ๋„ฃ์ง€ ์•Š์•„๋„ ์ ์šฉ๋œ ๊ฒƒ์ฒ˜๋Ÿผ ๋™์ž‘

    @RequestMapping("/hello")
    public class HelloController {
        ...
        @GetMapping
        @ResponseBody
        public String hello(String name) {
            return helloService.sayHello(Objects.requireNonNull(name));
        }
    }

.

์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋กœ ํ†ตํ•ฉ

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ์ดˆ๊ธฐํ™” ์ž‘์—… ์ค‘์— ํ˜ธ์ถœ๋˜๋Š” ํ›… ๋ฉ”์†Œ๋“œ์— ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ(ํ†ฐ์บฃ)์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ๋„์šฐ๋Š” ์ฝ”๋“œ ์‚ฝ์ž…

GenericWebApplicationContext applicationContext = new GenericWebApplicationContext() {
    @Override
    protected void onRefresh() {
        super.onRefresh();

        ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
        WebServer webServer = serverFactory.getWebServer(servletContext -> {
            servletContext.addServlet("dispatcherServlet",
                    new DispatcherServlet(this)
            ).addMapping("/*");
        });
        webServer.start();
    }
}; 

.

@Component Scan

  • ํด๋ž˜์Šค์— ์• ๋…ธํ…Œ์ด์…˜์„ ์„ ์–ธํ•˜๊ณ , ์ด๋ฅผ ์Šค์บ”ํ•ด์„œ ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ๋นˆ์œผ๋กœ ์ž๋™ ๋“ฑ๋ก

    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฉ”์ธ ํด๋ž˜์Šค์—๋Š” @ComponentScan ์„ ์–ธ

    • ๋“ฑ๋ก ๋Œ€์ƒ์ด ๋  ํด๋ž˜์Šค์—๋Š” @Component ์„ ์–ธ

    • @Component ๋Š” ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์• ๋…ธํ…Œ์ด์…˜๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

      • @Controller, @RestController, @Service ๋“ฑ..

  • @RestController

    • @RestController ๋Š” @Controller ๋ฅผ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ ,

    • @Controller ๋Š” @Component๋ฅผ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ

    • ์ด ๊ฒฝ์šฐ @RestController ๋Š” @Component ์• ๋…ธํ…Œ์ด์…˜์ด ๋ถ™์€ ๊ฒƒ๊ณผ ๊ฐ™์€ ํšจ๊ณผ

    • @RestController ๊ฐ€ ๋ถ™์€ ๊ฒฝ์šฐ DispatcherServlet ์˜ ๋งคํ•‘ ์ •๋ณด ํƒ์ƒ‰ ๋Œ€์ƒ์ด ๋˜๋ฏ€๋กœ ํด๋ž˜์Šค ๋ ˆ๋ฒจ์— ๋งคํ•‘ ์• ๋…ธํ…Œ์ด์…˜(@RequestMapping) ๋ถˆํ•„์š”

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Controller
    @ResponseBody
    public @interface RestController {}

.

Bean์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ

/** 
 * @Bean ๋ฉ”์†Œ๋“œ์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ƒ์„ฑ
 * 
 * DispatcherServlet ์ด ํ•„์š”๋กœ ํ•˜๋Š” WebApplicationContext ํƒ€์ž… ์ปจํ…Œ์ด๋„ˆ ์˜ค๋ธŒ์ ํŠธ๋Š” -> dispatcherServlet.setApplicationContext(this);
 * ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ๋นˆ ์ƒ์• ์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ฃผ์ž… ๋น‹๊ฒŒ ๋œ๋‹ค.
 */
@Bean
public DispatcherServlet dispatcherServlet() {
    return new DispatcherServlet();
}
  • DispatcherServlet ์€ ApplicationContextAware ๋ผ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ setter ๋ฉ”์†Œ๋“œ๋กœ ์ฃผ์ž…ํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง„ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„

  • ์ด๋Ÿฌํ•œ ์ƒ์• ์ฃผ๊ธฐ ๋นˆ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ฐ€์ง„ ๋นˆ์ด ๋“ฑ๋ก๋˜๋ฉด ์Šคํ”„๋ง์€ ์ž์‹ ์„ ์ง์ ‘ ์ฃผ์ž…

  • ๋นˆ ์ƒ์• ์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋˜๋Š” ์˜ค๋ธŒ์ ํŠธ๋Š” ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์Šค์Šค๋กœ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•ด์„œ ๋นˆ์œผ๋กœ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋„๋ก ์ง€์›

  • ๊ทธ๋ฐ–์— ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ์ƒ์• ์ฃผ๊ธฐ ๋ฉ”์†Œ๋“œ

    BeanNameAware's setBeanName,
    BeanClassLoaderAware's setBeanClassLoader,
    BeanFactoryAware's setBeanFactory,
    EnvironmentAware's setEnvironment,
    EmbeddedValueResolverAware's setEmbeddedValueResolver,
    ResourceLoaderAware's setResourceLoader (only applicable when running in an application context),
    ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context),
    MessageSourceAware's setMessageSource (only applicable when running in an application context),
    ApplicationContextAware's setApplicationContext (only applicable when running in an application context),
    ServletContextAware's setServletContext (only applicable when running in a web application context),
    postProcessBeforeInitialization methods of BeanPostProcessors,
    InitializingBean's afterPropertiesSet,
    a custom init-method definition,
    postProcessAfterInitialization methods of BeanPostProcessors

TEST

TestRestTemplate

  • ์›น ์„œ๋ฒ„์— HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์•„์„œ ๊ฒ€์ฆํ•˜๋Š” ํ…Œ์ŠคํŠธ์—์„œ๋Š” TestRestTemplate ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์ž.

@Test
void hello() {
    TestRestTemplate restTemplate = new TestRestTemplate();

    ResponseEntity<String> res =
            restTemplate.getForEntity("http://localhost:8080/hello?name={name}", String.class, "Spring");

    assertThat(res.getStatusCode()).isEqualTo(HttpStatus.OK);
    assertThat(res.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE).startsWith(MediaType.TEXT_PLAIN_VALUE)).isTrue();
    assertThat(res.getBody().trim()).isEqualTo("Hello Spring");
}

.

๋‹จ์œ„ ํ…Œ์ŠคํŠธ

  • ์˜์กด ์˜ค๋ธŒ์ ํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ, ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋™์•ˆ์— ์ˆ˜ํ–‰๋  ์ตœ์†Œํ•œ์˜ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ์˜์กด ์˜ค๋ธŒ์ ํŠธ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธ์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉ

@Test
void helloController() {
    HelloController helloController = new HelloController(name -> name);
    String ret = helloController.hello("Test");
    Assertions.assertThat(ret).isEqualTo("Test");
}

.

Decorator Pattern and Proxy Pattern

Result
  • Decorator Pattern

    • ๊ธฐ์กด ์ฝ”๋“œ์— ๋™์ ์œผ๋กœ ์ฑ…์ž„์„ ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด

    • ์˜ค๋ธŒ์ ํŠธ ํ•ฉ์„ฑ ๊ตฌ์กฐ๋กœ ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค๊ณ„

    • DI๋ฅผ ์ ์šฉํ•ด์„œ ์˜์กด๊ด€๊ณ„๋ฅผ ๋Ÿฐํƒ€์ž„์— ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์˜์กด ์˜ค๋ธŒ์ ํŠธ์™€ ๋™์ผํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ํ™•์žฅ๊ธฐ๋Šฅ(๋ฐ์ฝ”๋ ˆ์ดํ„ฐ)์„ ๋™์ ์œผ๋กœ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

    • ์žฌ๊ท€์ ์ธ ๊ตฌ์กฐ๋กœ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฑ…์ž„์„ ๋ถ€๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅ

Result
  • Proxy Pattern

    • ํ”„๋ก์‹œ๋Š” ๋‹ค๋ฅธ ์˜ค๋ธŒ์ ํŠธ์˜ ๋Œ€๋ฆฌ์ž ํ˜น์€ ํ”Œ๋ ˆ์ด์Šค ํ™€๋” ์—ญํ• 

    • ํ”„๋ก์‹œ๋Š” ๋ฆฌ๋ชจํŠธ ์˜ค๋ธŒ์ ํŠธ์— ๋Œ€ํ•œ ๋กœ์ปฌ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜, ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ๋Œ€์ƒ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑ

    • ๋ณด์•ˆ์ด๋‚˜ ์ ‘์† ์ œ์–ด ๋“ฑ์— ์‚ฌ์šฉ

Auto Configuration

Meta-annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // Meta Annotation
public @interface Service {
}
  • ์• ๋…ธํ…Œ์ด์…˜์— ์ ์šฉํ•œ ์• ๋…ธํ…Œ์ด์…˜

  • ์Šคํ”„๋ง์€ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์˜ ํšจ๋ ฅ์„ ์ ์šฉ

Composed-annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller // Meta Annotation
@ResponseBody // Meta Annotation
public @interface RestController {
...
}
  • ํ•˜๋‚˜ ์ด์ƒ์˜ ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋œ ์• ๋…ธํ…Œ์ด์…˜

  • ๋ชจ๋“  ๋ฉ”ํƒ€ ์• ๋…ธํ…Œ์ด์…˜์ด ์ ์šฉ๋œ ๊ฒƒ๊ณผ ๋™์ผํ•œ ํšจ๊ณผ

Result

Application Logic Bean

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๊ณ  ์žˆ๋Š” ๋นˆ

  • ์ปดํฌ๋„ŒํŠธ ์Šค์บ๋„ˆ์— ์˜ํ•ด์„œ ๋นˆ ๊ตฌ์„ฑ ์ •๋ณด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋กœ ๋“ฑ๋ก

  • ex. HelloController, HelloDecorator ..

Application Infrastructure Bean

  • ์Šคํ”„๋ง ๋ถ€ํŠธ์—์„œ ์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด์— ์˜ํ•ด ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋˜๋Š” ๋นˆ

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋™์ž‘ํ•˜๋Š”๋ฐ ๊ผญ ํ•„์š”ํ•œ ๊ธฐ์ˆ  ๊ธฐ๋ฐ˜์„ ์ œ๊ณตํ•˜๋Š” ๋นˆ

  • ex. ServletWebServerFactory, DispatcherServlet..

Container Infrastructure(Infra) Bean

  • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ์˜ ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•ด์„œ ๋นˆ ๋“ฑ๋ก๊ณผ ์ƒ์„ฑ, ๊ด€๊ณ„์„ค์ •, ์ดˆ๊ธฐํ™” ๋“ฑ์˜ ์ž‘์—…์— ์ฐธ์—ฌํ•˜๋Š” ๋นˆ

  • ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ง์ ‘ ๋งŒ๋“ค๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋นˆ์ด๋ฏ€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นˆ๊ณผ ๊ตฌ๋ถ„

  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ฃผ์ž… ๋ฐ›์•„์„œ ํ™œ์šฉ ๊ฐ€๋Šฅ

.

์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด ๋™์  ๋“ฑ๋ก

public interface ImportSelector {
    String[] selectImports(AnnotationMetadata importingClassMetadata);
    ...
}

...

public class MyAutoConfigImportSelector implements DeferredImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {
                "tobyspring.config.autoconfig.DispatcherServletConfig",
                "tobyspring.config.autoconfig.TomcatWebServerConfig"
        };
    }
}
  • ImportSelector ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ @Import ํ•ด์ฃผ๋ฉด selectImports ๊ฐ€ ๋ฆฌํ„ดํ•˜๋Š” ํด๋ž˜์Šค ์ด๋ฆ„์œผ๋กœ @Configuration ํด๋ž˜์Šค๋ฅผ ์ฐพ์•„์„œ ๊ตฌ์„ฑ ์ •๋ณด๋กœ ์‚ฌ์šฉ

  • @import ๋Œ€์ƒ์„ ์™ธ๋ถ€์—์„œ ์ฝ”๋“œ๋กœ ๊ฐ€์ ธ์˜ค๊ณ  ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋™์ ์ธ ๋ฐฉ๋ฒ• ์ œ๊ณต

.

์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด ํŒŒ์ผ ๋ถ„๋ฆฌ

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    ArrayList<Object> autoConfigs = new ArrayList<>();

    ImportCandidates.load(MyAutoConfiguration.class, classLoader).forEach(autoConfigs::add);

    return autoConfigs.toArray(new String[0]);
}
  • @MyAutoConfiguration ์• ๋…ธํ…Œ์ด์…˜ ์ƒ์„ฑ

  • tobyspring.config.MyAutoConfiguration.imports ํŒŒ์ผ์„ META-INF/spring ํด๋” ์•„๋ž˜ ์ƒ์„ฑ

  • selectImports() ์—์„œ ํŒŒ์ผ์— ์ž‘์„ฑ๋œ ํด๋ž˜์Šค ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก์‹œํ‚ฌ @Configuration ํด๋ž˜์Šค ๋ชฉ๋ก ์ €์žฅ

.

@Configuration ๋™์ž‘ ๋ฐฉ์‹

@Configuration(proxyBeanMethods = false)
  • proxyBeanMethods = true (default, ์Šคํ”„๋ง 5.2 ๋ฒ„์ „๋ถ€ํ„ฐ ์ง€์›)

    • true ์ผ ๊ฒฝ์šฐ, @Configuration ํด๋ž˜์Šค๋Š” CGLib ๋ฅผ ์ด์šฉํ•ด์„œ ํ”„๋ก์‹œ ํด๋ž˜์Šค๋กœ ํ™•์žฅ ํ›„ @Bean ์ด ๋ถ™์€ ๋ฉ”์†Œ๋“œ์˜ ๋™์ž‘ ๋ฐฉ์‹์„ ๋ณ€๊ฒฝ

    • @Bean ๋ฉ”์†Œ๋“œ๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด์„œ ๋‹ค๋ฅธ ๋นˆ์˜ ์˜์กด ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•  ๋•Œ ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœ๋˜๋”๋ผ๋„ ์‹ฑ๊ธ€ํ†ค ๋นˆ์ฒ˜๋Ÿผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งค๋ฒˆ ๊ฐ™์€ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๋ฆฌํ„ด

      /**
       * Spring ์€ ํ•˜๋‚˜์˜ ๋นˆ์„ ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋‹ค๋ฅธ ๋นˆ์—์„œ ์˜์กดํ•˜๊ณ  ์žˆ์„ ๊ฒฝ์šฐ,
       * Factory Method ํ˜ธ์ถœ ์‹œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๋นˆ์ด ์ƒ์„ฑ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด
       * @Configuration class ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ proxy ๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ธฐ๋Šฅ ํ™•์žฅ
       * (proxyBeanMethods = true)
       */
      static class MyConfigProxy extends MyConfig {
          private Common common;
      
          @Override
          Common common() {
              if (this.common == null) {
                  this.common = super.common();
              }
      
              return this.common;
          }
      }
      
      ...
      
      @Configuration
      static class MyConfig {
          @Bean
          Common common() {
              return new Common();
          }
      
          @Bean
          Bean1 bean1() {
              return new Bean1(common());
          }
      
          @Bean
          Bean2 bean2() {
              return new Bean2(common());
          }
      }
  • ๋‹จ, @Bean ๋ฉ”์†Œ๋“œ ์ง์ ‘ ํ˜ธ์ถœ๋กœ ๋นˆ ์˜์กด๊ด€๊ณ„ ์ฃผ์ž…์„ ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ตณ์ด ๋ณต์žกํ•œ ํ”„๋ก์‹œ๋ฅผ ์ƒ์„ฑํ•  ํ•  ํ•„์š”๊ฐ€ ์—†์Œ

    • ์ด ๊ฒฝ์šฐ proxyBeanMethods = false ๋กœ ์ง€์ •ํ•ด ๋ณด์ž.

    • @Bean ๋ฉ”์†Œ๋“œ๋Š” ํ‰๋ฒ”ํ•œ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์ฒ˜๋Ÿผ ๋™์ž‘

์กฐ๊ฑด๋ถ€ ์ž๋™ ๊ตฌ์„ฑ

Spring Boot AutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore
@AutoConfigureAfter
public @interface AutoConfiguration {
  ...
}

META-INF.spring.org.springframework.boot.autoconfigure.AutoConfiguration.imports

  • ์•ฝ 144 ๊ฐœ์˜ autoConfiguration ์ด Spring Boot ๊ธฐ๋ณธ ๋“ฑ๋ก

Spring Boot application starters

.

@Conditional๊ณผ Condition

/**
 * ์Šคํ”„๋ง 4.0์— ์ถ”๊ฐ€๋œ ์• ๋…ธํ…Œ์ด์…˜์œผ๋กœ ๋ชจ๋“  ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ปจํ…Œ์ด๋„ˆ์— ๋นˆ์œผ๋กœ ๋“ฑ๋ก
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
    Class<? extends Condition>[] value();
}

...

/**
 *  @Conditional ์— ์ง€์ •๋˜์–ด์„œ ๊ตฌ์ฒด์ ์ธ ๋งค์นญ ์กฐ๊ฑด์„ ๊ฐ€์ง„ ํด๋ž˜์Šค๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผํ•  ์ธํ„ฐํŽ˜์ด์Šค
 */
@FunctionalInterface
public interface Condition {
    boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

...

/**
 * Condition interface ๊ตฌํ˜„์ฒด
 */
static class BooleanCondition implements Condition {
    /**
     *  @Conditional ์• ๋…ธํ…Œ์ด์…˜์˜ ์—˜๋ฆฌ๋จผํŠธ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋Š” AnnotatedTypeMetadata ์ „๋‹ฌ
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(BooleanConditional.class.getName());
        Boolean value = (Boolean) annotationAttributes.get("value");
        return value;
    }
}
  • @Conditional์€ @Configuration ํด๋ž˜์Šค์™€ @Bean ๋ฉ”์†Œ๋“œ์— ์ ์šฉ ๊ฐ€๋Šฅ

  • ํด๋ž˜์Šค ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ ๋ฉ”์†Œ๋“œ๋Š” ๋ฌด์‹œ

.

Costume @Conditional

  • @Conditional ์˜ ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ๋ฐฉ๋ฒ•์€ ํด๋ž˜์Šค ์กด์žฌ ํ™•์ธ

  • ์–ด๋–ค ๊ธฐ์ˆ ์˜ ํด๋ž˜์Šค๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‚ฌ์šฉํ•˜๋„๋ก ํฌํ•จ์‹œ์ผฐ๋‹ค๋ฉด, ์ด ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•  ์˜๋„๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์œผ๋กœ ๋ณด๊ณ  ๊ด€๋ จ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค๋ฅผ ๋“ฑ๋ก

.

์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด ๋Œ€์ฒด

  • ์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด๋Š” ๋‹ค์Œ์˜ ๊ณผ์ •์œผ๋กœ ๋“ฑ๋ก

    • imports ํŒŒ์ผ์—์„œ ์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด ํด๋ž˜์Šค ํ›„๋ณด ๋กœ๋”ฉ

    • @Conditional ์กฐ๊ฑด ์ฒดํฌ๋ฅผ ํ†ตํ•ด ์„ ํƒ๋œ ํด๋ž˜์Šค๊ฐ€ ๋นˆ์œผ๋กœ ๋“ฑ๋ก

/**
 * ์ž๋™ ๊ตฌ์„ฑ์œผ๋กœ ๋“ฑ๋ก๋˜๋Š” ๋นˆ๊ณผ ๋™์ผํ•œ ํƒ€์ž…์˜ ๋นˆ์„ ์ง์ ‘ ์ •์˜(@Configuration/@Bean)ํ•˜๋Š” ๊ฒฝ์šฐ,
 * ์ง์ ‘ ์ •์˜ ๋นˆ ๊ตฌ์„ฑ์ด ์ž๋™ ๊ตฌ์„ฑ์„ ๋Œ€์ฒด
 */
@Configuration(proxyBeanMethods = false)
public class WebServerConfiguration {
    @Bean ServletWebServerFactory customerWebServerFactory() {
        TomcatServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
        serverFactory.setPort(9090);
        return serverFactory;
    }
}

...

/**
 * ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์˜ @Bean ๋ฉ”์†Œ๋“œ์— @ConditionalOnMissingBean ์ด ์ •์˜๋œ ๊ฒฝ์šฐ,
 * ์œ ์ € ๊ตฌ์„ฑ์— ์ง€์ •ํ•œ ํƒ€์ž…์˜ ๋นˆ์ด ์ •์˜๋˜์–ด์žˆ์œผ๋ฉด ์ž๋™ ๊ตฌ์„ฑ ๋นˆ์˜ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์ง€ ์•Š์•„ ๋“ฑ๋ก๋˜์ง€ ์•Š์Œ.
 */
@Bean("tomcatWebServerFactory")
@ConditionalOnMissingBean
public ServletWebServerFactory servletWebServerFactory() {
    return new TomcatServletWebServerFactory();
}

์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด ๋Œ€์ฒดํ•˜๊ธฐ

.

Spring Boot @Conditional

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์ž๋™ ๊ตฌ์„ฑ์€ ๋‹ค์–‘ํ•œ @Conditional ์„ ์ด์šฉ.

Class Conditions

  • @ConditionalOnClass

  • @ConditionalOnMissingClass

    โ€ข ํ”„๋กœ์ ํŠธ ๋‚ด ์ง€์ •ํ•œ ํด๋ž˜์Šค์˜ ์กด์žฌ๋ฅผ ํ™•์ธํ•ด์„œ ํฌํ•จ ์—ฌ๋ถ€ ๊ฒฐ์ •
    โ€ข ์ฃผ๋กœ @Configuration ์„ ํด๋ž˜์Šค ๋ ˆ๋ฒจ์—์„œ ์‚ฌ์šฉํ•˜์ง€๋งŒ, @Bean ๋ฉ”์†Œ๋“œ์—๋„ ์ ์šฉ ๊ฐ€๋Šฅ
    โ€ข (๋‹จ, ํด๋ž˜์Šค ๋ ˆ๋ฒจ์˜ ๊ฒ€์ฆ ์—†์ด @Bean ๋ฉ”์†Œ๋“œ์—๋งŒ ์ ์šฉํ•˜๋ฉด ๋ถˆํ•„์š”ํ•œ @Configuration ํด๋ž˜์Šค๊ฐ€ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ž˜์Šค ๋ ˆ๋ฒจ ์‚ฌ์šฉ์„ ์šฐ์„ )

Bean Conditions

  • @ConditionalOnBean

  • @ConditionalOnMissingBean

    โ€ข ๋นˆ์˜ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํฌํ•จ ์—ฌ๋ถ€ ๊ฒฐ์ •
    โ€ข ๋นˆ์˜ ํƒ€์ž… ๋˜๋Š” ์ด๋ฆ„์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ์ง€์ •๋œ ๋นˆ ์ •๋ณด๊ฐ€ ์—†์œผ๋ฉด ๋ฉ”์†Œ๋“œ์˜ ๋ฆฌํ„ด ํƒ€์ž…์„ ๊ธฐ์ค€์œผ๋กœ ๋นˆ ์กด์žฌ ์—ฌ๋ถ€ ์ฒดํฌ
    โ€ข ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋œ ๋นˆ ์ •๋ณด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ฒดํฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž๋™ ๊ตฌ์„ฑ ์‚ฌ์ด์— ์ ์šฉํ•˜๋ ค๋ฉด @Configuration ํด๋ž˜์Šค์˜ ์ ์šฉ ์ˆœ์„œ๊ฐ€ ์ค‘์š”
    โ€ข ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ •์˜ํ•œ ์ปค์Šคํ…€ ๋นˆ ๊ตฌ์„ฑ ์ •๋ณด๊ฐ€ ์ž๋™ ๊ตฌ์„ฑ ์ •๋ณด ์ฒ˜๋ฆฌ๋ณด๋‹ค ์šฐ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ด€๊ณ„์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•ˆ์ „ํ•˜์ง€๋งŒ, ๋ฐ˜๋Œ€๋กœ ์ปค์Šคํ†ฐ ๋นˆ ๊ตฌ์„ฑ ์ •๋ณด์— ์ ์šฉํ•˜๋Š” ๊ฑด ํ”ผํ•˜์ž.

@Configuration ํด๋ž˜์Šค ๋ ˆ๋ฒจ์˜ @ConditionalOnClass

@Bean ๋ฉ”์†Œ๋“œ ๋ ˆ๋ฒจ์˜ @ConditionalOnMissingBean

์กฐํ•ฉ์€ ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ์‹

ํด๋ž˜์Šค ์กด์žฌ๋กœ ํ•ด๋‹น ๊ธฐ์ˆ  ์‚ฌ์šฉ ์—ฌ๋ถ€ ํ™•์ธ โ†’ ์ปค์Šคํ…€ ๋นˆ ๊ตฌ์„ฑ ์กด์žฌ๋ฅผ ํ™•์ธํ•ด์„œ ์ž๋™ ๊ตฌ์„ฑ์˜ ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ด์šฉํ• ์ง€ ์ตœ์ข… ๊ฒฐ์ •

Property Conditions

  • @ConditionalOnProperty

    โ€ข ์Šคํ”„๋ง์˜ ํ™˜๊ฒฝ ํ”„๋กœํผํ‹ฐ ์ •๋ณด๋ฅผ ์ด์šฉ
    โ€ข ์ง€์ •๋œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜๊ณ  ๊ฐ’์ด false ๊ฐ€ ์•„๋‹ˆ๋ฉด ํฌํ•จ ๋Œ€์ƒ
    โ€ข ํŠน์ • ๊ฐ’์„ ๊ฐ€์ง„ ๊ฒฝ์šฐ๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์„ ๋•Œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋„๋ก ์„ค์ • ๊ฐ€๋Šฅ
    โ€ข ํ”„๋กœํผํ‹ฐ์˜ ์กด์žฌ๋ฅผ ํ™•์ธํ•ด์„œ ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ํ•ด๋‹น ๋นˆ ์˜ค๋ธŒ์ ํŠธ์—์„œ ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ์ด์šฉํ•ด์„œ ์„ธ๋ฐ€ํ•˜๊ฒŒ ๋นˆ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ

Resource Conditions

  • @ConditionalOnResource

    โ€ข ์ง€์ •๋œ ๋ฆฌ์†Œ์Šค(ํŒŒ์ผ) ์กด์žฌ ํ™•์ธ

Web Application Conditions

  • @ConditionalOnWebApplication

  • @ConditionalOnNotWebApplication

    โ€ข ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์—ฌ๋ถ€ ํ™•์ธ
    โ€ข ex. ์›น ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฐฐ์น˜

SpEL Expression Conditions

  • @ConditionalOnExpression

    โ€ข ์Šคํ”„๋ง SpEL(์Šคํ”„๋ง ํ‘œํ˜„์‹) ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ ๊ธฐ์ค€์œผ๋กœ ํŒ๋‹จ
    โ€ข ๋งค์šฐ ์ƒ์„ธํ•œ ์กฐ๊ฑด ์„ค์ • ๊ฐ€๋Šฅ

์™ธ๋ถ€ ์„ค์ •์„ ์ด์šฉํ•œ ์ž๋™ ๊ตฌ์„ฑ

์Šคํ”„๋ง์˜ Environment ์ถ”์ƒํ™”

Result
Environment.getProperty("property.name")

Environment ํƒ€์ž…์˜ ์˜ค๋ธŒ์ ํŠธ๋ฅผ ๊ฐ€์ ธ์™€์„œ ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์„ ์ œ๊ณตํ•˜์—ฌ ์„ค์ •๊ฐ’ ์กฐํšŒ

  • ํ”„๋กœํผํ‹ฐ ์šฐ์„ ์ˆœ์œ„

    • ServletConfig Parameters

    • ServletContext Parameters

    • JNDI

    • System Properties

    • System Environment Variables

    • @PropertySource

    • xml, yml

  • ์ œ๊ณต๋˜๋Š” ํ”„๋กœํผํ‹ฐ ์ด๋ฆ„์„ ๋ณ€ํ˜•ํ•ด์„œ ์„ค์ •๊ฐ’ ํƒ์ƒ‰

    • property.name

    • property_name

    • PROPERTY.NAME

    • PROPERTY_NAME

.

์ž๋™ ๊ตฌ์„ฑ์— Environment ํ”„๋กœํผํ‹ฐ ์ ์šฉ

@Bean("tomcatWebServerFactory")
@ConditionalOnMissingBean
public ServletWebServerFactory servletWebServerFactory(Environment env) {
  TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
  factory.setContextPath(env.getProperty("contextPath"));
  return factory;
}
  • ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์˜ ๋ฉ”์†Œ๋“œ์— Environment ๋ฅผ ์ฃผ์ž… ๋ฐ›์•„์„œ ๋นˆ ์†์„ฑ์œผ๋กœ ์ง€์ •ํ•  ํ”„๋กœํผํ‹ฐ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ

.

@Value

  • @Value ๋Š” element ๋กœ placeholder(์น˜ํ™˜์ž)๋ฅผ ์ง€์ •ํ•˜๊ณ  ์ปจํ…Œ์ด๋„ˆ ์ดˆ๊ธฐํ™”์‹œ ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ ์ด๋ฅผ ๋Œ€์ฒด

  • ์น˜ํ™˜์ž๋ฅผ ํ”„๋กœํผํ‹ฐ ๊ฐ’์œผ๋กœ ๊ต์ฒดํ•˜๋ ค๋ฉด PropertySourcesPlaceholderConfigurer ํƒ€์ž…์˜ ๋นˆ ๋“ฑ๋ก ํ•„์š”

    • ํŒฉํ† ๋ฆฌ์˜ ํ›„์ฒ˜๋ฆฌ๊ธฐ๋กœ ๋™์ž‘ํ•ด์„œ ์ดˆ๊ธฐ ๊ตฌ์„ฑ ์ •๋ณด์—์„œ ์น˜ํ™˜์ž๋ฅผ ์ฐพ์•„์„œ ๊ต์ฒดํ•˜๋Š” ๊ธฐ๋Šฅ ๋‹ด๋‹น

@MyAutoConfiguration
public class PropertyPlaceholderConfig {
    @Bean
    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

.

ํ”„๋กœํผํ‹ฐ ํด๋ž˜์Šค์˜ ๋ถ„๋ฆฌ

.

ํ”„๋กœํผํ‹ฐ ๋นˆ์˜ ํ›„์ฒ˜๋ฆฌ๊ธฐ ๋„์ž…

Spring JDBC ์ž๋™ ๊ตฌ์„ฑ ๊ตฌํ˜„

์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์™€ ๋นˆ ์„ค๊ณ„

  • ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์˜ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์— ์ ์šฉํ•  ์กฐ๊ฑด๊ณผ ๋งŒ๋“ค์–ด์ง€๋Š” ๋นˆ ์˜ค๋ธŒ์ ํŠธ ์ข…๋ฅ˜ ๋“ฑ์„ ๋จผ์ € ์„ค๊ณ„

Result
  • ๋‘ ๊ฐœ์˜ DataSource ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋“ฑ๋ก

    • DataSourceProperties ํ”„๋กœํผํ‹ฐ ํด๋ž˜์Šค ์ด์šฉ

.

DataSource ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค

  • @TestPropertySource

    • application.properties ํŒŒ์ผ ๋“ฑ๋ก์€ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ ๊ธฐ๋ณธ ๋™์ž‘ ๋ฐฉ์‹์ด ์•„๋‹˜

    • ์Šคํ”„๋ง ๋ถ€ํŠธ ์ดˆ๊ธฐํ™” ๊ณผ์ •์—์„œ ์ถ”๊ฐ€ํ•ด ์ฃผ๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ํ…Œ์ŠคํŠธ์—์„œ ๋ณ„๋„ ์ถ”๊ฐ€ ํ•„์š”

    • @TestPropertySource("classpath:/application.properties") ๋กœ properties ์ •๋ณด๋ฅผ ์ฝ์–ด์˜ค๋„๋ก ์„ค์ •

.

JdbcTemplate๊ณผ ํŠธ๋žœ์žญ์…˜ ๋งค๋‹ˆ์ € ๊ตฌ์„ฑ

  • @ConditionalOnSingleCandidate

    • ๋นˆ ๊ตฌ์„ฑ์ •๋ณด์— ํ•ด๋‹น ํƒ€์ž… ๋นˆ์ด ํ•œ ๊ฐœ๋งŒ ๋“ฑ๋ก๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ ์กฐ๊ฑด ๋งค์นญ

  • @EnableTransactionManagement

    • ์• ๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•˜๋Š” ํŠธ๋žœ์žญ์…˜ ๊ธฐ๋Šฅ์„ ์ด์šฉ

.

Hello Repository

์ธํ„ฐํŽ˜์ด์Šค์— default, static ๋ฉ”์†Œ๋“œ๋ฅผ ๋„ฃ์–ด์„œ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€

์ž๋ฐ”์˜ Comparator<T> ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ฐธ๊ณ ํ•ด ๋ณด์ž.

Spring Boot

์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ์ž๋™ ๊ตฌ์„ฑ๊ณผ ํ…Œ์ŠคํŠธ

  • @SpringBootApplication

    • Spring Boot Main Annotation

  • @JdbcTest

    • Spring Boot Test ์ค€๋น„

    • ์ž๋™๊ตฌ์„ฑ ์ค‘ JDBC ๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋นˆ๋“ค๋งŒ ๋กœ๋”ฉ โž” ๋น ๋ฅธ ํ…Œ์ŠคํŠธ

    • embedded db ๋กœ dataSource ๊ต์ฒด โž” ํ”„๋กœํผํ‹ฐ๋กœ ์„ค์ •ํ•œ DB ์ ‘์† ์ •๋ณด ์‚ฌ์šฉ X

  • @SpringBootTest

    • ์Šคํ”„๋ง ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋„์šฐ๊ณ  ์ž๋™ ๊ตฌ์„ฑ๊นŒ์ง€ ์ ์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ

    • ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ ์—ฌ๋ถ€ ์„ค์ •

      • ์›น ํ™˜๊ฒฝ ์„ธํŒ… ์ œ์™ธ: webEnvironment = SpringBootTest.WebEnvironment.NONE

      • ์›น ํ™˜๊ฒฝ ์„ธํŒ…: webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT

.

์Šคํ”„๋ง ๋ถ€ํŠธ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ธฐ

Result
  • ์Šคํ”„๋ง ๋ถ€ํŠธ์˜ ๋™์ž‘ ๋ฐฉ์‹ ์ดํ•ด

  • ์‚ฌ์šฉ ๊ธฐ์ˆ ๊ณผ ๊ด€๋ จ๋œ ์ž๋™ ๊ตฌ์„ฑ ๋นˆ๊ณผ ๊ตฌ์„ฑ, ์†์„ฑ, ํ”„๋กœํผํ‹ฐ ์„ค์ • ๋“ฑ์„ ๋ถ„์„

    • ์ž๋™ ๊ตฌ์„ฑ ๋นˆ๊ณผ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๋นˆ ์„ ํƒ ๊ธฐ์ค€

  • ์ด๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํŒŒ์•…

.

์ž๋™ ๊ตฌ์„ฑ ๋ถ„์„ ๋ฐฉ๋ฒ•

์ž๋™ ๊ตฌ์„ฑ ํ›„๋ณด ๋ชฉ๋ก๊ณผ ์กฐ๊ฑด ํŒ๋‹จ ๊ฒฐ๊ณผ ์กฐํšŒํ•˜๊ธฐ

Result
  • -Ddebug or --debug ์ธ์ž๋ฅผ ์ด์šฉํ•ด์„œ ์Šคํ”„๋ง ๋ถ€ํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰

  • ConditionEvaluationReport ํƒ€์ž…์˜ ๋นˆ์„ ์ฃผ์ž… ๋ฐ›๊ณ , ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ์„ ํƒํ•ด์„œ ์ž๋™ ๊ตฌ์„ฑ ๊ฒฐ๊ณผ ํ™•์ธ

  • ListableBeanFactory ํƒ€์ž…์˜ ๋นˆ์„ ์ฃผ์ž… ๋ฐ›๊ณ , ๋นˆ ์ด๋ฆ„์„ ๊ฐ€์ ธ์™€์„œ(ํ•„์š” ์‹œ ๋นˆ ์˜ค๋ธŒ์ ํŠธ๋„) ๋“ฑ๋ก๋œ ๋นˆ ๋ชฉ๋ก ํ™•์ธ

  • ์ž๋™ ๊ตฌ์„ฑ ์„ ์ • ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์Šคํ”„๋ง ๋ถ€ํŠธ ๋ ˆํผ๋Ÿฐ์Šค ๋ฌธ์„œ, ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค ์†Œ์Šค ์ฝ”๋“œ, ํ”„๋กœํผํ‹ฐ ํด๋ž˜์Šค, Customizer ๋“ฑ์„ ์‚ดํŽด๋ณด๋ฉฐ ์–ด๋–ป๊ฒŒ ์–ด๋–ค ์กฐ๊ฑด์œผ๋กœ ๋™์ž‘ํ• ์ง€ ๋ถ„์„

VM options: -Ddebug

Positive matches:
-----------------

   AopAutoConfiguration matched:
      - @ConditionalOnProperty (spring.aop.auto=true) matched (OnPropertyCondition)

   AopAutoConfiguration.ClassProxyingConfiguration matched:
      - @ConditionalOnMissingClass did not find unwanted class 'org.aspectj.weaver.Advice' (OnClassCondition)
      - @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)

   ApplicationAvailabilityAutoConfiguration#applicationAvailability matched:
      - @ConditionalOnMissingBean (types: org.springframework.boot.availability.ApplicationAvailability; SearchStrategy: all) did not find any beans (OnBeanCondition)

...

Negative matches:
-----------------

   ActiveMQAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

   AopAutoConfiguration.AspectJAutoProxyingConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.aspectj.weaver.Advice' (OnClassCondition)

   ArtemisAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory' (OnClassCondition)

...

ConditionEvaluationReport

  • ์กฐ๊ฑด์ด ๋งค์นญ๋œ ์ž๋™ ๊ตฌ์„ฑ ํด๋ž˜์Šค์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ์ถœ๋ ฅ

@Bean
ApplicationRunner run(ConditionEvaluationReport report) {
    return args -> {
        long result = report.getConditionAndOutcomesBySource().entrySet().stream()
                .filter(co -> co.getValue().isFullMatch()) // ์ปจ๋””์…˜ ์กฐ๊ฑด์„ ๋ชจ๋‘ ํ†ต๊ณผํ•œ ๋นˆ ๋ชฉ๋ก
                .filter(co -> co.getKey().indexOf("Jmx") < 0) // Jmx ๊ด€๋ จ ๊ตฌ์„ฑ ์ •๋ณด ์ œ์™ธ
                .map(co -> {
                    System.out.println(co.getKey());
                    co.getValue().forEach(c -> {
                        System.out.println("\t" + c.getOutcome()); // ์ปจ๋””์…”๋„ ํ†ต๊ณผ ์กฐ๊ฑด
                    });
                    System.out.println();
                    return co;
                }).count();

        System.out.println(result);
    };
}

org.springframework.boot:spring-boot-starter (springboot core)

  • spring boot code ์—์„œ Jmx ์ œ์™ธ ๋นˆ์ด ๋ชฉ๋ก

.

org.springframework.boot:spring-boot-starter-web

  • spring boot web ์—์„œ Jmx ์ œ์™ธ ๋นˆ ๋ชฉ๋ก

org.springframework.boot:spring-boot-starter-jdbc

  • jdbc ๊ด€๋ จ ๋นˆ ๋ชฉ๋ก

Last updated