Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
관리 메뉴

dearbeany

[Spring] Spring DI 종합실습1~3. JDBC 를 Spring 프로젝트로 바꾸기 | AOP 본문

Spring

[Spring] Spring DI 종합실습1~3. JDBC 를 Spring 프로젝트로 바꾸기 | AOP

dearbeany 2022. 10. 12. 10:48

라이브러리 추가한 코드 pom.xml

<dependencies>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.3.18</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.3.18</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.28</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-dbcp2</artifactId>
			<version>2.9.0</version>
		</dependency>
</dependencies>

 

 

 

1. service와 dao의 관점분리 

service : '기능'에 집중 ex. getBoardList() → 데이터를 모두 가져오고 selectAll, 데이터를 가공해서 게시물 리스트를 보여줄 수도 있음

dao(data access object) : '데이터' 읽고 쓰기  ex. selectAll()

→ 둘은 관점이 다르다.

→ service 기능을 구현하기 위해 dao(기능을 위한 재료)를 사용한다. service가 dao를 의존 한다.

public class BoardServiceImpl implements BoardService {
	private BoardDao boardDao;
	public BoardServiceImpl(BoardDao boardDao) {
		this.boardDao = boardDao;
	}

→ BoardService 인터페이스를 implements한 BoardServiceImpl를 만드는데, 얘가 직접 sql을 날리는 게 아니라 dao가 날리도록 하고, 이러한 dao에 의존하도록 하자. 그렇다면 BoardDao를 가지고 있어야 한다. 단 BoardDaoImpl이 아니라, BoardDao의 객체를 가져야 보다 느슨한 결합. (인터페이스에 의존)

 

 

 

2. 객체 등록 및 의존관계 설정

- 스프링컨테이너(applicationContext.xml)에 service를 bean등록해주고 의존관계 설정한다.

	<bean class="com.ssafy.model.service.BoardServiceImpl" id="boardServiceImpl">
		<constructor-arg name="boardDao" ref="boardDao"></constructor-arg>
	</bean>

 

 

 

3. Test 실행

- 스프링 컨테이너 빌드, service의 객체 getBean()으로 가져오고, service의 객체로 함수 호출(getBoardList)하면 실행된다. (dao 객체 따로, service 객체 따로)

public class Test {
	public static void main(String[] args) {
		// Spring 컨테이너 빌드
		ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
		BoardService boardService = context.getBean("boardService", BoardService.class);
		for (Board b : boardService.getBoardList()) {
			System.out.println(b);
		}

 

4. 제어의 역전으로 의존관계는 모두 스프링컨테이너에서 관리한다.

 

 

5. DBUtil을 없애보자.

- util은 DB와 연결하는 역할. util.getConnection() 하는데, DB와 연결할 때마다 connection 얻어오고 끊을 때마다  리소스낭비가 큼.

- 그러면 한 번 연결해놓고 계속 써야하나? No 이것도 낭비가 크다.

 

 

 

 

6. 커넥션 풀을 사용하자.

- 상황에 맞게 효율적으로 Connection의 개수를 자동으로 관리한다. 필요하면 더 만들고, 필요 없으면 줄이고..

 

→ 커넥션 풀 사용하더라도 ①Mysql 드라이버 클래스명 ②DB연결을 위한 url ③username ④userpwd 정보는 필요하다.

→ 커넥션 풀은 이러한 정보들로 이뤄진 자바의 규격인 DataSource에 의존한다.

DB와 연결을 위해 사용하자. 이제부터는 DBUtil을 직접 구현하는 게 아니라, DBUtil과 비슷한 역할을 하는 클래스를 컨테이너에 등록하고 그를 ds에 생성자주입해주자.

public class BoardDaoImpl implements BoardDao {
	private DataSource ds;
	public BoardDaoImpl(DataSource ds) {
		this.ds = ds;
	}
}

현재 dao는 DataSource라는 인터페이스에 의존한다. (인터페이스에 의존 → 느슨한 결합 )

 

<bean class="com.ssafy.board.model.dao.BoardDaoImpl" id="boardDao">
	<constructor-arg name="ds" ref="DataSource를 구현한 클래스의 객체"></constructor-arg>
</bean>
<bean class="com.ssafy.board.model.service.BoardServiceImpl" id="boardService">
	<constructor-arg name="boardDao" ref="boardDao"></constructor-arg>
</bean>

스프링프레임워크에 DataSource를 implements한 객체가 존재한다. spring-jdbc 라이브러리를 추가한다.

 

<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
   	<property name="url" value="jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC"></property>
	<property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
</bean>
	
<bean class="com.ssafy.board.model.dao.BoardDaoImpl" id="boardDao">
	<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<bean class="com.ssafy.board.model.service.BoardServiceImpl" id="boardService">
	<constructor-arg name="boardDao" ref="boardDao"></constructor-arg>
</bean>

dataSoruce는 DB와 연결된 것에 집중(DBUtil 역할)

dao는 SQL 날리고 그 결과를 조회하는 것에 집중

service는 기능에만 집중

 

 

<bean class="org.apache.commons.dbcp2.BasicDataSource" id="dataSource">
	<property name="url" value="jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC"></property>
	<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
	<property name="username" value="root"></property>
	<property name="password" value="root"></property>
	<property name="initialSize" value="5"></property>
</bean>

 

 

*AOP(Aspect Oriented Programming) : 관점 지향 프로그래밍

- 수평으로 공통점을 끌어오는 느낌. 모듈화

- 관점 : 어떤 기능을 구현할 것인지에 대한 주제 ex) 로깅, 보안, 트랜잭션 처리..

- 모두 관점이라는 단위로 쪼개놓고 여러 관점에 걸쳐서 넓게 적용되는 관점은 '공통 관심 사항(Cross Cutting)', 각각의 자기만의 핵심기능은 '핵심 관심사항(Core Concern)'이라고 부른다

- 공통 관심 사항에 대하여 모듈화를 하자.

→ 로깅이 예금인출, 예금송금에 다 들어간다면? 여러 기능에 걸쳐서 공통되기에 실행될 때 조립하자. 즉, 핵심관심사항과 합쳐서 실행되도록 한다.

 

cf. OOP와는 전혀 다름 - 상속, 수직으로 공통점을 끌어올리는 느낌

 

*용어정리

- Aspect : 공통 구현되는 관심사를 따로 코드로 빼서 만들어 둔 것 (조립하기 위해 따로 쪼개논 기능의 클래스) ex) 로깅을 따로 구현해 논 클래스, 보안 기능을 따로 구현해 논 클래스..

- Join Point : 공통관심사가 들어가는 시점의 후보들 ex) 메소드 호출 시점

- Pointcut : Join Point 중에서 하나를 골라서 조건을 명시해논 것. 수많은 조인포인트 중에서 지정한 포인트컷의 aspect가 조립되는 것. ex) doSomething() 함수 호출 전에 입실체크(aspect)를 before 실행하도록 Pointcut으로 설정해논다.

- Advice : 특정 조인포인트(=포인트컷)에서 aspect가  before, after를 정의해논 것

- Target : advice가 적용되고자 하는 대상

- Proxy : advice가 target에 적용돼서 만들어진 완성체 

- weaving : advice가 target에 끼어드는 동작 자체

 

*프록시 : 대행자

*jdk dynamic proxy : 동적바인딩