PSA , 스프링에서 PSA형식으로 되어있는 것들(인강+블로그)

Back-End/Spring 2019. 6. 8. 12:57
728x90
반응형

-PSA란??-


잘 만든 인터페이스


이식가능한 서비스 추상화


PSA를 사용하면 확장성이 좋아지고 (테스트하기 편함)


기술자체를 유동적으로 바꿔서 사용할 수 있다.


스프링이 제공하는 거의 모든 API는 PSA이다.


@Transactional 을 예로 들면


어노테이션과 그 실행 aspect 클래스가 따로 존재한다.


그 aspect는 Transaction 기술과는 독립적인 PlatformTransactionManager라는 인터페이스가 사용된 코드


PlatformTransactionManager 인터페이스의 구현체가 바뀌더라도 TransactionAspect의 코드는 바뀌지 않는다.


구현체들 중에 여러가지가 bean으로 등록 되있는 것들이 있다 ex-JPA


aspect는 Platform TransactionManager를 사용하여 코딩했기 때문에


jpaTransactionManager에서 DatasourceManager로 바뀌더라도 Transaction을 처리하는 aspect 코드는 바뀌지 않는다.


(인터페이스가 가진 기본 기능, 기본 틀은 바뀌지 않는다는 뜻)





-스프링 트랜잭션-


스프링은 코드 기반의 트랜잭션 처리 뿐 아니라 선언적 트랜잭션 (Declarative Transaction)을 지원하고 있다.


스프링이 제공하는 트랜잭션 템플릿 클래스를 이용하거나 설정 파일, 어노테이션을 이용해서 트랜잭션의


범위 및 규칙을 정의할 수 있다.



선언적 트랜잭션 처리


ㄱ. 선언적 트랜잭션은 설정파일이나 어노테이션을 이용해서 트랜잭션의 범위, 롤백 규칙 등을 정의


ㄴ. 다음과 같은 2가지 방식으로 정의함


1. <tx:advice> 태그를 이용한 트랜잭션 처리


2. @Transactional 어노테이션을 이용한 트랜잭션 설정



-예  시-

/**

     * 사업부 정보 등록,수정

     * @param map

     * @return

     * @throws Exception

     */

    @Transactional

    public int saveDivisionData(Map<String, Object> map) throws Exception {

      int cnt = companyDAO.saveDivisionData(map);

       

      // 사업부 수정이 정상적으로 처리되면 대상 사업부를 확산대상으로 지정한다.

      if(cnt == 1){

        companyDAO.saveExtensionTarget(map);

      }

      

        return cnt;

    }



@Transactional을 써주는 이유??


companyDAO.saveDivisionData 에서 처리한 쿼리문이 정상적으로 완료가 되고, companyDAO.saveextensionTarget 에서 처리 도중


에러가 났을 때 companyDAO.saveDivisionData 에서 처리한 쿼리를 자동 rollback(작업 취소) 해주기 위해 사용된다.


만약 저 어노테이션을 써주지 않는다면, 위에꺼는 정상적으로 완료가 되었기 때문에 직접 save 한 division 데이터를


복구 시켜놔야한다.


-인터페이스를 구현한 클래스로 선언된 빈은 인터페이스 메소드에 한해서 트랜잭션이 적용됨


-인터페이스에 붙은 @Transactional 선언은 인터페이스 내의 모든 메소드에 적용됨


-동시에 메소드 레벨에도 @Transactional을 지정할 수 있다. 


-클래스의 @Transaction > 인터페이스의 @Transactional


-@Transactional 적용 대상은 미리 결정하고 애플리케이션 안에서 통일하는게 좋음. 인터페이스와 클래스 양쪽


  에 불규칙하게 @Transaction이 혼용되는건 바람직하지 못하다.



context-transaction.xml 파일에 아래와 같이 선언


