Spring/about spring

[스프링 삼각형] PSA 잘 만든 인터페이스

dev_rosieposie 2023. 7. 17. 16:06

Goal 

  1. 스프링 삼각형에 대해 알아본다
  2. 스프링이 구현한 PSA에 대해 알아보자
  3. 샘플코드를 통해 PSA를 이해해본다

스프링 삼각형 

스프링을 이해하는 데는 POJO(Plain Old Java Obejct)를 기반으로 스프링 삼각형이라는 애칭을 가진 Ioc/DI, AOP, PSA라고 하는 스프링의 3대 프로그래밍 모델에 대한 이해가 필수다. 

 

이번 포스팅에서는 3대 프로그래밍 중 하나인 PSA에 관해 살펴보자

 

PSA (Portable Service Abstraction) 

이식 가능한 서비스 추상화 => 잘 만든 인터페이스 

 

PSA 적용 전

  • 나의 코드
  • 확장성이 좋지못한 코드 또는 기술에 특화되어 있는 코드

문제 

확장성이 좋지못한 코드 => 테스트가 어렵다

기술에 특화되어 있는 코드 => 어떠한 기술을 바꿀 때마다 나의 코드가 바뀌는 문제

PSA 적용 후

  • 나의 코드
  • 잘 만든 인터페이스 PSA
  • 확장성이 좋지 못한 코드 또는 기술에 특화되어 있는 코드

해결

잘 만든 인터페이스(PSA)를 사용해서 내 코드를 작성하면 테스트가 쉽고, 나의 코드 변경 없이 기술 자체를 바꾸기도 좋다

 

스프링이 제공하는 PSA 

스프링 대부분의 api

Core IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP, AOT.
Data Access Transactions, DAO Support, JDBC, R2DBC, O/R Mapping, XML Marshalling.
Web Servlet Spring MVC, WebSocket, SockJS, STOMP Messaging 등..

* 추상화(PSA)가 적용된 기술 

스프링 PSA의 예 

1.  Transaction

aop, psa의 예가 되기도 한다. @Transactional이라는 어노테이션이 붙어있으면 트랜잭션을 처리할 aspect가 어딘가에 존재하는데, 그 aspect에서는 트랜잭션 처리를 기술에 독립적인 플랫폼 PlatfromTransactionManager라는 인터페이스를 사용하여 기술을 해놓았다. 그렇기 때문에 PlatfromTransactionManager의 구현체들(JpaTransacionManager, DatasourceTransactionManager, HibernateTransactionManager)이 바뀌더라도 그 트랜잭션 aspect의 코드들은 바뀌지 않는다

@Component
@Aspect
public class LogAspect {
   Logger logger = LoggerFactory.getLogger(LogAspect.class);

   @Around("@annotation(LogExcutionTime)")
   public Object logExcutionTime(ProceedingJoinPoint joinPoint) throws Throwable{

      StopWatch stopWatch = new StopWatch();
      stopWatch.start();

      Object ret = joinPoint.proceed();

      stopWatch.stop();
      logger.info(stopWatch.prettyPrint());

      return ret;
   }
}
  • sping data jpa를 사용하고 있어 스프링부트의 자동설정에 의해서 jpa transaction manager가 기본으로 bean으로 등록이 됨
  • 그래서 트랜잭션을 처리하는 aspect는 인터페이스를 사용하였기 때문에 bean이 바뀌어도 (jpa transaction manager -> data source transaction manager) 트랜잭션을 처리하는 aspect코드는 바뀌지 않는다

2.  Cache

@Configuration(proxyBeanMethods = false)
@EnableCaching
class CacheConfiguration {

   @Bean
   public JCacheManagerCustomizer petclinicCacheConfigurationCustomizer() {
      return cm -> cm.createCache("vets", cacheConfiguration());
   }

   private javax.cache.configuration.Configuration<Object, Object> cacheConfiguration() {
      return new MutableConfiguration<>().setStatisticsEnabled(true);
   }
}
  1. @EnableCaching는 스프링프레임워크에서 온 것으로, 사용하면 캐시관련 기능이 활성화된다.
  2. 활성화되면 @Cacheable | @CacheEvict | ...와 같은 여러 애노테이션을 사용할 수 있다.
  3. 그렇게 사용하기 위해서는 CacheManager가 있어야 한다
  4. @Cacheable | @CacheEvict 을 처리하는 aspect가 어딘가에 있고 그 aspect에서는 CacheManager를 사용한다

3.  Web MVC

@GetMapping("/owners/new")
public String initCreationForm(Map<String, Object> model) {
   Owner owner = new Owner();
   model.put("owner", owner);
   return VIEWS_OWNER_CREATE_OR_UPDATE_FORM;
}
  1. 나의 코드 - controller와 getmapping을 사용해 webmvc를 구현한다
  2. /owners/new라는 요청이 들어오면 initCreationForm이라는 메소드가 호출된다
  3. 뷰 리턴을 하는데, 서블릿일 수도 있고, 리액티브 일 수도 있다.
  4. 무엇을 사용하는지 위 코드로는 알 수 없고 의존성을 확인해봐야 알 수 있다. => 추상화 (기술에 독립적으로 웹 구현체를 만듦)
  5. servlet을 로우 레벨로 사용하지 않는다 => 추상화 레이어

 

 

 

참고

스프링입문 강의 by 백기선

https://www.inflearn.com/course/lecture?courseSlug=spring&unitId=15538

코드샘플

https://github.com/spring-projects/spring-petclinic