본문 바로가기

공부방/Spring

교육 2일차 정리

AOP 관심지향 프로그래밍


OOP의 한계를 극복하고 보완하는 프로그래밍 개념


OOP를 통한 모듈화를 사용하더라도 쉽게 분리하기 힘든 부분이 자주 발견되다. AOP에서는 이를 관심영역이라고 하며, 해당 모듈의 핵심 기능을 나타내는 부분이 핵심 관심(Core Concerns)이라고 불리며, 분리하기 힘든 부분 (공통으로 사용되는 부분)을 횡단 관심(Crosscutting Concerns)이라고 한다.


그림 설명






AOP 사용을 위한 설정


// 붉은 색으로 표시된 부분을 추가해준다.


<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"

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-3.0.xsd

http://www.springframework.org/schema/context 

        http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">


<context:component-scan base-package="com.multicampus.biz"/>

<!--  LogAdvice Bean 등록 -->

<bean id="log" class="com.multicampus.biz.common.LogAdvice"/>

<!--  AOP 설정 -->

<aop:config>

<aop:pointcut expression="execution(* com.multicampus.biz..BoardServiceImpl.*(..))" id="boardPointCut"/>

<aop:aspect ref="log">

<aop:before method="printLog" pointcut-ref="boardPointCut"/>

</aop:aspect>

</aop:config>

</beans>



설명


-- 사용자가 정의한 로그 클래스를 사용하기 위해 Bean을 등록해준다. --


<!--  LogAdvice Bean 등록 -->

<bean id="log" class="com.multicampus.biz.common.LogAdvice"/>


--  aop:pointcut 은 적용할 수식을 정의 한다. 

-- execution(* com.multicampus.biz..BoardServiceImpl.*(..)) 의 의미는 *은 리턴타입을 의미하며 모든 리턴타입을 수용하겠다는 의미이며, com.multicampus.biz..BoardServiceImpl.*은 해당 패키지의 해당 클래스안의 모든 메소드들 중에서(..) 어떤 인자를 가지든 적용하겠다는 의미이다. 만약 com.multicampus.biz..BoardServiceImpl.get*이라면  get으로 시작하는 메소드에 적용하겠다는 의미로 해석하면 된다.

-- aop:before method="printLog" pointcut-ref="boardPointCut"/> 의 의미는 printLog라는 메소드를 boardPointCut에 정의 되어있는 수식과 적용 범위를 적용하여 등록된 메소드들이 수행되기 전에(aop:before) 실행하겠다는 의미이다.


<!--  AOP 설정 -->

<aop:config>

<aop:pointcut expression="execution(* com.multicampus.biz..BoardServiceImpl.*(..))"         

                  id="boardPointCut"/>

<aop:aspect ref="log">

<aop:before method="printLog" pointcut-ref="boardPointCut"/>

</aop:aspect>

       </aop:config>




- 어노테이션을 활용한 AOP 설정

  - applicationCOntext.xml에  <aop:aspectj-autoproxy/>를 선언함으로서 aop를 어노테이션으로 수행하겠다고 선언한 

    다.


package com.multicampus.biz.common;


import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Service;


@Service

@Aspect  // Aspect = Pointcut + Advice(Before, After, Around...)

public class AroundAdvice {

@Pointcut("execution(* com.multicampus.biz..BoardServiceImpl.get*(..))")

public void boardPointcut(){} // 참조용 메서드 ( xml에서의 일종의 id 개념으로 사용)

@Around("boardPointcut()")  //@After, @Around, @Before 등등 사용가능

public Object aroudLog(ProceedingJoinPoint pjp) throws Throwable{

Object obj = null;

System.out.println("-----<호출 전 로그 출력>-------");

long start = System.currentTimeMillis();

obj = pjp.proceed();

String method = pjp.getSignature().getName();

long end = System.currentTimeMillis();

System.out.println("메소드 수행에 걸린 시간 : " + (end - start));

System.out.println(method + "() 가 호출되었습니다.");

System.out.println("-----<후출 뒤 로그 출력>-------");

return obj;

}

}



Spring JDBC 기초


-먼저 applicationContext.xml에 JDBC 사용을 위한 Bean 등록을 해준다.

  설명을 하자면 dataSource라는 이름의 빈을 생성하는데 property를 통해서 setter 메소드를 호출해주고 각각의 property값을   

  설정해준다. 이러한 방식은 1일차에 학습한 의존성 주입 방식중 세터 방식을 통한 의존성 주입이 되겠다.

  생성자를 통한 의존성 주입은 <constructor-arg value="aa"/> 방식이라는것을 잊지말고~ 무튼 jdbc 사용을 위한 bean 등록  

  은 세터 방식을 사용한다.