<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

      <property name="dataSource" ref="dataSource"/>

    </bean>

    

    <tx:advice id="txAdvice" transaction-manager="txManager">

        <tx:attributes>

            <tx:method name="select*" read-only="true" />

            <tx:method name="list*" read-only="true" />

            <tx:method name="retrieve*" read-only="true" />

            <tx:method name="get*" read-only="true" />

            <tx:method name="find*" read-only="true" />

            <tx:method name="view*" read-only="true" />

            <tx:method name="*Move" read-only="true" />

            <tx:method name="insert*" propagation="REQUIRED" />

            <tx:method name="update*" propagation="REQUIRED" />

            <tx:method name="delete*" propagation="REQUIRED"/>

            <tx:method name="save*" propagation="REQUIRED"/>

            <tx:method name="create*" propagation="REQUIRED"/>

            <tx:method name="merge*" propagation="REQUIRED"/>

            <tx:method name="execute*" propagation="REQUIRED"/>

            <tx:method name="excel*" propagation="REQUIRED"/>

            <tx:method name="CALL" propagation="REQUIRED"/>

            <tx:method name="*" rollback-for="Exception"/>

        </tx:attributes>

    </tx:advice>

    

    <aop:config>

        <aop:pointcut id="requiredTx" expression="execution(* com.????.??..impl.*Impl.*(..))"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />

    </aop:config>


<tx:annotation-driven transaction-manager="txManager" />


// @Transactional을 사용할 때 필요한 설정은 다음 한 줄 뿐이다.


<tx:annotation-driven> 태그는 등록된 빈 중에서 @Transactional이 붙은 클래스나 인터페이스 또는 메소드를 찾아


트랜잭션 어드바이스를 적용해준다.


출처: https://crosstheline.tistory.com/96 [이거 알아영???ㅎㅎㅎ]




-스프링 캐시-


  캐시란?


  복잡한 계산, DB작업, 원격 처리 결과 등을 임시 저장소인 캐시에 저장해뒀다가 동일한 요청이 들어오면


  캐시에 보관해뒀던 기존의 결과를 그대로 돌려줌



  주의할점


  1. 반복적이고 동일한 작업에만 사용 가능


  2. 캐시의 유효성 검사


  ㄱ. 공지사항이 수정되서 DB가 바뀌었는데도 계속해서 캐시의 이전내용을 보여주면 곤란


  ㄴ. 캐시의 내용이 유효하지 않은 시점이 되면 캐시에서 해당 내용을 제거해주는 작업이 필요하다.


  ㄷ. 캐시의 제거는, 주기적으로 하거나 어떤 메소드가 실행될때 캐시를 제거하도록 어노테이션을 이용해서 설정할 수 있다.




출처

https://m.blog.naver.com/PostView.nhn?blogId=kbh3983&logNo=220952478803&proxyReferer=https%3A%2F%2Fwww.google.co.kr%2F




@EnableCaching 어노테이션을 사용하면 캐시 관련된 기능이 활성화 된다.


이게 활성화되면 @Cacheable나 @CacheEvict 같은 어노테이션들을 사용할 수 있다.


그렇게 사용할려면 CacheManager가 있어야한다.  


왜냐하면 @Cacheable나 @CacheEvict을 처리하는 aspect가 어딘가에 있기 때문... 그리고 그 aspect에서는 트랜잭션 매니저를 사용한다. 


이 빈에서는 JCacheManager를 사용하고 있고, 의존성에 ehCache(원래는 JCache 였는데 이름이 바뀐거같음) 가 있다.


이 빈을 ehCacheManagerCustomizer로 바꿔주면 ehCacheManager를 쓰게 될것이고,  


그럼에도 @Cacheable, @CacheEvict를 처리하는 cacheaspect코드는 바뀔일이 없다.




추상화 웹 MVC (@Controller 과 @RequestMapping)


지금은 @Controller과 @GerMapping를 사용해서 웹 mvc를 구현

메소드에서 뷰를 리턴하면 해당이 되는 뷰를 출력함


하지만 매핑하는 값이 서블릿일수도 있고 리액티브를 쓰는것일수도 있음.

의존성을 확인하기 전까진 알지 못한다.

그렇기 때문에 매핑하는 값도 추상화로 볼 수 있다.

(즉, 기술 (Servlet, Reactive)를 바꾸어도 코드의 변경이 일어나지 않는다

그리고 테스트 하기도 더 쉽다.)







728x90
반응형
: