Service

김창모·2023년 5월 27일
0

SpringBoot

목록 보기
6/19

Controller Service Repository

우리는 SOLID 원칙에 대해서 인지하였고 앞에서 Controller 클래스를 만들었다.

Controller 의 역할은 사용자 요청을 처리한 후 지정된 뷰에 모델 객체를 넘겨주는 것이였다.
여기서 SOLID 원칙 S 단일 책임 원칙에 따르면 Controller 는 자신의 역할이 명확하다.

사실 하나의 책임 이란것의 기준이 개인마다 다르고 모호할수 있다고 생각한다.
따라서 필자는 단일책임 원칙을 나름의 기준에 따라 적절히 기능을 분리하는것 이라고 생각하며
이 기능을 잘 나누는 것이 유지보수와 가독성 좋은 코드를 만들수 있다고 생각한다.

SpringMVC 에서는 클라이언트 요청에 대해 아래 세가지 단계로 나누어 처리한다.

1. Controller

사용자 요청을 처리한후 모델 객체를 뷰에 전달한다.

2. Service

알맞은 정보를 가공하여 Controller 에게 데이터를 넘긴다.
이때 알맞은 정보를 가공하는 것을 비니지스 로직을 수행,처리 한다 라고 한다.

3. Repository

Repository 는 저장소 라는 뜻을 가진 단어이다. DB에 접근하는 메서드들 사용하기 위한 인터페이스 이다.

오늘은 Service 에 대해 알아보자.

Service

service 디렉토리에 HelloService 클래스를 생성하여 @Service 어노테이션을 붙여주었다.
그리고 helloService 라는 메서드를 만들어 "Hello Service"를 반환하게 하였다.

package com.hello.hello.service;

import org.springframework.stereotype.Service;

@Service
public class HelloService {
	public String helloService() {
        return "Hello Service";
    }
}

@Service

@Service 어노테이션을 먼저 살펴보자

/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.stereotype;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;

/**
 * Indicates that an annotated class is a "Service", originally defined by Domain-Driven
 * Design (Evans, 2003) as "an operation offered as an interface that stands alone in the
 * model, with no encapsulated state."
 *
 * <p>May also indicate that a class is a "Business Service Facade" (in the Core J2EE
 * patterns sense), or something similar. This annotation is a general-purpose stereotype
 * and individual teams may narrow their semantics and use as appropriate.
 *
 * <p>This annotation serves as a specialization of {@link Component @Component},
 * allowing for implementation classes to be autodetected through classpath scanning.
 *
 * @author Juergen Hoeller
 * @since 2.5
 * @see Component
 * @see Repository
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any (or empty String otherwise)
	 */
	@AliasFor(annotation = Component.class)
	String value() default "";

}

@Service 어노테이션에도 역시나 컴포넌트 스캔을 이용한 Bean 등록을 위해 @Component 어노테이션이 포함되어있으며 Service 역할을 수행한다는 것을 한눈에 알기 쉽게 해준다.

Controller 수정

package com.hello.hello.controller;

import com.hello.hello.service.HelloService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    private final HelloService helloService;

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

    @GetMapping("/")
    public String home() {
        return "Hello World!";
    }

    @GetMapping("/helloService")
    public String helloService() {
        return helloService.helloService();
    }
}

HelloController DI

현재 우리는 컴포넌트 스캔 방식을 활용하여 HelloController 와 HelloService 를 스프링 컨테이너에 빈으로 등록해두었다.
HelloService 는 HelloController 의 필드변수 이면서 아직 초기화가 되지 않았다.
DI(의존성 주입) 에 여러 방법이 있었지만 생성자 주입 방식을 가장 추천한다고 하였었다.
HelloController 생성자에 HelloService 를 매개변수로 넣어 값을 초기화 해주면서 HelloController 의 의존성 주입을 완료한다.

이때 @RequiredArgsConstructor 어노테이션을 활용하면 필요한 생성자들을 자동으로 생성해주어 코드를 조금더 간략하게 작성할수 있다.

위의 코드를 변경해보면

@RequiredArgsConstructor

package com.hello.hello.controller;

import com.hello.hello.service.HelloService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class HelloController {

    private final HelloService helloService;

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

    @GetMapping("/")
    public String home() {
        return "Hello World!";
    }

    @GetMapping("/helloService")
    public String helloService() {
        return helloService.helloService();
    }
}

이처럼 @RequiredArgsContructor 어노테이션을 사용하여 생성자 부분의 코드를 생략하고 코드를 작성할수 있다.

Controller 에 "/helloService" 라는 URL 에 Get 요청이 들어오면 HelloService 클래스의 helloService() 메서드를 실행하여 값을 반환하도록 하였다.

이를 실행해보자.

"/helloService"

Hello Service 라는 메시지가 출력되었다.

  1. HelloController 에서 요청 받음.
  2. HelloService 로 요청 보냄.
  3. HelloService 에서 "Hello Service" Model 을 HelloController 에 반환.
  4. HelloController 에서 반환받은 값을 ResponseBody 에 담아 응답.

위의 과정을 통해 "Hello Service" 라는 메세지가 출력된 것이다.

Next

하지만 아직 우리는 무언가 데이터를 저장하거나 저장된 데이터를 불러올수는 없다.
다음번엔
DB 에서 무언가를 등록 조회 수정 삭제 하는 메서드 들을 다루는 Repository 에 대해 알아보자.

0개의 댓글