코딩 기록들
게시판만들기 _ AOP, Transaction 본문
@Responsebody의 역할 : 객체 -> JSON으로 변경
1) 비 AJAX ->페이지 2) AJAX -> JSON --> 두 경우의 처리를 동시에 @Responsebody가 할 수 없다
-> 해결방법 : 예외가 발생한 URL이 어디인가? -> Request라는 객체가 필요함
객체를 json으로 바꿔주는 라이브러리
https://mvnrepository.com/artifact/com.google.code.gson/gson -> pom.xml에 추가
AOP
- 원래있던 코드에 실행전, 실행후 시점에 특정 코드를 실행시키는것
- 공통코드를 원래코드로 넣어주어 동작되게 함 -> AOP는 interceptor와 다른 것
- 파라미터가 무엇이든, 반환타입이 무엇이든 관계없이 알아서 처리해줌
* 위빙
- code1,2,3, a,b,c,d,e 모두 java파일이라면, 이들은 JVM 속에서 complie을 통해 .class가 되어야만 동작될수있다
- weaving(위빙) = class파일을 조작하는 파일 : .class를 조작! 이미컴파일이 끝난 파일을 조작하는 것
- 위빙을 다르게 해주는 라이브러리 : aspect.jriver ?
a
code1
b
c
code2
d
e
code3
f
* a,b,c,d,e,f 위치 : helper code
* -code1,2,3, a,b,c,d,e 모두 java파일
* Dependency 추가 https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop/3.2.4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
AOP클래스 만들기 (TimingAspect.java)
@Aspect // AOP 모듈
@Component // Spring Bean으로 생성
public class TimingAspect {
}
@Bean, @Component의 차이
- @Bean : 우리가 객체를 만들고 bean 컨테이너에 적재를 시킴
- @Component : 스프링이 찾아서 객체를 만드는것
@Pointcut
- aop를 적용할 대상을 지정
- 즉, 위빙을 해줄 대상을 찾는 일(위빙을 할 대상을 지정)
- execution() : 실행단계에서 적용할 대상을 지정
@Pointcut("execution(public * com.example.demo..service.*ServiceImpl.*(..))")
private void aroundTarget() {}
// aroundtarget() : pointcut을 주는 역할만 함
- public: public 접근제어자를 사용하는 것을 대상으로 함
- 반환타입 : * (* : 모든 반환타입을 대상으로 함)
- com.forum..service.*ServiceImpl : com.hello.forum아래에 있는 모든패키지 중에서 service패키지 내부에 있는 serviceImpl로 끝나는 모든 클래스를 대상으로 함
- .*(..) : ServiceImpl로 끝나는 모든 클래스 내부의 모든 메소드를 대상으로 함
=> ServiceImpl클래스 밑에 있는 public 모든 반환타입 메소드명()을 대상으로 Aspect를 실행함
@Around
- @Around 하나가 @Before, @After, @AfterReturning, @AfterThrowing다 포함
사용예시) 아래 코드 - 원래 실행될 메소드의 전, 후에 공통코드를 실행한다.
- ServiceImpl에 있는 메소드가 실행될 때(Pointcut대상이 실행될 때) 아래 메소드가 실행된다=weaving된 코드가 실행된다
@Around("aroundTarget()") //Around 하나가 @Before, @After, @AfterReturning, @AfterThrowing다 포함
public Object timingAdvice(ProceedingJoinPoint pjp) throws Throwable {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object result = null;
try {
result = pjp.proceed();
} catch (Throwable e) {
//serviceImpl에서 발생한 예외를 그대로 던진다.
//controller로 예외가 전달되고, 마지막으로 controllerAdvice로 예외가 전달되어
// 공통예외를 처리할 수 있기 때문
throw e;
} finally {
stopWatch.stop();
//원래 실행되어야하는 클래스
String classPath = pjp.getTarget().getClass().getName();
//원래 실행되어야하는 메소드
String methodName = pjp.getSignature().getName();
logger.debug("{}.{} 걸린시간: {}ms", classPath, methodName, stopWatch.lastTaskInfo().getTimeMillis());
}
return result;
}
Transaction
하나의 Business Logic이 완료/실패 되는 단위
- 개발자가 말하는 transaction : 하나의 업무 단위
- DA / DB가 말하는 트랜잭션 : 하나의 쿼리
ServiceImpl.java가 데이터를 Update, Insert, Delete 하는 과정에서
- 에러가 발생할 경우 : 한 트랜잭션이 처리한 모든 수정 사항을 Rollback
- 정상 처리한 경우 : 한 트랜잭션이 처리한 모든 수정 사항을 Commit
Transaction의 기본원칙 (ACID)
* 고립성 예시
- 오라클) 변경중인 쿼리에만 lock을 건다
- mysql, mariadb, sqlserver, cubrid, postgresql ) 변경중인 테이블에 lock을 건다 (=select 자체가 안된다)
Transaction 처리방법
- Repository로 구성된 Dao를 사용 할 경우 : Spring에 이미 정의된 Transaction AOP코드가 자동개입함
- (단, @Service 클래스의 메소드에 @Transactional Annotation이 정의되어야 함)
- 롤백이 필요한 부분에만 @Transactional 붙인다! (웬만하면 다 붙이게 됨)
- select만 할 경우엔 데이터변경이 없으므로 @Transactional안붙여도 됨!
- > serviceImpl 에 있는 메소드 하나하나가 하나의 업무이기 때문에 serviceImpl에 있는 함수 중 select를 제외한 함수에다가 @Transactional 어노테이션 붙여준다!