이번에 소개할 내용은 지난 36번 글에 이어서 AOP를 추가로 적용한 방법에 대해 소개하려고 한다.
어노테이션 방식의 트랜젝션 구축이 이해가 되지 않으면, 이전 글을 참고하면 도움이 된다.
1. [Spring-Framework] 36. Spring-JDBCTemplate - 트랜젝션 (어노테이션, Java 설정), 2020-10-10
IDE: Eclipse 2020-06
- Spring Framework 4.2.4 Releases
- Spring-JDBC
- Spring-TX
- Spring-Core
- AspeetJ Weaver
- AspectJ
DB: Oracle Databases 11g (Express Edition)
1. 프로젝트 구성도(비교)
AOP 작업을 추가한 프로젝트와 기존의 프로젝트의 구성을 비교해놓은 것이다.
이 글에서는 이전의 작성된 객체 파일을 그대로 복사 붙여넣기하여 AOP패키지에 적용하였다.
LogAdvisor.java 파일 말고는 추가 코드를 작성하진 않았다.
MainTestAOP.java도 복사, 붙여넣기해서 만든 것이다. 가리키고 있는 명칭만 변경하였다.
|
|
그림 1, 그림 2. |
그림 3, 그림 4. 이전 프로젝트 |
2. pom.xml 설정하기
((중략) - 추가된 사항)
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- AspectJWeaver 추가 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
3. LogAdvisor.java(com.website.example.aop)
package com.website.example.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;
//관점, 서비스
@Aspect
@Service
public class LogAdvisor {
// 2단계 - 전 단계 시야)
@Before("execution(* com.website.example.aop.service.AccountServiceAOP.*(..))")
// @Before("execution(public void sum())")
// 반환값 없어도 무방
public void logBefore() {
System.out.println("전 단계");
}
}
파일명: LogAdvisor.java
[첨부(Attachments)]
4. AccountServiceAOP.java(com.website.example.aop.service) - 예(복사, 붙여넣기)
코드 자체를 복사 붙여넣기 한 것이다.
AOP를 왜 하는지 철학을 이해하라고 하나 예로 보여주는 것이다.
package com.website.example.aop.service;
import java.sql.SQLException;
import com.website.example.vo.AccountVO;
public interface AccountServiceAOP {
void accountCreate(AccountVO vo) throws SQLException;
void accountTransfer(String sender, String receiver, int money) throws SQLException;
}
5. AccountServiceImplAOP.java(com.website.example.aop.service) - 예(복사, 붙여넣기)
하나 어노테이션 @Repository를 달아주었다. 그거 말고는 동일하다.
package com.website.example.aop.service;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.website.example.dao.AccountDAO;
import com.website.example.dao.AccountDAOImpl;
import com.website.example.vo.AccountVO;
@Repository
@Transactional
public class AccountServiceImplAOP implements AccountServiceAOP{
private AccountDAO accountDAO;
private DataSource ds = null;
public AccountServiceImplAOP(DataSource ds) {
this.accountDAO = new AccountDAOImpl(ds);
this.ds = ds;
}
@Override
@Transactional(propagation=Propagation.NEVER)
public void accountCreate(AccountVO vo) throws SQLException {
accountDAO.createAccount(vo);
System.out.println("create CurrentTransactionName: " + TransactionSynchronizationManager.getCurrentTransactionName());
}
@Override
@Transactional
public void accountTransfer(String sender, String receiver, int money) throws SQLException {
int balance = accountDAO.getBalance(sender); // 보내는 사람 잔액 체크
if(balance >= money){ // 보내는 돈이 잔액보다 많으면
System.out.println("transfer CurrentTransactionName: " + TransactionSynchronizationManager.getCurrentTransactionName() );
accountDAO.minus(sender, money);
accountDAO.plus(receiver, money);
} else{
System.out.println("돈 없음");
//throw new NoMoneyException();
}
}
}
6. RootConfigAOP.java(com.website.example.common) - 예(복사, 붙여넣기)
package com.website.example.common;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@Import({DBConfigAOP.class})
@ComponentScan(basePackages = {"com.website.example"})
@EnableAspectJAutoProxy
//@ComponentScan(basePackages = {"com.local.example.beans", "com.local.example.advisor"})
public class RootConfigAOP {
}
7. DBConfigAOP.java(com.website.example.common) - 예(복사, 붙여넣기)
package com.website.example.common;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.website.example.dao.AccountDAO;
import com.website.example.dao.AccountDAOImpl;
import com.website.example.aop.service.AccountServiceAOP;
import com.website.example.aop.service.AccountServiceImplAOP;
@Configuration
@EnableTransactionManagement
public class DBConfigAOP {
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public DataSource dataSource() {
DataSource dataSource = new MyDataSourceFactory().getOracleDataSource();
/* Apache DBCP
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/testDb?useUnicode=true&characterEncoding=utf8");
dataSource.setUsername("test");
dataSource.setPassword("test123!@#");
*/
return dataSource;
}
@Bean
public AccountDAO accountDAOImpl() {
AccountDAO dao = new AccountDAOImpl(dataSource());
return dao;
}
@Bean
public AccountServiceAOP accountServiceImplAOP() {
AccountServiceAOP service = new AccountServiceImplAOP(dataSource());
return service;
}
}
8. MainTestAOP.java(com.website.example.unit) - 예(복사, 붙여넣기)
package com.website.example.unit;
import java.sql.SQLException;
import java.sql.Timestamp;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.website.example.common.MyDataSourceFactory;
import com.website.example.common.RootConfigAOP;
import com.website.example.dao.AccountDAOImpl;
import com.website.example.aop.service.AccountServiceAOP;
import com.website.example.aop.service.AccountServiceImplAOP;
import com.website.example.vo.AccountVO;
class MainTestAOP {
@Test
void test() throws SQLException {
@SuppressWarnings("resource")
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfigAOP.class);
AccountServiceAOP service = (AccountServiceAOP) applicationContext.getBean("accountServiceImplAOP");
AccountVO vo = new AccountVO();
// 1. 계정 생성
vo.setName("홍길동2");
vo.setBalance(10000);
vo.setRegidate(Timestamp.valueOf("2020-01-20 11:05:20"));
service.accountCreate(vo);
// 2. 계정 생성
vo.setName("홍길자2");
vo.setBalance(0);
vo.setRegidate(Timestamp.valueOf("2020-01-20 23:05:20"));
service.accountCreate(vo);
// 3. 거래 처리
service.accountTransfer("홍길동", "홍길자", 500);
}
}
* 맺음글(Conclusion)
AOP를 쉽고 간단하게 트랜젝션과 연결해서 사용하는 방법에 대해서 소개하였다.
'소프트웨어(SW) > Spring-Framework(단종)' 카테고리의 다른 글
[Spring Framework] 39. Beans와 Context-XML 방식으로 DB 설정 그리고 Autowired - (web.xml) (2) | 2020.10.10 |
---|---|
[Spring-Framework] 38. Beans와 Context-XML 방식으로 DB 설정 - (Junit5) (2) | 2020.10.10 |
[Spring-Framework] 36. Spring-JDBCTemplate - 트랜젝션 (어노테이션, Java 설정) (1) | 2020.10.10 |
[Spring-Framework] 35. Spring-JDBCTemplate - 트랜젝션 (어노테이션 X) (1) | 2020.10.09 |
[Spring-Framework] 34. Spring JDBCTemplate - 사용하기 (2) | 2020.10.09 |