Spring + Java

[Spring] 스프링은 추상화를 어떻게 적용했을까?

Stark97 2023. 11. 2. 23:26
반응형
 
 

스프링은 추상화를 어떻게 사용할까? 간단한 예시로 알아보자

📌 서론

이번 포스트는 실제로 스프링을 개발하면서 자주 사용하게 되는 기능들을 기준으로 정리하였으며 쉽게 이해하기 위해 간단한 코드로 내용을 구성하였다.

만약 추상화의 개념이 부족하다면 아래의 글을 읽어보는것을 추천한다.

 

[Spring] 추상화란 무엇인가?

자바의 "추상화"의 개념을 알아보고 스프링을 이것을 어떻게 사용하는지 알아보자 📌 서론 항상 추상화를 사용하고 있지만 누군가 "그래서 대체 추상화가 뭔데?"라고 물어볼때마다 바로바로 떠

curiousjinan.tistory.com

 

1. Java의 추상화

추상 클래스와 추상 메서드

  • Java에서는 abstract 키워드를 사용하여 추상 클래스와 추상 메서드를 정의할 수 있다. 추상 클래스는 인스턴스를 생성할 수 없고, 하나 이상의 추상 메소드를 포함할 수 있다.
public abstract class Animal {
    public abstract void makeSound();
}

 

왜 사용하는가?

  • 추상 클래스와 메서드는 상속을 통해 하위 클래스에서 구현된다. 이를 통해 공통의 로직은 상위 클래스에서 처리하고, 구체적인 로직은 하위 클래스에서 구현할 수 있다.

구체적인 예시

  • 예를 들어, Animal 클래스가 있고 이를 상속받는 Dog와 Cat 클래스가 있다고 가정해 보자. 여기서 Animal 클래스의 makeSound 메소드는 추상 메서드다.
  • Dog와 Cat 클래스에서 이 메서드를 오버라이딩하여 구체적인 소리를 출력한다.
public class Dog extends Animal {
    public void makeSound() {
        System.out.println("Woof woof");
    }
}

public class Cat extends Animal {
    public void makeSound() {
        System.out.println("Meow meow");
    }
}

 

 

2. Spring Boot에서의 추상화: 데이터 액세스 추상화

Spring Boot는 Java 기반의 웹 애플리케이션 개발을 위한 프레임워크로, 다양한 방법으로 추상화를 적용하여 개발자의 생산성을 높인다. 아래에서는 Spring Boot에서 사용되는 몇 가지 추상화 기법에 대해 상세히 설명한다.

 

Repository 패턴

  • Spring Boot에서는 JPA (Java Persistence API)를 이용하여 데이터베이스 작업을 추상화한다. JpaRepository 인터페이스를 상속받아 사용자 정의 Repository를 만들면, CRUD(Create, Read, Update, Delete) 연산을 추상화할 수 있다.
public interface UserRepository extends JpaRepository<User, Long> {
    // 사용자 정의 쿼리 메소드를 추가할 수 있습니다.
    Optional<User> findByUsername(String username);
}

 

Service Layer

  • Service 계층은 비즈니스 로직을 담당하며, Repository 계층과 Controller 계층을 연결한다. 이를 통해 Controller는 데이터베이스의 내부 로직을 몰라도 된다.
@RequiredArgsConstructor
@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User findUserById(Long id) {
        return userRepository.findById(id).orElseThrow(() -> new UserNotFoundException("User not found"));
    }
}

 

Controller Layer

  • Controller 계층은 HTTP 요청을 처리하고 응답을 반환한다. Service 계층의 메소드를 호출하여 필요한 작업을 수행한다.
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        User user = userService.findUserById(id);
        return new ResponseEntity<>(user, HttpStatus.OK);
    }

}

 

3. Spring Boot에서의 추상화: 로깅과 캐싱

로깅(Logging) 추상화

  • Spring Boot는 SLF4J (Simple Logging Facade for Java)를 통해 로깅을 추상화한다. 이를 통해 개발자는 로깅 라이브러리의 내부 구현을 몰라도 로깅을 쉽게 할 수 있다.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class LogService {

    private static final Logger logger = LoggerFactory.getLogger(LogService.class);

    public void logInfo(String message) {
        logger.info(message);
    }
}

 

데이터 소스 추상화

  • Spring Boot는 DataSource 인터페이스를 통해 데이터베이스 연결을 추상화한다. application.properties 파일에서 데이터베이스 연결 정보를 설정할 수 있다.
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=root

 

