스프링 AOP
자바 은행에서 로깅을 스프링 AOP로 구현해 보자. 아래 의존성을 pom.xml에 추가한다.
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.19</version> </dependency>
TestLogger.java를 아래와 같이 작성한다.
TestLogger.java
package net.java_school.commons; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Aspect public class TestLogger { Logger logger = LoggerFactory.getLogger(this.getClass()); @AfterReturning("execution(* net.java_school.bank.BankDao.deposit(..))") public void depositLog(JoinPoint point) { Object[] a = point.getArgs(); String accountNo = (String) a[0]; Long amount = (Long) a[1]; String methodName = point.getSignature().getName(); logger.debug("{}|{}|{}", methodName, accountNo, amount); } @AfterReturning("execution(* withdraw(..)) && args(accountNo, amount)") public void withdrawLog(String accountNo, double amount) { logger.debug("WITHDRAW|{}|{}", accountNo, amount); } }
자바 소스에서 로그 관련 코드를 제거한다.
MyBankDao.java
package net.java_school.bank; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class MyBankDao implements BankDao { static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE"; static final String USER = "scott"; static final String PASSWORD = "tiger"; //중간 생략.. @Override public void deposit(String accountNo, double amount) { Connection con = null; PreparedStatement pstmt = null; String sql = "UPDATE bankaccount " + "SET balance = balance + ? " + "WHERE accountNo = ?"; try { con = getConnection(); pstmt = con.prepareStatement(sql); pstmt.setLong(1, amount); pstmt.setString(2, accountNo); pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { close(null, pstmt, con); } } @Override public void withdraw(String accountNo, double amount) { Connection con = null; PreparedStatement pstmt = null; String sql = "UPDATE bankaccount " + "SET balance = balance - ? " + "WHERE accountNo = ?"; try { con = getConnection(); pstmt = con.prepareStatement(sql); pstmt.setLong(1, amount); pstmt.setString(2, accountNo); pstmt.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { close(null, pstmt, con); } } //중간 생략.. }
XML 설정
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy /> <bean id="testLogger" class="net.java_school.commons.TestLogger" /> <bean id="bankUi" class="net.java_school.bank.BankUi"> <property name="stream" value="#{T(System).out}" /> <property name="bank" ref="myBank" /> </bean> <bean id="myBank" class="net.java_school.bank.MyBank"> <property name="dao" ref="myBankDao" /> </bean> <bean id="myBankDao" class="net.java_school.bank.MyBankDao"> </bean> </beans>
테스트하기 전에 BankUi.java의 메인 메소드를 아래를 참조해 수정한다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //XML //AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class); //JavaConfig
JavaConfig 설정
BankConfig.java
package net.java_school.bank; import net.java_school.commons.TestLogger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy public class BankConfig { @Bean public TestLogger testLogger() { return new TestLogger(); } @Bean public BankDao myBankDao() { return new MyBankDao(); } @Bean public Bank myBank() { Bank bank = new MyBank(); bank.setDao(myBankDao()); return bank; } @Bean public BankUi bankUi() { BankUi ui = new BankUi(); ui.setBank(myBank()); ui.setStream(System.out); return ui; } }
테스트하기 전에, applicationContext.xml 설정을 모두 주석 처리한다. BankUi.java의 메인 메소드를 아래를 참조해 수정한다.
//ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //XML AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class); //JavaConfig
최종 소스
https://github.com/kimjonghoon/aop
참고