- 그리고 jdbcTemplate이라는 bean을 선언하고, 클래스를 등록시켜 주며, property는 앞서 선언한 dataSource를 매칭시켜준

   다.

 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>

<property name="url" value="jdbc:oracle:thin:@localhost:1521:xe"/>

<property name="username" value="hr"/>

<property name="password" value="hr"/>

</bean>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

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

</bean>



jdbcTemplate을 이용한 사용 예제



package com.multicampus.biz.board.impl;


import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.List;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.RowMapper;

import org.springframework.stereotype.Repository;


import com.multicampus.biz.board.vo.BoardVO;


@Repository

public class BoardDAOSpring {

@Autowired  //자동 의존성 주입

private JdbcTemplate spring;

// SQL 명령어들

private final String BOARD_ADD = "insert into board(seq, title, writer, content) values((select nvl(max(seq), 0)+1 from board),?,?,?)";

private final String BOARD_UPDATE = "update board set title=?, content=? where seq=?";

private final String BOARD_DELETE = "delete board where seq=?";

private final String BOARD_GET = "select * from board where seq=?";

private final String BOARD_LIST = "select * from board order by seq desc";

public void addBoard(BoardVO vo){

spring.update(BOARD_ADD,vo.getTitle(),vo.getWriter(),vo.getContent());

}

public void updateBoard(BoardVO vo){

spring.update(BOARD_UPDATE, vo.getTitle(), vo.getContent(), vo.getSeq());

}

public void deleteBoard(BoardVO vo){

spring.update(BOARD_DELETE, vo.getSeq());

}

public BoardVO getBoard(BoardVO vo){

return  spring.queryForObject(BOARD_GET, new Object[]{vo.getSeq()}, new BoardRowMapper());

}

public List<BoardVO> getBoardList(BoardVO vo){

return spring.query(BOARD_LIST, new BoardRowMapper());

}

}


class BoardRowMapper implements RowMapper<BoardVO>{


public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {

// TODO Auto-generated method stub

BoardVO board = new BoardVO();

board.setSeq(rs.getInt("SEQ"));

board.setTitle(rs.getString("TITLE"));

board.setWriter(rs.getString("WRITER"));

board.setContent(rs.getString("CONTENT"));

board.setRegDate(rs.getDate("REGDATE"));

board.setCnt(rs.getInt("CNT"));

return board;

}

}



jdbcTemplate 에서는 주로 사용하는 메소드가 3개 있다

   - update : 데이터 입력, 수정, 삭제에 사용

   - query : 실행 결과가 여러 목록으로 리턴될 때

   - queryForObject : 실행 결과가 하나의 객체일 때



query 와 queryForObject  사용을 위해서는 RowMapper를 구현한 클래스가 있어야 한다.

class BoardRowMapper implements RowMapper<BoardVO>{

public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {

// TODO Auto-generated method stub

BoardVO board = new BoardVO();

board.setSeq(rs.getInt("SEQ"));

board.setTitle(rs.getString("TITLE"));

board.setWriter(rs.getString("WRITER"));

board.setContent(rs.getString("CONTENT"));

board.setRegDate(rs.getDate("REGDATE"));

board.setCnt(rs.getInt("CNT"));

return board;

}

}


그것이 BoardRowMapper  클래스 이며 자세히 살펴보면 

class BoardRowMapper implements RowMapper<BoardVO>  라고 선언함으로서 BoardVO 객체를 Mapper에 사용하겠다고 선언하고 있으며, 무조건 추상 메소드 mapRow를 구현해야 한다.


위에서는 인자로 ResultSet rs 와 데이터 수 rowNum 을 사용하고 있으며, 만약 데이터가 여러개라면 자동으로 해당 메소드가 rowNum만큼 반복 실행되어 결과가 리턴되게 된다.


궁금하면 mapRow 메소드에 rowNum을 출력해보시길 ㅋㅋㅋ


- queryForObject 사용 방법

   - 유심히 봐야 할 부분은 Object 배열로 인자를 넘겨야 한다는 것이다!

public BoardVO getBoard(BoardVO vo){

return  spring.queryForObject(BOARD_GET, new Object[]{vo.getSeq()}, new BoardRowMapper());

}


- query 사용방법

public List<BoardVO> getBoardList(BoardVO vo){

return spring.query(BOARD_LIST, new BoardRowMapper());

}


'공부방 > Spring' 카테고리의 다른 글

교육5일차 정리  (0) 2013.03.08
교육 4일차 정리  (0) 2013.03.07
교육 3일차 정리  (0) 2013.03.06
교육 1일차 정리  (0) 2013.03.04
IoC(제어의 역전), DI(의존성 주입) 이란??  (3) 2013.02.06