1. REST(Representational State Transfer)란?



- HTTP URI + HTTP Method이다.

- HTTP URI를 통해 제어할 자원(Resource)을 명시하고 HTTP Method(GET, POST, PUT, DELETE)를 통해

해당 자원(Resource)를 제어하는 명령을 내리는 방식의 아키텍쳐이다.




2. RESTful API란?




RESTful API는 HTTP와 URI기반으로 자원에 접근할 수 있도록 

제공하는 애플리케이션 개발 인터페이스(REST의 원리를 따르는 시스템은 RESTful이라고 지칭된다.)




3. 기존의 웹 접근방식과 RESTful API 방식과의 차이점




 종류

 방식

 기존게시판

 방식

 Restful API 지원하는 게시판

 긁읽기

 GET

 /list.do?no=100&name=java

 GET

 /bbs/java/100

 글등록

 POST

 /insert.do

 POST

 /bbs/java/100

 글삭제

 GET

 /delete.do?no=100&name=java

 DELETE

 /bbs/java/100

 글수정

 POST

 /update.do

 PUT

 /bbs/java/100



- 기존의 게시판은 GET, POST만 자원에 대한 CRUD처리하며 URI는 액션을 나타낸다.

- RESTful 게시판은 GET, POST, PUT, DELETE를 모두 사용하여 CRUD를 처리하며 URI는 제어하려는 자원을 나타낸다.





1. MVC(Model-View-Controller) 패턴의 개념



모델-뷰-컨트롤러(Model-View-Controller, MVC)는 소프트웨어 공학에서 사용되는 

아키텍처 패턴으로 MVC 패턴의 주목적은 business logic과 presentation logic을 분리하기 위함이다.


MVC 패턴을 사용하면, 사용자 인터페이스로부터 비즈니트 로직을 분리하여 애플리케이션의 시각적 요소나

그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠수 있는 애플리케이션을 만들수 있다.


- Model : 애플리케이션의 정보(데이터, Business Logic 포함)

- View : 사용자에게 제공할 화면(Presentation Logic)

- Controller : Model과 View 사이의 상호 작용을 관리




2. MVC 컴포넌트의 역할



1. 모델(Model) 컴포넌트


- 데이터 저장소(db)와 연동하여 사용자가 입력한 데이터나 사용자에게 출력할 데이터를 다루는 일을 한다.

- 여러개의 데이터 변경 작업(추가, 변경, 삭제)을 하나의 작업으로 묶는 트랜젝션을 다루는 일도 한다.

- DAO 클래스, Service 클래스에 해당한다.




2. 뷰(View) 컴포넌트


- 모델이 처리한 데이터나 그 작업 결과를 가지고 사용자에게 출력할 화면을 만드는 일을 한다.

- 생성된 화면은 웹 브라우저가 출력하고, 뷰 컴포넌트는 HTML, CSS, JS로 웹브라우저가 출력할 UI를 만든다.

- HTML, JSP 등이 사용된다.




3. 컨트롤러(Controller) 컴포넌트


- 클라이언트의 요청을 받았을 떄 그 요청에 대해 실제 업무를 수행하는 모델 컴포넌트를 호출하는 일을 한다.

- 클라이언트가 보낸 데이터가 있다면, 모델을 호출할 때 전달하기 쉽게 데이터를 적절히 가공하는 일을 한다.

- 모델이 업무 수행을 완료하면, 그 결과를 가지고 화면을 생성하도록 뷰에 전달한다.

- Servlet과 JSP를 사용하여 작성할수 있다.



3. 모델1,2, FrontController 아키텍처


- 모델 1 아키텍처 : Controller 역할을 JSP가 담당한다.

- 모델 2 아키텍처 : Controller 역할을 Servlet이 담당한다.



- FrontController 패턴 아키텍처




- Front Controller는 클라이언트가 보낸 요청을 받아서 공통적인 작업을 먼저 수행한다.

- Front Controller는 적절한 세부 Controller에게 작업을 위임한다.

- 각각의 애플리케이션 Controller는 클라이언트에게 보낼 뷰를 선택해서 최종 결과를 생성한다.

- Front Controller 패턴은 인증니나 권한 체크처럼 모든 요청에 대하여 공통적으로 처리해야 하는

로직이 있을 경우 전체적으로 클라이언트의 요청을 중앙 집중적으로 관리하고자 할 경우에 사용한다.



4. Spring MVC의 특징



- Spring은 DI나 AOP 같은 기능뿐만 아니라, 서블릿 기반의 웹 개발을 위한 MVC 프레임워크를 제공한다.

- Spring MVC는 모델2 아키텍처와 Front Controller 패턴을 프레임워크 차원에서 제공한다.

- Spring MVC 프레임워크는 Spring을 기반으로 하고 있기 때문에 Spring이 제공하는 트랜젝션 처리나 DI, AOP등을 손쉽게 사용한다.

- 대부분의 MVC 프레임워크들은 Front COntroller 패턴을 적용해서 구현한다.

- Spring MVC도 Front Controller 역할을 하는 DispatherServlet 이라는 클래스를 계층의 맨 앞단에 놓고, 

서버로 들어오는 모든 요청을 받아서 처리하도록 구성한다.

