본문 바로가기

Spring Boot

20230521_스프링부트 학습

DI (의존성 주입)

 

HelloController - SimpleHelloService  

                         - ComplexHelloService

 

HelloService 라는 인터페이스를 이용해 컨트롤러가 영향받지 않도록 할수 잇음.

 

하지만 Assembler를 이용해 둘간의 관계를 만들어주어야함.  -> new 키워드를 사용하는것 대신함. 

 

어셈블러가 곧 스프링컨테이너 역할. 

 

*DispatcherServlet

public class HellobootApplication {

public static void main(String[] args) {

GenericWebApplicationContext applicationContext = new GenericWebApplicationContext();
applicationContext.registerBean(HelloController.class);
applicationContext.registerBean(SimpleHelloService.class);
applicationContext.refresh();

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

DispatcherServlet 의 사용으로 간략해진 코드.

 

@RestController를 사용하면 모든 메서드에 @ResponseBody 를 붙인 효과이다.

 

 

 

 

public class HellobootApplication {

public static void main(String[] args) {
/* 스프링 컨테이너를 코드로 등록 */
GenericWebApplicationContext applicationContext = new GenericWebApplicationContext();
applicationContext.registerBean(HelloController.class);
applicationContext.registerBean(SimpleHelloService.class);
applicationContext.refresh();

/* 서블릿 컨테이너를 코드로 실행하면서 서블릿을 등록하는 작업 */
ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
WebServer webServer = serverFactory.getWebServer(servletContext -> {
servletContext.addServlet("dispatcherServlet",
new DispatcherServlet(applicationContext)
).addMapping("/*");
});
webServer.start();
}
}

나눠진 작업을 통합해보자.

 

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();
}

};

onRefresh 라는 메서드를 사용해서 스프링컨테이너 초기화중에 서블릿컨테이너를 등록하고 실행하여 통합하였다.

 

 

 

 

@Configuration
public class HellobootApplication {
@Bean
public HelloController helloController(HelloService helloService) {
return new HelloController(helloService);
}
@Bean
public HelloService helloService() {
return new SimpleHelloService();
}

@Configuration @Bean 을 사용해 빈을 등록할수 있음.

 

더 간략하게 하는 방법은

@Configuration
@ComponentScan
public class HellobootApplication {
@RequestMapping
@Component
public class HelloController {
@Component
public class SimpleHelloService implements HelloService {

@Component

@ComponentScan

을 사용해서 빈으로 등록된 클래스를 스캔함.

 

두 방식은 장단점이 있음. 관리의 용이성은 첫번째 방식이 유리함.

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface MyComponent {
}
@RequestMapping
@MyComponent
public class HelloController {

메타에노테이션을 만들어서 커스텀해서 사용하는 방법도 존재함.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

@Controller 에노테이션은 @Component 에너테이션을 가지고 있음. @Service도 마찬가지

@RestController 는 하위 에너테이션으로 @ResponseBody를 가지고 있어서 하위 메서드에 @ResponseBody를 붙여줄 필요가 없게 되는 것이다.

 

///////////////////////////////////////////////////////////////////////////

public class MySpringApplication {
public static void run(Class<?> applicationClass, String... args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext() {
@Override
protected void onRefresh() {
super.onRefresh();

ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);

WebServer webServer = serverFactory.getWebServer(servletContext -> {
servletContext.addServlet("dispatcherServlet", dispatcherServlet)
.addMapping("/*");
});
webServer.start();
}
};
applicationContext.register(applicationClass);
applicationContext.refresh(); //스프링컨테이너 초기화
}
}
@Configuration
@ComponentScan
public class HellobootApplication {
@Bean
public ServletWebServerFactory servletWebServerFactory() {
return new TomcatServletWebServerFactory();
}

@Bean
public DispatcherServlet dispatcherServlet() {
return new DispatcherServlet();
}

public static void main(String[] args) {
MySpringApplication.run(HellobootApplication.class, args);
}

}

처음 스프링부트 프로젝트를 시작했을 때 모습과 비슷해졌다는것을 알수 있다.

 

 

##테스트코드 작성

public class HelloApiTest {
@Test
void helloApi() {
// http localhost:8080/hello?name=Spring
TestRestTemplate rest = new TestRestTemplate();

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

// status code 200
Assertions.assertThat(res.getStatusCode()).isEqualTo(HttpStatus.OK);
//header(content-type) text/plain
Assertions.assertThat(res.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE)).startsWith(MediaType.TEXT_PLAIN_VALUE);
//body Hello Spring
Assertions.assertThat(res.getBody()).isEqualTo("Hello Spring");
}
}

 

'Spring Boot' 카테고리의 다른 글

20230604_스프링부트학습  (0) 2023.06.04
20230528_스프링부트학습  (0) 2023.05.28
20230526_스프링부트 학습  (0) 2023.05.26
스프링부트_20230520  (0) 2023.05.20
인프런_스프링부트학습_20230514  (0) 2023.05.14