[요약]
- LogConsole 클래스를 FreeBoardServiceImpl 클래스에 계속 반복 주입해야 하는데 LogConsole 클래스가 수정될 때 계속 수정해야 하니 이를 간단하게 하기 위해 AOP를 사용한다.
[과제]
- FreeBoardServiceImpl 클래스
- LogConsole 클래스
- FreeBoardServiceRun 클래스
- root-context.xml aop 설정
[내용 정리]
1. Why? (① DB 연동방식의 이해)
- DB 연결 요청 시 커넥션의 개수가 계속 증가함으로 인한 메모리 부족을 방지
- 스프링에서 설정파일로 공통관심을 묶어서 관리
공통관심(로그출력, 트랜잭션, 예외처리 등) 을 축약. 내용 변경 시 클래스만 변경할 수 있도록 수정.
[DB 연동 방식]
① JDBC(Java DataBase Connectivity)
- 자바에서 제공해주는 DB 연결 표준 API
- DB 연결 요청 시 Web Application 이 커넥션을 계속 생성
- 커넥션 개수 증가 시 DB 서버 과부하, 메모리 부족 야기

② DBCP(DataBase Connection Pool)
- Web Application 내 DB Connection을 미리 만들어 놓고 DB 요청 시 DB Connection을 대여하는 방식.
- 설정 값: 초기 Connection 개수, 최소 Connection 개수, 평소 유지되는 Connection 개수

③ JNDI(Java Naming and Directory Interface)
- 방식 DBCP와 같음 / 차이점: WAS(Web Application Server)에서 관리함.