- 예외가 발생했을 때 일관된 방식으로 처리하는 것도 Front Controller의 역할이다.



5. DipatcherServlet 클래스


- Front Controller 패턴 적용했다.

- web.xml에서 설정한다.

- 클라이언트로부터의 모든요청을 전달 받는다.

- Controller나 View와 같은 Spring MVC의 구성요소를 이용하여 클라이언트에게 서비스를 제공한다.




1. Spring MVC 처리과정 및 구성요소






DispathcerServlet


- 클라이언트의 요청을 받아서 Controller에게 클라이언트의 요청을 전달하고 리턴한 결과값을 View에게

전달하여 알맞은 응답을 생성한다.



HadlerMapping


- URL과 요청정보를 기준으로 어떤 핸들러 객체를 사용할 지 결정하는 객체이며, DispathcerServlet은 하나 이상의 

핸들러 매핑을 가질 수 있다.



Controller


- 클라이언트의 요청을 처리한 뒤, Model을 호출하고 그 결과를 DispathcerServlet에게 알려준다.



ModelAndView


- Controller가 처리한 데이터 및 화면에 대한 정보를 보유한 객체이다.



View


- Controller의 처리 결과 화면에 대한 정보를 보유한 객체이다.



ViewResolver


- Controller가 리턴한 뷰 이름을 기반으로 Controller 처리 결과를 생성할 뷰를 결정한다.




spring mvc 테스트 코드 첨부


SpringMVCTest.zip


springmvc.pptx



1. Spring AOP의 핵심기능과 부가기능






- 업무 로직을 포함하는 기능을 핵심 기능(Core Concerns)

- 핵심 기능을 도와주는 부가적인 기능(로깅, 보안)을 부가기능(Cross-cutting Concerns) 이라고 부른다.




2. AOP란?


객체지향의 기본원칙을 적용하여도 핵심기능에서 부가기능을 분리해서 모듈화하는 것은 매우 어렵다.

AOP는 애플리케이션에서의 관심사의 분리(기능의 분리), 핵심적인 기능에서 부가적인 기능을 분리한다.

분리한 부가기능을 에스펙트(Aspect)라는 독특한 모듈형태로 만들어서 설계하고 개발하는 방법이다.


- OOP를 적용하여도 핵심기능에서 부가기능을 쉽게 분리된 모듈로 작성하기 어려운 문제점을 AOP가

해결해 준다고 볼수 있다.


- AOP는 부가기능을 애스펙트(Aspect)로 정의하여, 핵심기능에서 부가기능을 분리함으로써 

핵심기능을 설계하고 구현할 때 객체지향적인 가치를 지킬수 있도록 도와주는 개념이다.




3. 애스펙트(Aspect)란?


- 애스펙트는 부가기능을 정의한 코드인 어드바이스(Advice)와 어드바이스를 어디에 적용하지를 결정하는

포인트컷(PointCut)을 합친 개념이다.


Advice + PointCut = Aspect


- AOP 개념을 적용하면 핵심기능 코드 사이에 침투된 부가기능을 독립적인 애스펙트로 구분해 낼수 있다.

- 구분된 부가기능 애스펙트를 런타임 시에 필요한 위치에 동적으로 참여하게 할 수 있다.





4. AOP 용어 정리



타겟(Target)

- 핵심 기능을 담고 있는 모듈로 타겟은 부가기능을 부여할 대상이 된다.



어드바이스(Advice)

- 어드바이스는 타겟에 제공할 부가기능을 담고 있는 모듈이다.



조인포인트(Join Point)

- 어드바이스가 적용될 수 있는 위치를 말한다.

- 타겟 객체가 구현한 인터페이스의 모든 메서드는 조인 포인트가 된다.



포인트 컷(Pointcut)

- 어드바이스를 적용할 타겟의 메서드를 선별하는 정규표현식이다.

- 포인트컷 표현식은 execution으로 시작하고 메서드의 Signature를 비교하는 방법을 주로 이용한다.



애스펙트(Aspect)

- 애스펙트는 AOP의 기본 모듈이다.

- 애스펙트 = 어드바이스 + 포인트컷

- 애스펙트는 싱글톤 형태의 객체로 존재한다.



어드바이저(Advisor)

- 어드바이저 = 어드바이스 + 포인트컷

- 어드바이저는 Spring AOP에서만 사용되는 특별한 용어이다.



위빙(Weaving)

- 위빙은 포인트컷에 의해서 결정된 타겟의 조인 포인트에 부가기능(어드바이스)를 삽입하는 과정을 뜻한다.

- 위빙은 AOP가 핵심기능(타겟)의 코드에 영향을 주지 않으면서 필요한 부가기능(어드바이스)를 추가할 수 있도록

해주는 핵심적인 처리과정이다.




5. Spring AOP 특징



1. Spring은 프록시 기반 AOP를 지원한다.


- Spring은 타겟(target) 객체에 대한 프록시를 만들어 제공한다.

- 타겟을 감싸는 프록시는 실행시간(Runtime)에 생성된다.

- 프록시는 어드바이스를 타겟 객체에 적용하면서 생성되는 객체이다.



2. 프록시(Proxy)가 호출을 가로챈다(Intercept)


- 프록시는 타겟 객체에 대한 호출을 가로챈 다음 어드바이스의 부가기능 로직을 수행하고 난 후에 타겟의

핵심기능 로직을 호출한다.(전처리 어드바이스)


- 또는 타겟의 핵심기능 로직 메서드를 호출한 후에 부가기능(어드바이스)을 수행하는 경우도 있다.(후처리 어드바이스)



3. Spring AOP는 메서드 조인 포인트만 지원한다.


- Spring은 동적 프록시를 기반으로 AOP를 구현하므로 메서드 조인 포인트만 지원한다.

- 핵심기능(타겟)의 메서드가 호출되는 런타임 시점에만 부가기능(어드바이스)을 적용할 수 있다.


- 반면에 AspectJ 같은 고급 AOP 프레임워크를 사용하면 객체의 생성, 필드값의 조회와 조작,

static 메서드 호출 및 초기화 등의 다양한 작업에 부가기능을 적용 할 수 있다.





6. Spring AOP의 구현 방식



1. XML 기반의 POJO 클래스를 이용한 AOP 구현


- 부가기능을 제공하는 Advice 클래스를 작성한다.

- XML 설정 파일에 <aop:config>를 이용해서 애스펙트를 설정한다.

(즉, 어드바이스와 포인트컷을 설정함)



2. @Aspect 어노테이션을 이용한 AOP 구현


- @Aspect 어노테이션을 이용해서 부가기능을 제공하는 Aspect 클래스를 작성한다.

- 이 때 Aspect 클래스는 어드바이스를 구현하는 메서드와 포인트컷을 포함한다.

- XML 설정 파일에 <aop:aspectj-autoproxy />를 설정한다.






7. Advice의 종류



Around 어드바이스


타겟의 메서드가 호출되기 이전(before) 시점과 이후 (after) 시점에 모두 처리해야 할 필요가 잇는

부가기능을 정의한다.

-> Joinpoint 앞과 뒤에서 실행되는 Advice



Before 어드바이스


타겟의 메서드가 실행되기 이전(before) 시점에 처리해야 할 필요가 있는 부가기능을 정의한다.

-> Jointpoint 앞에서 실행되는 Advice



After Returning 어드바이스


타겟의 메서드가 정상적으로 실행된 이후(after) 시점에 처리해야 할 필요가 있는 부가기능을 정의한다.

-> Jointpoint 메서드 호출이 정상적으로 종료된 뒤에 실행되는 Advice



After Throwing 어드바이스


타겟의 메서드가 예외를 발생된 이후(after) 시점에 처리해야 할 필요가 있는 부가기능을 정의한다.

-> 예외가 던져 질때 실행되는 Advice




8. Advice를 정의하는 태그



<aop:before>


- 메서드 실행전에 적용되는 어드바이스를 정의한다.



<aop:after-returning>


- 메서드가 정상적으로 실행 된 후에 적용되는 어드바이스를 정의한다.



<aop:after-throwing>


- 메서드가 예외를 발생시킬 때 적용되는 어드바이스를 정의한다.

- try-catch 블록에서 catch 블록과 비슷하다.



<aop:after>


- 메서드가 정상적으로 실행되는지 또는 예외를 발생시키는지 여부에 상관없이 어드바이스를 정의한다.

- try-catch-finally에서 finally 블록과 비슷하다.



<aop:around>


- 메서드 호출 이전, 이후, 예외발생 등 모든 시점에 적용 가능한 어드바이스를 정의한다.




9. JointPoint 인터페이스


- JoinPoint는 Spring AOP 혹은 AspectJ에서 AOP가 적용되는 지점을 뜻한다.

- 해당 지점을 AspectJ에서 JoinPoint라는 인터페이스로 나타낸다.



1. JointPoint 메서드



 getArgs() 

 메서드 아규먼트를 반환한다.

 getThis()  

 프록시 객체를 반환한다.

 getTarget() 

 대상 객체를 반환한다.

 getSignature()

 어드바이즈 또는 메서드의 설명(description)을 반환한다.

 toString() 

 어드바이즈 되는 메서드의 설명을 출력한다.






1. MyBatis 란?


- MyBatis는 자바 오브젝트와 SQL문 사이의 자동 Mapping 기능을 지원하는 ORM 프레임워크이다


- MyBatis는 SQL을 별도의 파일로 분리해서 관리하게 해주며, 객체-SQL 사이의 파라미터 Mapping 작업을 자동으로

해주기 때문에 많은 인기를 얻고 있는 기술이다.


- MyBatis는 Hibernate나 JPA(Java Persistence Api)처럼 새로운 DB프로그래밍 패러다임을 

익혀야하는 부담 없이, 개발자가 익숙한 SQL을 그대로 이용하면서 JDBC 코드작성의 불편함도 제거해주고,

도메인 객체나 VO 객체를 중심으로 개발이 가능하다는 장점이 있다.




2. Mybatis의 특징


- 간단한 퍼시턴스 프레임워크이다.

- XML 형태로 서술된 JDBC 코드라고 생각해도 될 만큼 JDBC의 모든 기능을 MyBatis가 대부분 제공한다.

- 복잡한 JDBC코드를 걷어내며 깔끔한 소스코드를 유지할 수 있다.

