- AOP 는 OOP 를 더욱 OOP 답게 만들어 줄 수 있다. - AOP 는 OOP 뿐만 아니라 기존의 절차적 프로그래밍에도 적용될 수 있다.
핵심 관심 모듈은 비즈니스 로직, 횡단 관심 모듈은 비즈니스 로직을 서포트하는 기능적인 요소들을 제공하는 모듈이다. 예를 들어, AOP 를 사용하지 않으면, 계좌이체시에 로깅이라는 작업이 필요하기에, 직접 계좌이체에 메서드를 수정해야하지만, AOP 를 사용하므로써, 위빙(Weaving)을 한다. 위빙은 핵심 관심 모듈과 횡단 관심 모듈을 합치는 것이며, 프레임워크는 이러한 위빙 작업을 통해 핵심 모듈 사이사이에 필요한 횡단 관심 코드가 동작하도록 엮어지게 만든다.
Spring DI Container 가 관리하는 객체를 빈(Bean) 이라고 하고, 이 빈(Bean)들을 관리하는 의미로 컨테이너를 BeanFactory 라고 부른다.
객체의 생성과 객체 사이의 run-time 관계를 DI 관점에서 볼 때는 컨테이너를 BeanFactory 라고 한다.
BeanFactory 에서 여러가지 컨테이너 기능을 추가하여 ApplicationContext 라고 부른다.
BeanFactory 와 ApplicationContext
BeanFactory
ApplicationContext
- Bean을 등록, 생성, 조회, 반환 관리함 - 보통 BeanFactory 를 바로 사용하지 않고, 이를 확장한 ApplicationContext 를 주로 사용함 - getBean() 메서드가 정의되어 있음 (Bean 을 조회할 수 있는 메서드)
- Bean을 등록, 생성, 조회, 반환 관리하는 기능은 BeanFactory 와 같음 - Spring 의 각종 부가 서비스를 추가로 제공함 - Spring 이 제공하는 ApplicationContext 여러종류의 구현 클래스가 존재함
BeanFactory 와 ApplicationContext 의 클래스 구조
기본적인 DI Container 역할을 하는 BeanFactory 가 최상위 인터페이스로 존재하며, ApplicationEventPublisher, ListableBeanFactory, MessageSource, RsourceLoader 들을 상속받는 ApplicationContext 인터페이스 존재한다. 궁극적으로 ApplicationContext 가 DI Container 역할을 한다. ApplicaitonContext 를 상속받아서 구체적으로 구현된 클래스는 StaticApplicationContext, GenerixXmlApplicationContext, WebApplicationContext 등이 있고, WebApplicationContext 를 상속받아서 구현된 XmlWebApplicationContext 도 존재한다.
bean.xml 에 의존관계에 대한 설정을 해둔 것이다. bean 은 스프링이 관리해주는 객체라는 뜻으로 받아들이면 된다. Hello.java 의 setter 메서드와 mapping 되는 태그가 bean.xml의 property 태그라고 보면 된다. 첫번째 property 는 Spring 의 값(value)를 넣고, 두번째 property 는 타입에 해당하는 객체인 printer 를 넣는다. 객체 printer 의 경우아래에 id=printer class="bean.StringPrinter" 라고 위치를 지정해둔다. bean 의 Setter Injection 은 한 번에 한 개씩 의존관계를 주입받을 수 있다.
Constructor Injection
Hello.java
package bean;
import java.util.LIst;
public class Hello {
String name;
Printer printer;
public Hello(String name, Printer printer) {
this.name = name;
this.printer = printer;
}
}
Constructor Injection 은 Setter Injection 과 다르게, 한 번에 여러개의 인자를 받을 수 있다. Hello 클래스 안에, 생성자를 선언한다. 이후에 설정파일에서 그 값을 지정한다.
bean.xml 에 위의 Hello.java 와의 의존관계에 대한 설정을 해둔 것이다. 첫번째 인자는 constructor-arg 에 index=0 (배열이기 때문에), value 값을 넣고, 두번쨰 인자에는 index=1, 타입에 해당하는 객체 (StringPrinter)를 적어둔다. 위의 Setter Injection 과 동일하게, printer 객체에 대한 정보는 bean id="printer" 에 적어둔 주소를 이용한다.
객체를 직접 생성(new 연산자)하는 것이 아니라 외부에서 생성된 객체를 주입받아 이용하는 것이다.
IoC (Inversion of Control, 제어권의 역전)
메소드나 객체의 생성, 라이프 사이클 관리, 호출작업을 개발자가 직접 하는게 아니라, 프레임워크의 컨테이너가 객체에 대한 제어권을 가지고 있는 것이다. (대부분의 프레임워크에서 IoC를 적용하고 있다.) IoC는 의존관계 설정 및 라이프 사이클을 해결하기 위한 디자인 패턴이다.
IoC Container
기능은 객체에 대한 생명 및 생명주기 관리하는 기능 제공한다.
객체의 생성을 책임지고, 의존성을 관리함
POJO의 생성, 초기화, 서비스, 소멸에 대한 권한을 가짐
개발자들이 직접 POJO를 생성할 수 있지만 컨테이너에게 맡김 컨테이너란 무언가를 담고, 특정 기능을 수행하는 프레임워크가 제공하는 논리적 컨텍스트
IoC의 분류
IoC
DL (Dependency Injection)
DI (Dependency Lookup)
Setter Injection
Constructor Injection
Method Injection
DL과 DI
DL (의존성 검색)
DI (의존성 주입)
저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 LookUp 하는 것
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTeller {
// public static void main(String[] args) {
@RequestMapping("/getYoil")
public void main(HttpServletRequest request, HttpServletResponse response) throws IOException{
// 1. 입력
String year = request.getParameter("year");
String month = request.getParameter("month");
String day = request.getParameter("day");
// 2. 작업
int yyyy = Integer.parseInt(year);
int mm = Integer.parseInt(month);
int dd = Integer.parseInt(day);
Calendar cal = Calendar.getInstance();
cal.set(yyyy, mm - 1, dd);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = 일, 2 = 월 ...
char yoil = "일월화수목금토".charAt(dayOfWeek);
// 3. 출력
response.setContentType("text/html"); // response 객체 형식을 적어야한다. 즉, 출력할 내용의 타입을 적어야한다.
response.setCharacterEncoding("UTF-8"); // 텍스트도 인코딩을 해야지 한글이 깨지지 않는다.
PrintWriter out = response.getWriter(); // response객체에서 브라우져로의 출력 스트림을 얻는다.
out.println(year + "년" + month + "월" + day + "일은 ");
// 원래 제대로 하려면 HTML 형식을 갖춰서 해야한다.
out.println(yoil + "요일입니다.");
}
}
관심사는 해야할 작업이라 생각하면 된다. 객체 지향적으로는 코드 분리를 잘해야한다. 현재 위의 [YoilTeller.java]파일에서 main이라는 메소드는 3개의 관심사가 있다. 즉 OOP 5대 설계원칙(SOLID)에 부합하는 코드로 보면, 좋은 코드는 아니다. (SOLID는 추후에 계속 설명) SOLID의 S는 SRP는 단일 책임 원칙이다. 단일 책임(관심사)의 원칙은 "하나의 메소드는 하나의 책임만 진다"는 뜻이다. 즉 3개의 관심사를 분리해야한다.
분리
관심사의 분리
변하는 것과 변하지 않는 것의 분리 (common, uncommon = 자주 변하는 것과 아닌 것)
공통코드(중복코드)
작성한 코드를 보고, 3가지 분리사항에 부합하는지 보면 객체 지향적으로 잘 분리된 코드로 볼 수 있다.
2. 공통 코드의 분리 - 입력의 분리
각각의 입력부분을 떼어서, 공통코드로 한 곳으로 분류한다.
@RequestingMapping("/getYoil")
public void main(HttpServletRequest request, HttpServletRespons)
String을 int로 쓸 수도 있다. (YoilTellerMVC.java 참고) 자동변환도 된다. 공통코드를 분리함으로써, 하나의 관심사가 사라지게 된다.
3. 출력(view)의 분리 - 변하는 것과 변하지 않는 것의 분리
[Spring MVC]
사용자의 요청이 들어오게 되면, 앞에서 입력처리를 한다. (DispatcherServlet), DispatcherServlet 입력 처리 후에 해당 Controller에게 넘겨준다. Controller는 처리한 결과를 Model 객체를 하나 만든 뒤에 값들을 다 저장하고 DispatcherServlet이 Model을 View에 전달한다. View는 작업 결과를 읽어서, 응답을 만들어 낸 뒤에, 클라이언트에게 전송하게 된다. 이것이 Spring MVC 패턴이다.
4. MVC 패턴
View를 Controller와 분리하게 되면, 상황에 맞는 View를 보여주기 편리해진다. 그렇기에 아래의 경우에는 yoil.jsp와 yoilError.jsp 로 구분했다.
[YoilTellerMVC.java]
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTellerMVC {
@RequestMapping("/getYoilMVC") // RequestMapping은 중복되는 게 있으면 안된다.
public String main(int year, int month, int day, Model model) throws IOException{
// String을 int로 변경, 반환타입은 String으로 변경
// 1. 유효성 검사 필요
if(isValid(year, month, day))
return "yoilError"; // WEB_INF/views/yoilError.jsp = 에러시에 나오는 view
// 2. 요일 계산
char yoil = getYoil(year, month, day);
// 3. 계산한 결과를 Model에 저장
model.addAttribute("year", year);
model.addAttribute("month", month);
model.addAttribute("day", day);
model.addAttribute("yoil", yoil);
return "yoil"; // WEB_INF/views/yoil.jsp
}
private boolean isValid(int year, int month, int day) {
// 클래스 내에서만 쓰기에 private
return true;
}
private char getYoil(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(year, month - 1, day);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1 = 일, 2 = 월 ...
return "일월화수목금토".charAt(dayOfWeek);
}
}
// 날짜 연월일을 입력하면, 날짜를 말해주는 프로그램
@Controller // Controller 를 통해서, 로컬프로그램을 원격프로그램으로 변경
public class YoilTellerMVC {
@RequestMapping("/getYoilMVC") // RequestMapping은 중복되는 게 있으면 안된다.
public ModelAndView main(int year, int month, int day) throws IOException{
// 반환타입을 ModelAndView로 변경
// 1. model and view의 경우
ModelAndView mv = new ModelAndView();
// 2. 유효성 검사
if(!isValid(year, month, day))
return mv;
// 3. 작업
char yoil = getYoil(year, month, day);
// 4. 작업 결과를 ModelAndView에 저장
mv.addObject("year", year);
mv.addObject("month", month);
mv.addObject("day", day);
mv.addObject("yoil", yoil);
// 5. 결과를 보여줄 view를 지정
mv.setViewName("yoil"); // view의 이름을 지정 // WEB_INF/views/yoil.jsp
return mv;
}
}
액션태그는 서버나 클라이언트에게 어떤 행동을 하도록 명령하는 태그이다. 또한, 액션 태그는 JSP 페이지에서 페이지와 페이지 사이를 제어하거나, 다른 페이지의 실행 결과 내용을 현제 페이지에 포함하거나, 자바빈즈(JavaBeans) 등의 다양한 기능을 제공한다. 액션 태그에는 다양한 종류가 있으며, XML 형식 <jsp: ··· />를 사용한다. 액션태그는 반드시 끝나는 태그 />로 마무리해야한다. 액션태그는 스크립트 태그와 마찬가지로 JSP 페이지에서 자바코드를 삽입할 수 있는 태그이다. 그렇기에, JSP 페이지를 작성할 때, 자바 코드의 삽입을 되로록 최소화하여 유지 보수를 효율적으로 하는 것이 목적이다.
웹 브라우저에 자바 애플릿을 실행한다. 자바 플러그인에 대한 OBJECT 또는 EMBED 태그를 만드는 브라우저별 코드를 생성한다.
element
<jsp:element ···/>
동적 XML 요소를 설정한다.
attribute
<jsp:attribute ···/>
동적으로 정의된 XML 요소의 속성을 설정한다.
body
<jsp:body ···/>
동적으로 정의된 XML 요소의 몸체를 설정한다.
text
<jsp:text ···/>
JSP 페이지 및 문서에서 템플릿 텍스트를 작성한다.
foward 액션 태그의 형태
<jsp:forward page="파일명" />
or
<jsp:forward page="파일명"> </jsp:forward>
forward 액션 태그의 기능
forward 액션 태그는 현재 JSP 페이지에서 다른 JSP 페이지로 이동하는 태그이다. JSP 컨테이너는 현재 JSP 페이지에서 forward 액션 태그를 만나면 그 전까지 출력 버퍼에 저장되어 있던 내용을 모두 삭제한다. forward 액션 태그에 설정된 페이지로 프로그램의 제어가 이동한다.
forward 액션 태그의 특징
forward 액션태그가 선언된 지점 이전까지 생성된 HTML 코드가 손실된다. 그러나 이미 전달 버퍼로 채워진 경우에는 전달이 중단될 때까지 해당 내용을 웹 서버에 응답으로 보낸다. 이런 경우에는 잘못된 페이지가 클라이언트로 전송될 수 있다.
include 액션 태그의 형태
<jsp:include Page="파일명" flush="false"/>
include 액션 태그의 기능
include 디렉티브 태그처럼 현재 JSP 페이지의 특정 영역에 외부 파일의 내용을 포함하는 태그이다. 포함할 수 있는 외부파일은 HTML, JSP, 서블릿 페이지 등이다.
include 액션 태그의 특징
flush 속성 값은 설정한 외부 파일로 제어가 이동할 때, 현재 JSP 페이지가 지금까지 출력 버퍼에 저장한 결과를 처리한다. 기본 값은 false이고, true로 설정하면 외부 파일로 제어가 이동할 때 현재 JSP 페이지가 직므까지 출력 버퍼에 저장된 내용을 웹 브라우저에 출력하고 출력 버퍼를 비운다. include 액션 태그는 forward태그와 다르게, 외부 파일이 실행된 후 현재 JSP 페이지로 제어를 반환한다. 또한, JSP 컨테이너는 현재 JSP 페이지에서 include 액션 태그를 만나면 include 액션 태그에 설정된 외부 파일의 실행 내용이 현재 JSP 페이지의 출력 버퍼에 추가 저장되어 출력되어진다.
include 액션 태그와 include 디렉티브 태그의 차이
구분
include 액션 태그
include 디렉티브 태그
처리 시간
요청 시 자원을 포함
번역 시 자원을 포함
기능
별도의 파일로 요청 처리 흐름을 이동
현재 페이지에 삽입
데이터 전달방법
request 기본 내장 객체나 param 액션 태그를 이용하여 파라미터를 전달
페이지 내의 변수를 선언한 후 변수에 값을 저장
용도
화면 레이아웃의 일부분을 모듈화할 때 주로 사용
다수의 JSP 웹 페이지에서 공통으로 사용되는 코드나 저작권과 같은 문장을 포함하는 경우에 사용
setProperty 액션 태그는 useBean 액션 태그와 함께 자바빈즈의 Setter() 메소드에 접근하여 자바빈즈의 멤버 변수인 프로피티의 값을 저장하는 태그이다. setProperty 액션 태그는 폼 페이지로부터 전달되는 요청 파라미터의 값을 직접 저장하거나 자바빈즈의 프로퍼티로 변경하여 값을 저장할 수 있다. 또는 모든 자바빈즈 프로퍼티 이름과 동일하게 요청 파리미터를 설정할 수 있다.
setProperty 액션 태그의 속성
속성
설명
name
useBean 태그에 id 속성 값으로 설정된 자바빈즈를 식별하기 위한 이름이다.
property
자바빈즈의 프로퍼티 이름이다. 만약 프로퍼티 이름에 '*'를 사용하면 모든 요청 파라미터가 자바빈즈 프로퍼티의 Setter() 메소드에 전달됨을 의미한다.
value
변경할 자바빈즈의 프로퍼티 값이다. 만약 프로퍼티 값이 null이거나 존재하지 않는 요청 파라미터인 경우에는 SetProperty 액션태그가 무시된다.
param
자바빈즈의 프로퍼티 값을 전달하는 요청 파라미터의 이름이다. param과 value를 모두 사용할 수 없으며, 하나를 선택하여 사용하는 것은 가능하다.