캐싱(Caching) 추상화

  • Spring Boot에서는 @Cacheable 어노테이션을 사용하여 캐싱을 추상화한다. 이를 통해 캐싱 메커니즘의 내부 구현을 몰라도 캐싱을 쉽게 적용할 수 있다.
@Service
public class ProductService {

    @Cacheable("products")
    public Product findProductById(Long id) {
        // DB 조회 등의 로직
        return product;
    }
}

 

4. Spring Boot에서의 추상화: 보안과 트랜잭션

Spring Security의 추상화

  • Spring Security는 인증과 권한 부여 등의 보안 기능을 추상화하여 제공한다. 예를 들어, @PreAuthorize 어노테이션을 사용하여 메서드 레벨에서 권한을 체크할 수 있다.
@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin")
public String getAdminPage() {

    return "Admin Page";
}

 

트랜잭션 추상화 (@Transactional)

  • Spring에서는 @Transactional 어노테이션을 사용하여 데이터베이스 트랜잭션을 추상화한다. 이를 통해 개발자는 트랜잭션의 복잡한 관리를 몰라도 된다.
@Transactional
public void createUser(User user) {

    userRepository.save(user);
    // 여기서 예외가 발생하면 위의 save 연산은 롤백됩니다.
}

 

5. Spring Boot에서의 추상화: 고급 추상화 기법

메시징 추상화

  • Spring Boot는 JmsTemplate나 RabbitTemplate 등을 통해 메시징 시스템을 추상화한다. 이를 통해 개발자는 메시징 시스템의 내부 로직을 몰라도 메시지를 송수신할 수 있다.
@RequiredArgsConstructor
@Service
public class MessageService {

    private final JmsTemplate jmsTemplate;

    public void sendMessage(String destination, String message) {

        jmsTemplate.send(destination, session -> {
            TextMessage textMessage = session.createTextMessage(message);
            return textMessage;
        });
    }
}

 

스케줄링 추상화

  • Spring Boot에서는 @Scheduled 어노테이션을 사용하여 작업 스케줄링을 추상화한다. 이를 통해 개발자는 복잡한 스케줄링 로직을 몰라도 주기적인 작업을 수행할 수 있다.
@Scheduled(fixedRate = 1000)
public void performTask() {

    // 매 초마다 이 메소드가 실행됩니다.
}

 

테스트 추상화

  • Spring Boot에서는 @MockBean이나 @WebMvcTest 등을 사용하여 테스트를 추상화할 수 있다. 이를 통해 개발자는 복잡한 테스트 환경 설정 없이도 단위 테스트나 통합 테스트를 쉽게 작성할 수 있다.
@WebMvcTest(UserController.class)
public class UserControllerTest {

    @MockBean
    private UserService userService;

    @Autowired
    private MockMvc mockMvc;

    // 테스트 코드
    @Test
    public void getUserByIdTest() throws Exception {
        User user = new User(1L, "John");
        when(userService.findUserById(1L)).thenReturn(user);

        mockMvc.perform(get("/api/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name", is("John")));
    }
}

 

에러 처리 추상화

  • Spring Boot에서는 @ControllerAdvice를 사용하여 전역 에러 처리를 추상화할 수 있다. 이를 통해 개발자는 각 컨트롤러에서 에러 처리 로직을 작성할 필요 없이, 중앙에서 에러를 효율적으로 관리할 수 있다.
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity<String> handleUserNotFound(UserNotFoundException ex) {

        return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
    }
}

 

프로파일 추상화

  • Spring Boot에서는 @Profile 어노테이션을 사용하여 환경별 설정을 추상화할 수 있다. 예를 들어, 개발 환경과 배포 환경에서 데이터베이스 설정이 다를 경우, @Profile을 사용하여 이를 쉽게 관리할 수 있다.
@Configuration
@Profile("dev")
public class DevConfig {

    @Bean
    public DataSource dataSource() {
        // 개발 환경용 데이터 소스 설정
        return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL).build();
    }
}
  • 이렇게 Spring Boot는 다양한 추상화 기법을 통해 개발자의 작업을 단순화하고 생산성을 높인다. 이러한 추상화는 개발자가 내부 로직에 신경 쓰지 않고도 빠르고 안정적인 애플리케이션을 개발할 수 있게 도와준다.

📌 마무리

이번 포스트에서는 항상 사용하면서도 잘 몰랐던 자바와 스프링의 추상화에 대해서 알아봤다. 내용이 많이 부족하지만읽어주신 분들께 감사하며 글을 마친다. 이 글을 정리하면서 다시 추상화에 대한 개념을 정립하게 되어서 많은 공부가 되었다.

반응형