- 수동적인 파라미터 설정과 쿼리 결과에 대한 매핑 구문을 제거할 수 있다.


SQL문과 프로그래밍 코드의 분리

SQL에 변경이 있을 때마다 자바코드를 수정하거나 컴파일 하지 않아도 된다.

SQL 작성과 관리 또는 검토를 DBA와 같은 개발자가 아닌 다른사람에게 맡길수도 있다.



3. Mybatis와 Mybatis-Spring을 사용한 DB 액세스 아키텍처






4. Mybatis 를 사용하는 데이터 액세스 계층 흐름도





5. MyBatis3의 주요 컴포넌트 역할



 MyBatis 설정파일

 (SqlMapConfig.xml)

 - 데이터베이스의 접속 주소 정보나 Mapping 파일의 경로 등의 고정된 환경정보를 설정한다.

 SqlSessionFactoryBuilder

 - MyBatis 설정 파일을 바탕으로 SqlSessionFactory를 생성한다.

 SqlSessionFactory

 - SqlSession을 생성한다.

 SqlSession

 - 핵심적인 역할을 하는 클래스로서 SQL실행이나 트랜잭션 관리를 실행한다.

 - SqlSession오브젝트는 Thread-Safe 하지 않으므로 thread마다 필요에 따라 생성한다.

 mapping 파일

 (user.xml)

 - SQL문과 OR Mapping을 설정한다.

 SqlSessionFactoryBean

 - MyBatis 설정파일을 바탕으로 SqlSessionFactory를 생성한다.

 - Spring Bean으로 등록해야 한다.

 SqlSessionTemplate

 - 핵심적인 역할을 하는 클래스로서 SQL실행이나 트랜잭션 관리를 실행한다.

 - SqlSession 인터페이스를 구현하며, Thread-Safe한다.

 - Spring Bean으로 등록해야 한다.



Spring MyBatis 사용 테스트 코드 첨부 :


SpringMyBatisTest.zip


mybatis.pptx



1. Bean 등록 메타정보 구성 전략



1. XML 설정 단독 사용


- 모든 Bean을 명시적으로 XML에 등록하는 방법


- 생성되는 모든 Bean을 XML에서 확인할 수 있다는 장점이 있으나 Bean의 개수가 많아지면

XML 파일을 관리하기 번거로울 수 있다.


- 여러 개발자가 같은 설정파일을 공유해서 개발하다 보면 설정파일을 동시에 수정하다가 충돌이

일어나는 경우도 적지 않다.


- DI에 필요한 적절한 setter메서드 또는 constructor가 코드 내에 만드시 존재해야 한다.



1.1 XML 단독 사용방식을 사용한 코드


1. 인터페이스 Printer.java


1
2
3
4
5
package di.xml;
 
public interface Printer {
    public void print(String message);
}
cs



2. 인터페이스 구현 클래스1 StringPrinter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
package di.xml;
 
public class StringPrinter implements Printer {
    private StringBuffer buffer = new StringBuffer();
 
    public void print(String message) {
        this.buffer.append(message);
    }
 
    public String toString() {
        return this.buffer.toString();
    }
}
cs


3. 인터페이스 구현클래스2 ConsolePrinter.java


1
2
3
4
5
6
7
package di.xml;
 
public class ConsolePrinter implements Printer {
    public void print(String message) {
        System.out.println(message);
    }
}
cs


4. 모델 Hello.java


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
32
33
34
35
36
37
38
39
40
41
42
43
44
package di.xml;
 
import java.util.List;
 
public class Hello {
    String name;
    Printer printer;
    List<String> names;
 
    public Hello() {
        System.out.println("Hello Default Constructor Called..");
    }
 
    public Hello(String name, Printer printer) {
        this.name = name;
        this.printer = printer;
    }
 
    public List<String> getNames() {
        return this.names;
    }
 
    public void setNames(List<String> list) {
        this.names = list;
    }
 
    public void setName(String name) {
        System.out.println("setName() called " + name);
        this.name = name;
    }
 
    public void setPrinter(Printer printer) {
        System.out.println("setPrinter() called " + printer.getClass().getName());
        this.printer = printer;
    }
 
    public String sayHello() {
        return "Hello " + name;
    }
 
    public void print() {
        this.printer.print(sayHello());
    }
}
cs



5. DI를 위한 bean.xml


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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
    <!-- StringPrinter 클래스를 bean으로 등록 -->
    <bean id="stringPrinter" class="di.xml.StringPrinter"/>
    <!-- Console.Printer 클래스를 bean으로 등록 -->
    <bean id="consolePrinter" class="di.xml.ConsolePrinter"/>
    
    <!-- setter injection -->
    <!-- Hello 클래스를 bean으로 등록 -->
    <bean id="helloBean" class="di.xml.Hello" scope="singleton">
        <property name="name" value="상현"/>
        <property name="printer" ref="stringPrinter"/>
    </bean>
    
    <!-- constructor injection -->
    <bean id="helloConstructor" class="di.xml.Hello">
        <!-- constructor injection  -->
        <constructor-arg index="0" value="생성자" />
        <constructor-arg index="1" ref="consolePrinter" />
    </bean>
</beans>
cs


