DI (의존성 주입)
HelloController - SimpleHelloService
- ComplexHelloService
HelloService 라는 인터페이스를 이용해 컨트롤러가 영향받지 않도록 할수 잇음.
하지만 Assembler를 이용해 둘간의 관계를 만들어주어야함. -> new 키워드를 사용하는것 대신함.
어셈블러가 곧 스프링컨테이너 역할.
*DispatcherServlet
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 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();
}
}
나눠진 작업을 통합해보자.
@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 라는 메서드를 사용해서 스프링컨테이너 초기화중에 서블릿컨테이너를 등록하고 실행하여 통합하였다.
public class HellobootApplication {
@Bean
public HelloController helloController(HelloService helloService) {
return new HelloController(helloService);
}
@Bean
public HelloService helloService() {
return new SimpleHelloService();
}
@Configuration @Bean 을 사용해 빈을 등록할수 있음.
더 간략하게 하는 방법은
@ComponentScan
public class HellobootApplication {
@Component
public class HelloController {
public class SimpleHelloService implements HelloService {
@Component
@ComponentScan
을 사용해서 빈으로 등록된 클래스를 스캔함.
두 방식은 장단점이 있음. 관리의 용이성은 첫번째 방식이 유리함.
@Target(ElementType.TYPE)
@Component
public @interface MyComponent {
}
@MyComponent
public class HelloController {
메타에노테이션을 만들어서 커스텀해서 사용하는 방법도 존재함.
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@Controller 에노테이션은 @Component 에너테이션을 가지고 있음. @Service도 마찬가지
@RestController 는 하위 에너테이션으로 @ResponseBody를 가지고 있어서 하위 메서드에 @ResponseBody를 붙여줄 필요가 없게 되는 것이다.
///////////////////////////////////////////////////////////////////////////
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(); //스프링컨테이너 초기화
}
}
@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);
}
}
처음 스프링부트 프로젝트를 시작했을 때 모습과 비슷해졌다는것을 알수 있다.
##테스트코드 작성
@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 |