WIL | 22/07/31

개뉸·2022년 7월 31일
0

WIL

목록 보기
2/9
post-thumbnail

객체 중복 생성을 파하여 보자.

public class ProductService {

    public List<Product> getProducts() throws SQLException {
        ProductRepository productRepository = new ProductRepository();
				// ...
    }

    public Product createProduct(ProductRequestDto requestDto) throws SQLException {
        ProductRepository productRepository = new ProductRepository();
        // ...
    }

    public Product updateProduct(Long id, ProductMypriceRequestDto requestDto) throws SQLException {
        ProductRepository productRepository = new ProductRepository();
				// ...
    }
}		

ProductRepository productRepository = new ProductRepository();
이것이 중복된다. 계속해서 리포지토리를 빈것을 생성하는 중복이 발생한다.

public class ProductService {
    
    // 멤버 변수 선언
    private final ProductRepository productRepository;

    // 생성자: ProductService() 가 생성될 때 호출됨
    public ProductService() {
        // 멤버 변수 생성
        this.productRepository = new ProductRepository();
    }
    
    public Product createProduct(ProductRequestDto requestDto) throws SQLException {
        // 요청받은 DTO 로 DB에 저장할 객체 만들기
        Product product = new Product(requestDto);

        // 멤버 변수 사용
        this.productRepository.createProduct(product);

        return product;
    }

클래스를 하나 만들어서 거기다가 중복되는 것을 넣어버리고 공통으로 써버리자.

DI (의존성 주입)

Controller를 짜고있었다.
수정된걸 리턴하려면 Service가 필요하겠는걸?
어? DB에 저장하려면 Repository도 만들어야 하잖아...

이것은 마치 김치를 자르기 위해서 가위를 만드려는 행위와 같다.
또한 Controller, Service, Repository 에 하나씩 선언해서 사용하려다가
나중에 어디한군데를 수정하게 되면 모든곳에서 에러가 터져나올거다.
이런것을 결합이 강하다고 하여 '강한 결합' 이라고 한다.

그러지말고 자기것은 자기가 알아서 하고, 필요한놈은 키워드만 받아가게 해버리면
뭐가 수정되어도 받아간놈은
'그게 수정된건지는 나는 잘 모르겠고 거 님 키워드나 주쇼'
만 신경쓰면 된다. Controller는 Service 클래스의 service 만 받아오면 된다. 이 놈이 어떻게 만들어졌고 어디가 수정되었는지는 안중에 없다.
이런것을 결합이 느슨하다 하여 '느슨한(약한) 결합' 이라고 한다.

제어의 역전 (IoC: Inversion of Control)

결합이 약할수록 서로의 의존도가 낮아지게된다. 결국 처음의 방향성이 큰 주제에서 작은 주제로 이동하던것이, 이번에는 작은 주제(Repository) 에서 큰 주제(Controller)로 제어의 역전이 일어난다.

Bean

아 그건 알겠고, Repository 랑 Service 객체는 자기가 알아서 만들어야 한다면서.
이걸 어디다 만들어야 하냐? 애매한데.

스프링 프레임워크가 이런 객체들을 생성해두는 자리를 알아서 마련해 주신다.
Bean 이란, 스프링이 관리하는 객체.
스프링 IoC 컨테이너 라는건 '빈'을 모아둔 통. 그러니까 스프링이 마련해주신 자리다.
이곳에 객체를 생성하면 다른곳에서 이것을 가져다 쓰는데 이를 Bean 이라고 명칭한다고 생각하자.

아 그럼 IoC 컨테이너에 Bean 등록하려면 어떻게 하나요?
간단하다. 등록하고 싶은 객체의 클래스 위에
@Component
만 적어주자.

// 1. ProductService 객체 생성
ProductService productService = new ProductService();

// 2. 스프링 IoC 컨테이너에 빈 (productService) 저장
// productService -> 스프링 IoC 컨테이너

단 조건이 있다. 지정해둔 패키지 내에서만 가능하다.
@ComponentScan 에 설정해 준 packages 위치와 하위 packages 들만 가능하다는 것이다.

@Configuration
@ComponentScan(basePackages = "com.sparta.springcore")
class BeanConfig { ... }

"com.sparta.springcore" 패키지 내에서의 하위 패키지들 까지만 가능하다.
com.sparta 이거나 이보다 높은 쪽의 패키지에서는 @Component를 달아도 작동하지 않을거다.
이런 범위 설정은 @SpringBootApplication 에 default 로 설정되어 있다.

직접 객체를 생성하여 빈으로 등록 요청을 해보자.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfiguration {

    @Bean
    public ProductRepository productRepository() {
        String dbUrl = "jdbc:h2:mem:springcoredb";
        String dbId = "sa";
        String dbPassword = "";

        return new ProductRepository(dbUrl, dbId, dbPassword);
    }
}

이 Bean 을 다른녀석이 사용하려면 어떻게 하죠?
멤버변수 선언 위에 @Autowired 을 적어줌으로써 DI 가 된다.

@Component
public class ProductService {

    private final ProductRepository productRepository;

    @Autowired
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }
		
		// ...
}

빈에 저장된 productRepository 를 사용할 수 있게된다.

0개의 댓글