6. 검증에 필요한 jUnit 사용 Test 클래스 HelloBeanTest.java


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
32
33
34
35
package di.xml.test;
 
import org.junit.Assert;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.GenericXmlApplicationContext;
 
import di.xml.Hello;
import di.xml.Printer;
 
public class HelloBeanTest {
    @Test
    public void hellobean() {
        // 1. Spring Container 생성
        BeanFactory factory = 
                new GenericXmlApplicationContext("config/beans.xml");
        // 2. Bean 을 요청
        Hello helloBean = (Hello)factory.getBean("helloBean");
        Hello helloBean2 = factory.getBean("helloBean",Hello.class);
        
        // 주소 비교
        Assert.assertSame(helloBean, helloBean2);
        assertSame(helloBean, helloBean2);
        
        // 값 비교
        // name변수 값이 잘 주입되었는지 확인 가능`
        assertEquals("Hello 상현", helloBean.sayHello());
        
        // printer 변수 잘 주입 되었는지 확인
        helloBean.print();
        Printer printer = factory.getBean("stringPrinter", Printer.class);
        assertEquals("Hello 상현", printer.toString());
    }
}
cs


결과 : 







2. 어노테이션과 XML 설정 혼용해서 사용


- Bean으로 사용될 클래스에 특별한 어노테이션(Annotation)을 부여해주면 이런 클래스를 자동으로 찾아서 Bean으로 등록한다.


- @Component 어노테이션이 선언된 클래스를 자동으로 찾아서 Bean으로 등록해주는 방식을 

빈 스캐닝(Bean Scanning)을 통한 자동인식 Bean 등록기능이라고 한다.


- 어노테이션을 부여하고 자동 스캔으로 Bean을 등록 하면 XML문서 생성과 관리에 따른 수고를 덜어주고

개발속도를 향상 시킬수 있다.


- 애플리케이션에 등록될 Bean이 어떤것들이 있고, 의존관계가 어떻게 되는지를 한눈에 파악할수 없다는 단점이 있다.



2.1 어노테이션과 XML 혼용방식을 사용한 코드



1. 인터페이스 Printer.java


1
2
3
4
5
package di.annotation;
 
public interface Printer {
    public void print(String message);
}
cs


2. 인터페이스 구현 클래스1 StringPrinter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package di.annotation;
 
import org.springframework.stereotype.Component;
 
@Component
public class StringPrinter implements Printer {
    private StringBuffer buffer = new StringBuffer();
 
    public void print(String message) {
        this.buffer.append(message);
    }
 
    public String toString() {
        return this.buffer.toString();
    }
}
cs


3. 인터페이스 구현클래스2 ConsolePrinter.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
package di.annotation;
 
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/*
 * @Component 의 default 값은 consolePrinter
 */
@Component("consolePrinter")
@Scope("singleton")
public class ConsolePrinter implements Printer {
    public void print(String message) {
        System.out.println(message);
    }
}
cs


4. 기본생성자와 setter메소드를 뺀 모델 Hello.java


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package di.annotation;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
@Component("helloA")
public class Hello {
    String name;
    Printer printer;
    List<String> names;
 
    public Hello() {
        System.out.println("Hello Default Constructor Called..");
    }
 
//    public Hello(String name, Printer printer) {
//        this.name = name;
//        this.printer = printer;
//    }
    
    // 생성자 어노테이션
    @Autowired
    public Hello(@Value("어노테이션"String name, @Qualifier("consolePrinter") Printer printer) {
        this.name = name;
        this.printer = printer;
    }
 
    public List<String> getNames() {
        return this.names;
    }
 
    public void setNames(List<String> list) {
        this.names = list;
    }
 
//    public void setName(String name) {
//        System.out.println("setName() called " + name);
//        this.name = name;
//    }
//
//    public void setPrinter(Printer printer) {
//        System.out.println("setPrinter() called " + printer.getClass().getName());
//        this.printer = printer;
//    }
 
    public String sayHello() {
        return "Hello " + name;
    }
 
    public void print() {
        this.printer.print(sayHello());
    }
}
cs


5. DI를 위한 annot.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.3.xsd">
 
    <context:component-scan base-package="di.annotation" />
 
</beans>
cs



6. 검증에 필요한 jUnit 사용 Test 클래스 HelloBeanTest.java


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
package di.annotation.test;
 
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import di.annotation.Hello;
import di.annotation.Printer;
 
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:config/annot.xml")
public class HelloAnnotationTest {
    @Autowired
    Hello hello;
    
    @Autowired
    @Qualifier("stringPrinter")
    Printer printer;
    
    @Test 
    public void hello() {
        System.out.println(hello.sayHello());
        hello.print();
    }
    
}
cs


결과







3. 어노테이션 설정 단독 사용


- @Configuration 어노테이션과 @Bean 어노테이션을 이용해서 스프링 컨테이너에 새로운 빈 객체를 제공할 수 있다.

- Spring 3.0 부터는 어노테이션을 이용한 Bean의 등록과 Bean 들 간의 연결설정을 자바코드 내부에 하므로

XML을 전혀 사용하지 않는다.



3.1 XML 안쓰는 방법 전략 - 1



1. @Bean어노테이션을 사용한 HelloJavaConfig.java


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
32
33
34
35
36
37
38
39
package di.xml.config;
 
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import di.xml.ConsolePrinter;
import di.xml.Hello;
import di.xml.Printer;
import di.xml.StringPrinter;
 
 
//전략 3-1 xml 안쓰는 방법
 
@Configuration
public class HelloJavaConfig {
    