2. Why? (② 연계된 클래스가 변경될 시 어떻게 할까?)
가. FreeBoardServiceImple 클래스 생성
@Service
public class FreeBoardServiceImpl implements BoardService {
private FreeBoardDao freeBoardDao;
@Autowired
public FreeBoardServiceImpl(FreeBoardDao freeBoardDao) {
this.freeBoardDao = freeBoardDao;
}
@Override
public void post(BoardDto boardDto) {
freeBoardDao.post(boardDto);
}
@Override
public void modify(BoardDto boardDto) {
freeBoardDao.modify(boardDto);
}
@Override
public void delete(int id) {
freeBoardDao.delete(id);
}
@Override
public List<BoardDto> getBoardList() {
return freeBoardDao.getBoardList();
}
@Override
public BoardDto getBoard(int id) {
return freeBoardDao.getBoard(id);
}
}
나. LogConsole 클래스 생성
public class LogConsole {
public void consoleLog() {
System.out.println("[로그] 로직 수행 전");
}
}
다. FreeBoardServiceImple 클래스에 LogConsole 클래스를 추가
@Service
public class FreeBoardServiceImpl implements BoardService {
private FreeBoardDao freeBoardDao;
// private LogConsole logConsole;
private LogConsoleV logConsoleV;
@Autowired
public FreeBoardServiceImpl(FreeBoardDao freeBoardDao) {
this.freeBoardDao = freeBoardDao;
this.logConsoleV = new LogConsoleV();
}
@Override
public void post(BoardDto boardDto) {
logConsoleV.consoleLogPlus();
freeBoardDao.post(boardDto);
}
@Override
public void modify(BoardDto boardDto) {
logConsoleV.consoleLogPlus();
freeBoardDao.modify(boardDto);
}
@Override
public void delete(int id) {
logConsoleV.consoleLogPlus();
freeBoardDao.delete(id);
}
@Override
public List<BoardDto> getBoardList() {
logConsoleV.consoleLogPlus();
return freeBoardDao.getBoardList();
}
@Override
public BoardDto getBoard(int id) {
logConsoleV.consoleLogPlus();
return freeBoardDao.getBoard(id);
}
}
근데 만약 LogConsole이 업그레이드 돼서 LogConsole2로 바꿔야 한다면....... 다 바꿔줘야 한다.
버전이 v3, v4, v5..... 계속 될 수록 해야 될 일들이 많아진다..
이를 해결하기 위해 위의 DB 연동방식 중 2번 DBCP를 이용하여 연결해 주고,
클래스만 교체할 수 있도록 설정해주려 한다.
3. How? (① AOP 설정 하기)
가. root-context.xml - beans 설정
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
// xmlns:aop 추가
xmlns:aop="http://www.springframework.org/schema/aop"
// 스키마에 aop와 spring-aop 추가
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
나. root-context.xml - aop 설정
// 라이브러리(jar 파일)의 클래스에는 어노테이션을 달 수 없기때문에
// bean 엘리먼트를 통해서 bean 객체를 생성하고 등록한다.-->
// springboard 폴더 안에 있는 모든 폴더를 가져옴
<context:component-scan base-package="com.bit.springboard"/>
// 기존 JDBC 방식에서는 JDBCUtill을 모든 메서드를 통해 연결해줘야 했지만,
// DBCP 방식을 이용해 JDBC Driver를 별도로 연결하지 않도록 설정해준다.
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/studydb?serverTimezone=UTC"/>
<property name="username" value="study"/>
<property name="password" value="!dkdlxl1234"/>
</bean>
<!--AOP 설정-->
<!--공통적으로 사용될 클래스를 bean으로 등록-->
<bean id="logConsole" class="com.bit.springboard.common.LogConsoleV2"/>
<!--aop:config AOP의 설정의 루트 엘리먼트-->
<aop:config>
<!--aop:pointcut 공통적인 기능이 실행될 클래스와 메소드를 지정한다.-->
<aop:pointcut id="allpointcut" expression="execution(* com.bit.springboard.service..*Impl.*(..))"/>
<!--aop:aspect 공통 기능의 메소드와 실행될 메소드를 매핑하는 작업-->
<aop:aspect ref="logConsole">
<aop:before method="consoleLogPlus" pointcut-ref="allpointcut"/>
</aop:aspect>
</aop:config>
위 AOP 설정을 상세히 살펴보면 아래 사진과 같다.
What(결과) : FreeBoardServiceRun 클래스 생성 후 실행
public class FreeBoardServiceRun {
public static void main(String[] args) {
AbstractApplicationContext factory =
new GenericXmlApplicationContext("root-context.xml");
BoardService boardService = factory.getBean("freeBoardServiceImpl", BoardService.class);
BoardDto boardDto = new BoardDto();
boardDto.setTitle("자유게시글1");
boardDto.setContent("자유게시글 1번입니다.");
// writer_id는 member 테이블의 id 컬럼을 foreign key로 가져오기 때문에
// member 테이블에 존재하는 id 값만 입력할 수 있다.
boardDto.setWRITER_ID(1);
boardService.post(boardDto);
// 게시글 수정
BoardDto modifyBoardDto = new BoardDto();
modifyBoardDto.setId(1);
modifyBoardDto.setTitle("자유게시글1 수정");
modifyBoardDto.setContent("자유시글 1번입니다.-수정됨");
modifyBoardDto.setModdate(LocalDateTime.now());
boardService.modify(modifyBoardDto);
// 게시글 삭제
boardService.delete(2);
// 게시글 목록 조회
boardService.getBoardList().forEach(board -> {
System.out.println(board);
});
// 특정 id의 게시글 하나만 조회
System.out.println(boardService.getBoard(5));
factory.close();
}
}
결과 : 시행시기를 aop:before 로 실행했기 때문에 모든 메소드 시행 전에 (LogConsole2 클래스 내용이) 실행되는 것으로 나온다.
'백엔드 > Spring Framework' 카테고리의 다른 글
AOP 에서 aspect와 advisor를 사용할 때의 차이점 / Joinpoint와 pointcut의 차이 (2) | 2024.07.14 |
---|---|
트랜잭션 처리 (0) | 2024.07.12 |
JDBC Template (0) | 2024.07.12 |
AOP(Aspect Oriented Programming) / 관점 지향 프로그래밍 / JoinPoiont 인터페이스 (0) | 2024.07.11 |
AOP(Aspect Oriented Programming) / 관점 지향 프로그래밍 / 동작 시점 (0) | 2024.07.11 |