콘텐츠로 이동

2021 04 20

2021-04-20

토비의 스프링 [1장. 오브젝트와 의존관계]

    1. 개요 - 스프링이 가장 관심을 많이 두는 대상은 오브젝트 - 다양한 목적을 위해 재활용 가능한 설계 방법인 디자인 패턴, 리팩토링, 단위 테스트 등이 요구됨
  • 1.1 초난감 DAO - 1.1.1 User - 1.1.2 UserDao - 1.1.3 main()을 이용한 DAO 테스트 코드
  • 1.2 DAO의 분리 - 1.2.1 관심사의 분리 - 객체를 설계할 때 가장 염두에 둬야 할 사항은 미래의 변화 어찌 대비할 것인지 - 모든 변경과 발전은 한 번에 한 가지 관심사항에 집중해서 일어난다는 것 - 1.2.2 커넥션 만들기의 추출 - 1.2.3 DB 커넥션 만들기의 독립 - 슈퍼클래스에 기본적인 로직의 흐름을 만들고, 그 기능의 일부를 추상 메서드나 오버라이딩이 가능한 protected 메서드로 만든 뒤 서브클래스에서 이런 메서드를 필요에 맞게 구현해 사용하도록 하는 방법을 "템플릿 메서드 패턴"이라고 함 - 서브 클래스에서 구체적인 오브젝트 생성 방법을 결정하게 하는 것 "팩토리 메서드 패턴"
  • 1.3 DAO의 확장 - 1.3.1 클래스의 분리 - 클래스가 바뀔 수 있는 정보에 대해 많이 알면, 해당 구체적인 정보에 종속됨 (DIP 위반) - 1.3.2 인터페이스의 도입 - 두 개의 클래스가 서로 긴밀하게 연결되지 않게, 추상적인 느슨한 연결고리를 만들어 주자 - 외부에서 만든 오브젝트를 넘겨주자 - 1.3.3 관계설정 책임의 분리 - 1.3.4 원칙과 패턴 - 높은 응집도와 낮은 결합도로 구성하자 - 높은 응집도: 변화가 일어날 때 해당 모듈에서 변하는 부분이 크다는 것 - 낮은 결합도: 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도, 즉 느슨하게 연결된 형태를 유지하는 것이 바람직한 것
  • 1.4 제어의 역전 (IoC) - 1.4.1 오브젝트 팩토리 - 오브젝트 팩토리: 객체의 생성 방법을 결정하고, 그렇게 만들어진 오브젝트를 돌려주는 것
    public class DaoFactory {
        public UserDao userDao() {
            ConnectionMaker connectionMaker = new DConnectionMaker();
            UserDao userDao = new UserDao(connectionMaker);
            return userDao;
        }   
    }
    
    public class UserDaoTest {
        public static void main(String[] args){
            UserDao dao = new DaoFactory().userDao();
        }
    }
    
      - UserDao와 ConnectionMaker는 각각 애플리케이션의 핵심적인 데이터로직과 기술 로직을 담당
      - DaoFactory는 이런 애플리케이션의 오브젝트들을 구성하고 그 관계를 정의하는 책임을 맡고 있음
      - 애플리케이션의 컴포넌트 역할을 하는 오브젝트와 애플리케이션의 구조를 결정하는 오브젝트를 분리함
    

    - 1.4.2 오브젝트 팩토리의 활용 - 1.4.3 제어권의 이전을 통한 제어관계 역전 - 기존의 프로그램은 모든 오브젝트가 능동적으로 자신이 사용할 클래스를 결정하고, 언제 어떻게 그 오브젝트를 만들지 스스로 관장 - 즉 개발자, 사용하는 쪽에서 제어해줄 것 - 제어의 역전: 제어 흐름의 개념을 거꾸로 뒤집자! - 오브젝트가 자신이 사용할 오브젝트 선택/생성 X, 어디서 사용되는지도 모름 - 서블릿에서도 이런 흐름 있었음 - 서블릿에 대한 제어 권한을 가진 컨테이너가 적절한 시점에 서블릿 클래스의 오브젝트를 만들고, 그 안의 메서드를 호출함 - 제어권을 상위 템플릿 메서드에 넘기고, 자신은 필요할 때 호출되어 사용되도록 한다는 제어의 역전의 개념을 발견할 수 있다 - 라이브러리 VS 프레임워크 - 라이브러리: 사용하는 애플리케이션 코드가 흐름을 직접 제어 - 프레임워크: 애플리케이션 코드가 프레임워크에 의해 사용됨 - 원래 ConnectionMaker의 구현 클래스를 결정하고 오브젝트 만드는 결정권은 UserDao에 있었었음 - 근데 지금은 DaoFactory에 있음 - UserDao는 이제 수동적인 존재가 되었음 - 그냥 이제 DaoFactory가 만들어주는거 공급받아 써야함

  • 1.5 스프링의 IoC - 1.5.1 오프젝트 팩토리를 이용한 스프링 IoC - 빈: 스프링이 제어권을 가지고 직접 만들고 관계를 부여하는 오브젝트 - 스프링 컨테이너가 생성, 관계설정, 사용 등을 제어하는 제어의 역전이 적용됨 - 빈 팩토리: 빈의 생성과 관계 설정등의 제어를 담당하는 IoC 오브젝트 - 애플리케이션 컨텍스트: 빈 팩토리를 조금 더 확장한 개념으로써, 구성 요소의 제어 작업을 담당하는 IoC 엔진에 더 초점을 맞춘 것 - 빈의 생성, 관계 설정, 제어를 총괄함
    @Configuration
    public class DaoFactory {
        @Bean
        public UserDao userDao() {
            return new UserDao(connectionMaker());
        }
    
        @Bean
        public ConnectionMaker connectionMaker() {
            return new DConnection();
        }
    }
    
    public class UserDaoTest {
        public static void main(String[] args){
            //@Configuration이 붙은 자바 코드를 설정 정보로 사용하기
            ApplicationContext context = new AnnotationConfigApplicationContext(DaoFactory.class);
            //ApplicationContext에 등록된 "userDao"라는 이름의 빈을 가져오기
            //위에 보면 @Bean을 userDao라는 메서드에 붙였는데, 
            //해당 코드를 실행하면 DaoFactory의 userDao() 메서드를 호출해서 그 결과를 가져오는 것임
            UserDao dao = context.getBean("userDao", UserDao.class);
        }
    }
    

    - 1.5.2 애플리케이션 컨텍스트의 동작방식 - 애플리케이션 컨텍스트, IoC 컨테이너, 스프링 컨테이너, 빈 팩토리 다 비슷한 용어 - 애플리케이션 컨텍스트는 애플리케이션에서 IoC를 적용해 관리할 모든 오브젝트에 대한 생성과 관계 설정을 담당 - 1.5.3 스프링 IoC의 용어 정리 - 빈: 스프링이 직접 그 생성과 제어를 담당하는 오브젝트 - 빈 팩토리: 빈을 등록/생성/조회/반환/관리하는 기능 - 애플리케이션 컨텍스트: 빈 팩토리를 확장한 IoC 컨테이너. 스프링이 제공하는 각종 부가 서비스 추가로 지원 받음 - 설정 메타데이터: 애플리케이션 컨텍스트/빈 팩토리가 IoC를 적용하기 위해 사용하는 메타데이터

  • 1.6 싱글톤 레지스트리와 오브젝트 스코프 - 1.6.1 싱글톤 레지스트리로서의 애플리케이션 컨텍스트 - 애플리케이션 컨텍스트 == 싱글톤 저장하고 관리하는 싱글톤 레지스트리 - 빈은 모두 싱글턴! - Why 싱글턴? - 우선 스프링 서버용 프레임워크임 - 매 요청마다 오브젝트 생성하면 너무 느려 - 서블릿 클래스당 하나의 오브젝트만 만들고, 사용자의 요청을 담당하는 여러 스레드에서 하나의 오브젝트를 공유해 동시에 사용 - 싱글톤 레지스트리: 스프링이 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능 - 평범한 자바 클래스라도 IoC 방식의 컨테이너를 통해서 생성/관계설정/사용 등에 대한 제어권을 컨테이너에게 넘겨 손 쉽게 싱글톤 방식으로 만들어져 관리됨 - 기존 싱글턴 패턴의 자바 객체의 단점을 안 가짐 - 1.6.2 싱글톤과 오브젝트의 상태 - 멀티스레드 환경이라면, 여러 스레드가 동시에 접근해서 사용할 수 있음 - 상태 관리에 주의하자 - 무상태 방식을 추천한다! - Read Only 데이터면 인스턴스로 놔둬도 괜찮긴 함 - 1.6.3 스프링 빈의 스코프
  • 1.7 의존관계 주입(DI) - 1.7.1 제어의 역전(IoC)과 의존관계 주입 - 스프링 IoC의 대표적 동작 원리는 의존관계 주입임 - DI 컨테이너라고 더 많이 불리고 있음 - 1.7.2 런타임 의존관계 설정 - 인터페이스에 대해서만 의존관계를 만들자. - 구현 클래스와의 관계는 느슨해 지면서 변화에 영향을 덜 받는 상태 구축 가능 - 결합도 낮아짐 - 의존 오브젝트: 오브젝트가 만들어지고 나서 런타임 시에 의존 관계를 맺는 대상 - 의존 관계 주입 - 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않음. 인터페이스에 의존하자 - 런타임 시점의 의존 관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다 - 의존 관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공해줌으로써 만들어짐 - 1.7.3 의존관계 검색과 주입 - 의존 관계를 맺는 방법이 외부로 부터의 주입말고, 스스로 검색을 이용할 수도 있음 - 자신이 필요로 하는 의존 오브젝트 알아서 찾음 - 의존 관계 검색 방식에서는 검색하는 오브젝트는 자신이 스프링일 빈이 필요 없음 - 1.7.4 의존관계 주입의 응용 - DI의 장점은 관심사의 분리를 통해 얻어지는 높은 응집도에서 나온다 - 1.7.5 메소드를 이용한 의존관계 주입
  • 1.8 XML을 이용한 설정 - 1.8.1 XML 설정 - 1.8.2 XML을 이용하는 애플리케이션 컨텍스트 - 1.8.3 DataSource 인터페이스로 변환 - 자바에서는 DB 커넥션을 가져오는 오브젝트의 기능을 추상화해서 비슷한 용도로 사용할 수 있게 만들어진 DataSource 인터페이스 존재 - 1.8.4 프로퍼티 값의 주입
  • 1.9 정리 - 스프링 = "어떻게 오브젝트가 설계되고, 만들어지고, 어떻게 관계를 맺고 사용되는지에 관심갖는 프레임워크"