    @Bean
    public Hello hello() {
        Hello hello = new Hello();
        hello.setName("Java컨피그");
        hello.setPrinter(printer());
        return hello;
    }
    
    @Bean
    @Qualifier("stringPrinter")
    public Printer printer() {
        Printer printer = new StringPrinter();
        return printer;
    }
    
    @Bean
    @Qualifier("consolePrinter")
    public Printer cPrinter() {
        Printer printer = new ConsolePrinter();
        return printer;
    }
}
cs


2. AnnotationConfigContextLoader를 사용한 HelloJavaConfigTest.java


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
32
package di.xml.test;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
import di.xml.Hello;
import di.xml.Printer;
import di.xml.config.HelloJavaConfig;
 
// 전략 3의 1번째 방법
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=HelloJavaConfig.class, loader=AnnotationConfigContextLoader.class)
public class HelloJavaConfigTest {
    @Autowired
    Hello hello;
    
    @Autowired
    @Qualifier("stringPrinter")
    Printer printer;
    
    @Test
    public void hello() {
        System.out.println(hello.sayHello());
        hello.print();
        System.out.println(printer.toString());
    }
}
cs



결과





3.2 XML 안쓰는 방법 전략 - 2



1. @ComponentScan을 사용한 HelloJavaConfig2.java


1
2
3
4
5
6
7
8
9
10
package di.annotation.config;
 
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
 
@Configuration
@ComponentScan(basePackages= {"di.annotation"})
public class HelloJavaConfig2 {
    
}
cs




2. AnnotationConfigContextLoader를 사용한 HelloJavaConfigTest2.java


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
package di.annotation.test;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;
 
import di.annotation.Hello;
import di.annotation.config.HelloJavaConfig2;
 
 
// 전략 3의 2번째 방법
 
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=HelloJavaConfig2.class, loader=AnnotationConfigContextLoader.class)
public class HelloJavaConfig2Test {
    
    @Autowired
    Hello hello;
    
    @Test
    public void hello() {
        System.out.println(hello.sayHello());
        hello.print();
    }
}
cs



결과





Bean 등록 전략 테스트 코드 :


MySpringJunit.zip





1. Bean 등록 의존관계 주입 Annotation 종류



@Component 

컴포넌트를 나타내는 일반적인 스테레오 타입으로 <bean> 태그와 동일한 역할을 한다.



@Repository

퍼시스턴스(persistence)레이어, 영속성을 가지는 속성(파일, 데이터베이스)을 가진 클래스



@Service

서비스레이어, 비즈니스 로직을 가진 클래스



@Controller

프리젠테이션, 레이어, 웹 어플리케이션에서 웹 요청과 응답을 처리하는 클래스



@Autowired

- 정밀한 의존관계 주입(Dependency Injection)이 필요한 경우 유용하다.

- @Autowired는 변수, setter메서드, 생성자, 일반메서드에 적용 가능하다.

- @Autowired는 <property>, <constructor-arg> 태그와 동일한 역할을 한다.

- 의존하는 객체를 주입할 떄 Type을 이용한다.



@Resource

- 어플리케이션에서 필요로 하는 자원을 자동 연결할 떄 사용된다.

- @Resource는 변수, setter메서드에 적용 가능하다.

- 의존하는 객체를 주입할 때 주로 Name을 이용한다.



@value

- 단순한 값을 주입할 때 사용되는 어노테이션이다.

- @Value("Spring")은 <property.. value="Spring" /> 과 동일한 역할이다.



@Qualifier

- @Qualifier는 @Autowired 어노테이션과 같이 사용되어 진다.

- @Autowired는 타입으로 찾아서 주입하므로 동일한 타입의 Bean 객체가 여러개 존재할때

특정 Bean을 찾기 위해서는 @Qualifier를 같이 사용해야 한다.



@Bean

- @Bean 어노테이션은 새로운 빈 객체를 제공할때 사용되며 @Bean이 적용된 메서드의 이름을 

Bean의 식별값으로 사용한다.



@Configuration

- 클래스에 @Configuration 어노테이션을 선언하는 것은 스프링 IoC 컨테이너가 해당 클래스를

Bean 정의의 설정으로 사용한다는 것을 나타낸다.




<context:component-scan> 태그


@Component를 통해 자동으로 Bean을 등록하고 @Autowired로 의존관계를 주입받는

어노테이션을 클래스에서 선언하여 사용했을 경우에는 해당 클래스가 위치한 특정 패키지를 scan하기 위한 설정을

XML에 해주어야 한다.


1
<context:component-scan base-package="di.annot" />
cs


<context:include-filter> 태그 ( 자동 스캔 대상에 포함시킬 클래스 )

<context:exclude-filter>태그 ( 자동 스캔 대상에 포함시키지 않을 클래스 )

를 사용하여 구체적으로 명시할 수 있다.




1. jUnit이란?


