반응형

ApplicationContext가 스프링 컨테이너 이다.

public static void main(String[] args) {

    GenericApplicationContext applicationContext = new GenericApplicationContext();
    applicationContext.registerBean(HelloController.class);
    applicationContext.refresh();

    ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
    WebServer webServer = serverFactory.getWebServer(servletContext -> {

        servletContext.addServlet("frontcontroller", new HttpServlet() {
            @Override
            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

                // 인증, 보안, 다국어, 공통 기능
                if(req.getRequestURI().equals("/hello") && req.getMethod().equals(HttpMethod.GET.name())){
                    String name = req.getParameter("name");

                    HelloController bean = applicationContext.getBean(HelloController.class);

                    String ret = bean.hello(name);

                    resp.setContentType(MediaType.TEXT_PLAIN_VALUE);
                    resp.getWriter().println(ret);
                }else{
                    resp.setStatus(HttpStatus.NOT_FOUND.value());
                }
            }
        }).addMapping("/*"); // /밑으로 들어오는건 다 처리하겠다.
    });
    webServer.start();
}

Spring Container의 경우 object를 singleTon으로 유지되게끔 해준다.

 

DI 

Spring Container( Assembler )

//interface
public interface HelloService {
    String sayHello(String name);
}

//class
public class SimpleHelloService implements HelloService {
    @Override
    public String sayHello(String name){
        return "Hello " + name;
    }
}

//class
public class HelloController {

    private final HelloService helloService;

    public HelloController(HelloService helloService){
        this.helloService = helloService;
    }

    public String hello(String name){
        return helloService.sayHello(Objects.requireNonNull(name));
    }
}

//main
public static void main(String[] args) {

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

    ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
    WebServer webServer = serverFactory.getWebServer(servletContext -> {

        servletContext.addServlet("frontcontroller", new HttpServlet() {
            @Override
            protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

                // 인증, 보안, 다국어, 공통 기능
                if(req.getRequestURI().equals("/hello") && req.getMethod().equals(HttpMethod.GET.name())){
                    String name = req.getParameter("name");

                    HelloController bean = applicationContext.getBean(HelloController.class);

                    String ret = bean.hello(name);

                    resp.setContentType(MediaType.TEXT_PLAIN_VALUE);
                    resp.getWriter().println(ret);
                }else{
                    resp.setStatus(HttpStatus.NOT_FOUND.value());
                }
            }
        }).addMapping("/*"); // /밑으로 들어오는건 다 처리하겠다.
    });
    webServer.start();
}

DispatcherServlet

RequestMapping -> GetMapping, PostMapping으로 간결하게 추가

 

@RestController가 붙은 Controller는 하위 메소드들에 모두 @ResponseBody 붙인다.

//class
@RequestMapping("/hello")
public class HelloController {

    private final HelloService helloService;

    public HelloController(HelloService helloService){
        this.helloService = helloService;
    }

    @GetMapping
    @ResponseBody
    public String hello(String name){
        return helloService.sayHello(Objects.requireNonNull(name));
    }
}

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

 

아래는

Bean을 등록하는 FactoryMethod 방식

@Configuration
public class HellobootApplication {

    @Bean
    public HelloController helloController(HelloService helloService){
        return new HelloController(helloService);
    }

    @Bean
    public HelloService helloService(){ //interface 타입으로 리턴하자
        return new SimpleHelloService();
    }

    public static void main(String[] args) {

        //스프링 컨테이너
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(){
            @Override
            protected void onRefresh() {
                super.onRefresh();

                //서블릿 컨테이너
                ServletWebServerFactory serverFactory = new TomcatServletWebServerFactory();
                WebServer webServer = serverFactory.getWebServer(servletContext -> {

                    servletContext.addServlet("dispatcherServlet",
                            new DispatcherServlet(this)
                    ).addMapping("/*"); // /밑으로 들어오는건 다 처리하겠다.
                });
                webServer.start();
            }
        };
        applicationContext.register(HellobootApplication.class);
        applicationContext.refresh(); //초기화

    }

}

 

Factory 방식말고 더 간결하게 하는 방법

@ComponentScan으로 설정된 파일의 동일부터 하위까지의 @Component가 붙은 파일을 모두 Bean으로 등록한다.

메타 애노테이션이란 애노테이션 위에 애노테이션이 붙은

 

애노테이션을 만들려면

@Retention 이 필요 언제까지 살아있을것인가.

//Annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Component
public @interface MyComponent {
}

//HelloController
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    //스프링 컨테이너가 초기화 될때 실행된다. 
    System.out.println(applicationContext);
}
-> 스프링컨테이너에서 관리가 가능하면 생성자 주입도 가능하다. set메서드 삭제 후 생성자 주입변경
public HelloController(HelloService helloService, ApplicationContext applicationContext){
    this.helloService = helloService;
    this.applicationContext = applicationContext;
}

@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) {

        //스프링 컨테이너
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(){
            @Override
            protected void onRefresh() {
                super.onRefresh();

                //서블릿 컨테이너
                ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
                DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);

                //set하지 않아도 dispatcherServlet에서 setApplication을 해준다.
                dispatcherServlet.setApplicationContext(this); 

                WebServer webServer = serverFactory.getWebServer(servletContext -> {

                    servletContext.addServlet("dispatcherServlet",dispatcherServlet)
                            .addMapping("/*"); // /밑으로 들어오는건 다 처리하겠다.
                });
                webServer.start();
            }
        };
        applicationContext.register(HellobootApplication.class);
        applicationContext.refresh(); //초기화

    }

}

최종적으로

//MySpringApplication
public class MySpringApplication {
    public static void run(Class<?> applicationClass, String... args) {
        //스프링 컨테이너
        AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext(){
            @Override
            protected void onRefresh() {
                super.onRefresh();

                //서블릿 컨테이너
                ServletWebServerFactory serverFactory = this.getBean(ServletWebServerFactory.class);
                DispatcherServlet dispatcherServlet = this.getBean(DispatcherServlet.class);
                dispatcherServlet.setApplicationContext(this);

                WebServer webServer = serverFactory.getWebServer(servletContext -> {

                    servletContext.addServlet("dispatcherServlet",dispatcherServlet)
                            .addMapping("/*"); // /밑으로 들어오는건 다 처리하겠다.
                });
                webServer.start();
            }
        };
        applicationContext.register(applicationClass);
        applicationContext.refresh(); //초기화
    }
}

//HellobootApplication
@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);
	}
}

 

반응형

'인강 > 토비의 스프링부트' 카테고리의 다른 글

스프링부트 자동구성 애플리케이션  (0) 2023.02.06
스프링부트 테스트  (0) 2023.02.06
스프링부트 서블릿  (0) 2023.02.04
스프링 부트  (0) 2023.02.04