브라운 수업 복습 [Spring Core]

  • 배경 지식 강의 - 객체는 의존관계를 가지고, 스프링이 이 관계를 관리함 - 스프링은 개발자를 대신하여 객체를 생성/관리한다 - ChessService ==> ChessDao 1. ChessService에서 직접 ChessDao 생성 - 서비스 내에서 ChessDao 설정을 해주고 생성시켜야함 - Dao 변경 시, 서비스도 변경해야함 2. 의존 주입 받기 - Dao를 외부에서 주입해주자! - Spring Container가 이를 관리!
  • Qs. 빈으로 등록할 객체의 기준? - Ans. - 웨지: 스프링은 공통적인 부분을 처리 잘해줌, 웹 요청과 처리, Controller, Repository, Service 등은 빈으로 등록해도 되지 않을까? - 배럴: 상태가 없는 객체
  • 스프링이 객체를 관리하게 하려면.. - 객체 관리 대상 알려주기 - 빈 등록 방법 - @ComponentScan - @SpringBootApplication에 @ComponentScan 포함되어 있음 - @ComponentScan(패키지) ==> 패키지와 그의 하위 패키지들 거치면서 빈 등록 - 이게 여러개라면? - 컨테이너 여러개 생기는 건 아니야 - 중복 이름 생겨서 오류날 듯? - 컨테이너에 등록될 빈을 찾는 설정 - @Component - @Component, @Controller, @Service, @Repository - 의존성 정의 하기 - 생성자 주입 - 생성자 위에 @Autowired - 수정자 주입 (Setter) - Setter 위에 @Autowired