- Java에서 독립된 단위테스트(Unit Test)를 지원해주는 프레임워크이다.




2. 단위테스트(Unit Test)란?


- 소스코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차이다.

- 모든 함수와 메소드에 대한 테스트 케이스(Test case)를 작성하는 절차를 말한다.

- jUnit은 보이지 않고 숨겨진 단위 테스트를 끌어내어 정형화시켜 단위테스트를 쉽게 해주는 테스트 지원 프레임워크이다.




3. jUnit 특징


- 단정(assert) 메서드로 테스트 케이스의 수행 결과를 판별한다.(ex: assertEquals(예상값, 실제값))

- jUnit4부터는 테스트를 지원하는 어노테이션을 제공한다.(@Test @Before @After)

- @Test 메서드가 호출할 때 마다 새로운 인스턴스를 생성하여 독립적인 테스트가 이루어지게 한다.




4. jUnit에서 테스트를 지원하는 어노테이션(Annotation)



@Test


- @Test가 선언된 메서드는 테스트를 수행하는 메소드가 된다.

- jUnit은 각각의 테스트가 서로 영향을 주지 않고 독립적으로 실행됨을 원칙으로 @Test마다 객체를 생성한다.



@Ignore


- @Ignore가 선언된 메서드는 테스트를 실행하지 않게 한다.



@Before


- @Before가 선언된 메서드는 @Test 메서드가 실행되기 전에 반드시 실행되어진다.

- @Test메서드에서 공통으로 사용하는 코드를 @Before 메서드에 선언하여 사용하면 된다.



@After


- @After가 선언된 메서드는 @Test 메소드가 실행된 후 실행된다.



@BeforeClass


- @BeforeClass 어노테이션은 @Test 메소드보다 먼저 한번만 수행되어야 할 경우에 사용하면 된다.



@AfterClass


- @AfterClass 어노테이션은 @Test 메소드 보다 나중에 한번만 수행되어야 할 경우에 사용하면 된다.




5. 자주 사용하는 jUnit 메서드



 assertEquals(a,b); 

 객체 a,b의 값이 일치함을 확인한다.

 assertArrayEquals(a,b);

 배열 a,b의 값이 일치함을 확인한다.

 assertSame(a,b);

 객체 a,b가 같은 객체임을 확인한다.

 두 객체의 레퍼런스가 동일한가를 확인한다.

 assertTrue(a);

 조건 a가 참인가 확인한다.

 assertNotNull(a);

 객체 a가 null이 아님을 확인한다.




6. Spring-Test에서 테스트를 지원하는 어노테이션



@RunWith(SpringJUnit4ClassRunner.class)


- @RunWith는 jUnit 프레임워크의 테스트 실행방법을 확장할 때 사용하는 어노테이션이다.

- SpringJUnit4ClassRunner라는 클래스를 지정해주면 jUnit이 테스트를 진행하는 중에 ApplicationContext를 만들고 관리하는 작업을 진행해준다.

- @RunWith 어노테이션은 각각의 테스트 별로 객체가 새성되더라도 싱글톤(Singletone)의 ApplicationContext를 보장한다.


@ContextConfiguration


- 스프링 빈(Bean) 설정 파일의 위치를 지정할 떄 사용되는 어노테이션이다.


@Autowired


- 스프링 DI에서 사용되는 특별한 어노테이션이다.

- 해당 변수에 자동으로 빈(Bean)을 매핑 해준다.

- 스프링 빈(Bean) 설정 파일을 읽기 위해 굳이 GenericXmlApplicationContext를 사용할 필요가 없다.

- 변수, setter메서드, 생성자, 일반메서드에 적용가능하다.

- 의존하는 객체를 주입할 떄 주로 Type을 이용하게 된다.

- <property>, <constructor-arg> 태그와 동일한 역할을 한다.



1. IoC란?


- IoC(Inversion of Control 제어권의 역전)란 객체의 생성, 생명주기의 관리까지 모든객체에 대한 제어권이 바뀌었다는 것을 의미한다.

- 컴포넌트 의존관계 결정(component dependency resolution),

  설정(configuration) 및 생명주기(lifecycle)를 해결하기 위한 디자인 패턴(Design Pattern)이다.



IoC가 아닌경우 - new 방식을 써서 객체가 필요할때마다 생성해야 한다.

IoC인경우 - new 방식을 써서 객체를 생성할 필요없다.




2. IoC 컨테이너란?




- 객체에 대한 생성 및 생명주기를 관리 할수 있는 기능을 제공하고 있다.

- IoC 컨테이너는 객체의 생성을 책임지고, 의존성을 관리한다.

- POJO의 생성, 초기화, 서비스, 소멸에 대한 권한을 가진다.

- 개발자들이 직접 POJO를 생성할 수 있지만 컨테이너에게 맡긴다.




3. IoC의 분류






1. DL ( Dependency Lookup 의존성 검색 )이란?


 - 저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 Lookup 하는 것

 - DL 사용 시 컨테이너 종속성이 증가한다.


2. DI ( Dependency Injection 의존성 주입 )란?


- 각 클래스 간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것


- 개발자들은 단지 빈 설정파일에서 의존관계가 필요하다는 정보를 추가하면 된다.