public class ComponentScanTest {
    /**

     * TODO: core > scan 패키지 내에 있는 클래스를 스프링 빈으로 등록하기
     */
    // 이거 스프링 어플리케이션 띄운거 아니야!
    // @SpringBootTest 어노테이션을 붙여야 띄운거야~
    @Test
    void componentScan() {
        // 스프링이 관리하고 있는 컨테이너
        ApplicationContext context = getApplicationContext();
        LineDao dao = context.getBean("lineDao", LineDao.class);
        assertThat(dao).isNotNull();

        LineService service = context.getBean("lineService", LineService.class);
        assertThat(service).isNotNull();
    }

    /**

     * HelloApplication > @SpringBootApplication 설정을 통해 이미 ComponentScan 설정되어있음
     */
    private ApplicationContext getApplicationContext() {
        //@SpringBootApplication ==> @ComponentScan으로 빈 등록된거 긁어와
        ApplicationContext context = new AnnotationConfigApplicationContext(HelloApplication.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        System.out.print("등록된 빈들: ");
        System.out.println(Arrays.toString(beanDefinitionNames));
        return context;
    }
}

/*
보다시피 참 많음
등록된 빈들: 
[org.springframework.context.annotation.internalConfigurationAnnotationProcessor, 
org.springframework.context.annotation.internalAutowiredAnnotationProcessor, 
org.springframework.context.annotation.internalCommonAnnotationProcessor, 
org.springframework.context.event.internalEventListenerProcessor, 
org.springframework.context.event.internalEventListenerFactory, 
helloApplication, 
stationConstructorService, 
stationFieldService, 
stationRepository, 
stationSetterService,
lineDao, 
lineService, 
org.springframework.boot.autoconfigure.AutoConfigurationPackages, 
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration, 
propertySourcesPlaceholderConfigurer, 
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration, 
taskExecutorBuilder, 
applicationTaskExecutor, 
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor, 
org.springframework.boot.context.internalConfigurationPropertiesBinderFactory, 
org.springframework.boot.context.internalConfigurationPropertiesBinder, 
org.springframework.boot.context.properties.ConfigurationPropertiesBeanDefinitionValidator, 
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata, 
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties, 
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration, 
defaultValidator, 
methodValidationPostProcessor, 
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration, 
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration, 
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration, 
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration, 
standardJacksonObjectMapperBuilderCustomizer,
spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties, 
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration, 
jacksonObjectMapperBuilder, 
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$ParameterNamesModuleConfiguration, 
parameterNamesModule, 
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration, 
jacksonObjectMapper, 
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration, 
jsonComponentModule, 
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration, 
stringHttpMessageConverter, 
spring.http-org.springframework.boot.autoconfigure.http.HttpProperties,
org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration, 
mappingJackson2HttpMessageConverter, 
org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration, 
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration, 
messageConverters, org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration, 
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties, 
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration, 
taskSchedulerBuilder, 
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties, 
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration, 
restTemplateBuilder, 
org.springframework.aop.config.internalAutoProxyCreator]
*/
  • 스프링 빈 같은 경우, Stateless하게 구현하도록 하자! - 스프링 빈은 싱글턴으로 등록되거든요! - 공유됩니다 인스턴스변수!
  • Layered Architecture - Web Layer - Web 요청 응답 - Service Layer - 도메인 로직들의 총괄적인 비즈니스 플로우 관리 - Repository Layer (Persistent Layer) - DB 제어
  • POJO - 스프링 설정이 가해지기 전의 객체, POJO - 순수한 자바 객체
  • Java Bean - 클래스 직렬화 - 기본 생성자 - getter,setter - 필요한 이벤트 처리 메서드 포함해야함
  • 서블릿은? - 참고 1: https://mangkyu.tistory.com/14 - 참고 2: https://kohen.tistory.com/29 - 자바를 사용하여 웹을 만들기 위해 필요한 기술 - 자바로 구현된 CGI - 서블릿 특징 - 클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션 컴포넌트 - html을 사용하여 요청에 응답 - Java Thread를 이용하여 동작 - MVC 패턴의 Controller - 동적인 페이지를 제공하기 위해 서블릿 활용 - 서블릿의 동작 1. 사용자가 URL 클릭하면 HTTP Request를 서블릿 컨테이너로 전송 2. HTTP Request를 전달받은 서블릿 컨테이너는 HttpServletRequest, HttpServletResponse 두 객체 생성 3. web.xml은 사용자가 요청한 URL을 분석해 어느 서블릿에 대해 요청을 한 것인지 찾는다 4. 해당 서블릿에서 service 메서드를 호출한 후 클라이언트의 요청종류(GET, POST)에 따라 doGet, doPost를 호출 5. doGet, doPost 메서드는 동적 페이지 생성한 후 HttpServletResponse 객체에 응답 보냄 6. 응답 끝나면 HttpServletRequest, HttpServletResponse 소멸 - 서블릿 컨테이너 - 서블릿을 관리해주는 컨테이너 (ex. Tomcat) - 클라이언트의 요청을 받아주고 응답할 수 있도록 웹 서버와 소켓을 만들어 통신 - 서블릿 컨테이너 역할 1. 웹 서버와의 통신 지원 2. 서블릿 생명주기 관리 3. 멀티쓰레드 지원 및 관리 4. 선언적인 보안 관리