- 객체 레퍼런스를 컨테이너로부터 주입 받아서 실행 시에 동적으로 의존관계가 생성된다.

- 컨테이너가 흐름의 주체가 되어 애플리케이션 코드에 의존관계를 주입해 주는 것이다.


2.1 DI 장점 


- 코드가 단순해진다.

- 컴포넌트 간의 결합도가 제거된다.




4. DI 용어



1. 빈(Bean)


- 스프링이 IoC 방식으로 관리하는 객체라는 뜻이다.

- 스프링이 직접 생성과 제어를 담당하는 객체를 Bean이라고 한다.



2. 빈 팩토리(BeanFactory)


- 스프링의 IoC를 담당하는 핵심 컨테이너를 가리킨다.

- Bean을 등록, 생성, 조회, 반환 기능을 담당한다.

- 이 BeanFactory를 바로 사용하지 않고 이를 확장한 ApplicationContext를 주로 이용한다.


3. 애플리케이션 컨텍스트(ApplicationContext)


- BeanFactory를 확장한 IoC 컨테이너

- Bean을 등록하고 관리하는 기능은 BeanFactory와 동일하지만 

스프링이 제공하는 각종 부가 서비스를 추가로 제공한다.

- 스프링에서는 ApplicationContext를 BeanFactory보다 더 많이 사용한다.



4. 설정 메타정보(Configuration metadata)


- Applicationcontext또는 BeanFactory가 IoC를 적용하기 위해 사용하는 메타정보를 말한다.

- 설정 메타정보는 IoC컨테이너에 의해 관리되는 Bean객체를 생성하고 구성할 때 사용된다.




5. DI의 유형



1. Setter Injection ( Setter 메서드를 이용한 의존성 삽입 )

의존성을 입력받는 setter 메서드를 만들고 이를 통해 의존성을 주입한다.


2. Constructor Injection ( 생성자를 이용한 의존성 삽입 )

필요한 의존성을 포함하는 클래스의 생성자를 만들고 이를 통해 의존성을 주입한다.


3. Method Injection ( 일반 메서드를 시용한 의존성 삽입 )

의존성을 입력받는 일반 메서드를 만들고 이를 통해 의존성을 주입한다.




6. DI : Bean 의존관계



1. Setter Injection : <property> 태그


- Setter 메서드를 통해 의존관계가 있는 Bean을 주입하려면 <property> 태그의 ref 속성을 사용할 수 있다.

- Setter메서드를 통해 Bean의 레퍼런스가 아니라 단순 값을 주입하려고 할때는 <property> 태그의 value 속성을 사용한다.

- ref 속성을 사용하면 Bean의 id를 이용해 주입할 Bean을 찾는다.

- value 속성은 단순 값 또는 Bean이 아닌 객체를 주입 할 때 사용한다.


2. Constructor Injection : <constructor-arg> 태그


- Constructor를 통해 의존관계가 있는 Bean을 주입하려면 <constructor-arg> 태그를 사용할수 있다.

- Constructor 주입방식은 생성자의 파라미터를 이용하기 때문에 한번에 여러개의 객체를 주입할 수 있다.



다음은 Setter Injection , Constructor Injection 사용한 beans.xml 코드이다.


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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
    <!-- StringPrinter 클래스를 bean으로 등록 -->
    <bean id="stringPrinter" class="di.xml.StringPrinter"/>
    <!-- Console.Printer 클래스를 bean으로 등록 -->
    <bean id="consolePrinter" class="di.xml.ConsolePrinter"/>
    
    <!-- setter injection -->
    <!-- di.xml.Hello 클래스를 bean으로 등록 -->
    <bean id="helloBean" class="di.xml.Hello" scope="singleton">
        <property name="name" value="상현"/>
        <property name="printer" ref="stringPrinter"/>
    </bean>
    
    <!-- constructor injection -->
    <bean id="helloConstructor" class="di.xml.Hello">
        <!-- constructor injection  -->
        <constructor-arg index="0" value="생성자" />
        <constructor-arg index="1" ref="consolePrinter" />
    </bean>
</beans>
cs




7. Spring DI 컨테이너 구조



- Spring DI 컨테이너가 관리하는 객체를 빈(bean)이라 하고, 이 빈(bean)들을 관리한다는 의미로 컨테이너를 빈 팩토리(BeanFactory)라고 부른다.

- 객체의 생성과 객체 사이의 런타임(run-time)관계를 DI관점에서 볼때는 컨테이너를 BeanFactory라고 한다.

- Bean Factory에 여러가지 컨테이너 기능을 추가하여 애플리케이션 컨텍스트(ApplicationContext)라고 부른다.


1. BeanFactory


- Bean을 등록, 생성, 조회, 반환 관리한다.

- 보통은 BeanFactory를 바로 사용하지 않고, 이를 확장한 ApplicationContext를 사용한다.

- getBean() 메서드가 정의되어 있다.


2. ApplicationContext


- Bean을 등록, 생성, 조회, 반환 관리하는 기능은 BeanFactory와 같다.

- Spring이 각종 부가 서비스를 추가로 제공한다.

- Spring이 제공하는 ApplicationContext 구현 클래스가 여러가지 종류가 있다.




+ Recent posts