스프링
- 오픈소스 프레임워크다.
- 오픈소스 : 라이센스 무료, 가공/수익창출 허용
- 프레임워크 : 특정한 아이디(개발방식, 개발패턴, 아키텍처)의 구현체다.
- 라이브러리와 프레임워크
- 라이브러리 : 개발에 필요한(자주 사용되는) 기능의 구현체다.
필요한 기능이 구현되어 있는 라이브러리를 다운받아서 그 라이브러리의 기능을 사용한다.- 프레임워크 : 개발방식, 개발 패턴의 구현체다.
개발자는 해당 프레임워크에 제시하는 방식에 맞게 클래스나 인터페이스, 환경설정 정보를 구성하면 프레임워크가 제공하는 기능을 제공받을 수 있다.- JaVa 기반의 엔터프라이즈 애플리케이션 개발을 지원하는 프레임워크다.
- DI(의존성 주입)의 구현체다.
* 의존성 주입은 스프링의 가장 핵심적인 개념이다.
- 인터페이스를 이용해 클래스와 클래스간의 결합을 느슨하게 유지하고, 의존성 주입으로 의존하는 객체를 주입한다면, 코드의 변경없이 의존하는 객체를 변경할 수 있다.
- 즉, 확정성이 매우 뛰어난 애플리케이션을 개발할 수 있다.
- AOP(관점지향 프로그래밍)의 구현체다.
* 관점지향 프로그램은 프로그램의 공통관심사항을 핵심기능으로부터 분리시키는 것이다.
- 관점은 코드를 바라보는 시각이다. ("메소드 안에 무엇이 있지?"로 보는 것)
- 공통관심사항 = 모든 메소드 안에 공통적으로 포함되어 있는 것 Ex)로그 출력
- 핵심관심사항 = 각 메소드 안에 있는 다른 메소드와 다른 것 Ex)
- 공통관심사항을 제거하는 것!
- 관점은 코드를 핵심관심사항(핵심기능)과 공통관심사항(공통기능)으로 구분하는 것이다.
- 스프링의 AOP는 공통관심사항을 별도의 모듈(Advice와 Pointcut)로 개발하고, 공통관심사항이 적용될 대상과 시점을 지정하면 핵심기능이 구현된 메소드가 실행될 때마다 공통기능을 실행시킨다.
- 즉, 메소드에서 공통관심사항 코드를 제거할 수 있다. (중복코드의 제거)
- 스프링은 객체를 생성하는 공장이다. (Bean Factory다. Bean은 객체다.)
- 스프링은 객체를 조립한다.(객체간의 의존관계를 분석해서 필요로 하는 객체를 주입한다.)
- 애플리케이션에서 사용되는 객체의 라이프사이클(객체 생성, 조립, 유지/관리)을 관리한다.
- 스프링 컨테이너의 종류
BeanFactory
spring-bean.jar에 포함되어 있는 스프링 컨테이너 인터페이스다.
객체 생성, 객체 조립과 같은 간단한 기능만 제공하는 스프링 컨테이너다.
구현클래스 : XmlBeanFactory
ApplicationContext
spring-context.jar에 포함되어 있는 스프링 컨테이너 인터페이스다.
객체 생성, 객체 조립, 관점지향 프로그래밍 지원, 국제화, EJB 연동 등 다양한 기능을 제공하는 스프링 컨테이너다.
구현 클래스 : ClasspathXmlApplicationContext, FilesystemXmlApplicationContext, GenericXmlApplicationContext, WebApplicationContext
WebApplicationContext
spring-web.jar에 포함되어 있는 스프링 컨테이너 인터페이스다.
ApplicationContext 인터페이스와 기능은 유사하고, 웹 환경에 최적화되어 있는 스프링 컨테이너 인터페이스다.
구현 클래스 : XmlWebApplicationContext
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] [%-5level] %logger{36}.%M - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
spring/context-1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<!--
스프링 빈 설정파일에 생성할 객체 정보 설정하기
-->
<bean class="com.sample.controller.UserController"></bean>
<bean class="com.sample.dao.UserOracleDao"></bean>
</beans>
App1.java
package com.sample.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App1 {
public static void main(String[] args) {
// 스프링 설정파일의 경로
String resource = "spring/context-1.xml";
// 스프링 컨테이너 생성하기
ApplicationContext ctx = new ClassPathXmlApplicationContext(resource);
}
}
실행결과
실행결과(id를 입력했을 때)
context-1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<!--
스프링 빈 설정파일에 생성할 객체 정보 설정하기
-->
<bean id="userContoller" class="com.sample.controller.UserController"></bean>
<bean id="userOracleDao" class="com.sample.dao.UserOracleDao"></bean>
</beans>
OrderController
package com.sample.controller;
import com.sample.dao.OrderOracleDao;
import com.sample.dao.UserOracleDao;
public class OrderController {
private OrderOracleDao orderOracleDao;
private UserOracleDao userOracleDao;
public void setOrderOracleDao(OrderOracleDao orderOracleDao) {
this.orderOracleDao = orderOracleDao;
}
public void setUserOracleDao(UserOracleDao userOracleDao) {
this.userOracleDao = userOracleDao;
}
public void test() {
System.out.println("### OrderController 객체에 조립된 객체 확인하기");
System.out.println(orderOracleDao);
System.out.println(userOracleDao);
}
}
context-1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<!--
스프링 빈 설정파일에 생성할 객체 정보 설정하기
-->
<bean id="userContoller" class="com.sample.controller.UserController">
<!--
<bean>은 객체 생성 태그 / <property>는 객체 조립하는 태그
"userController"에 있는 userOracleDao에게 "userOracleDao"의 userDao를 참조하게 한다.
-->
<property name="userOracleDao" ref="userDao"></property>
</bean>
<bean id="orderController" class="com.sample.controller.OrderController">
<property name="orderOracleDao" ref="orderDao"></property>
<property name="userOracleDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.sample.dao.UserOracleDao"></bean>
<bean id="orderDao" class="com.sample.dao.OrderOracleDao"></bean>
</beans>
App1.java
package com.sample.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sample.controller.OrderController;
import com.sample.controller.UserController;
public class App1 {
public static void main(String[] args) {
// 스프링 설정파일의 경로
String resource = "spring/context-1.xml";
// 스프링 컨테이너 생성하기
ApplicationContext ctx = new ClassPathXmlApplicationContext(resource);
// 스프링 컨테이너에서 객체 가져오기
UserController controller = ctx.getBean(UserController.class);
controller.test();
OrderController controller2 = ctx.getBean(OrderController.class);
controller2.test();
}
}
실행 결과
실행 과정
- 스프링 컨테이너는 설정정보를 저장해서 조립을 해준다.
- 의존성 주입을 사용하였다!
의존성 주입을 사용하지 않은 예
의존성 주입을 사용한 예
- @Autowired 라는 것을 통해 의존성을 조사한다.
- 필요한 객체를 상관하지 않고 로직 구현만 신경쓸 수 있게 된다.
의존성 주입을 사용하지 않았을 때
- 여러개의 클래스가 존재한다.
- DB를 변경하게 되면, 기존의 클래스를 사용하지 못한다.
- DB를 변경하게 되면, 소스코드를 변경해야 한다.
- 매 번 바꿀 수는 없다. (유연성 / 확장성이 떨어진다.)
의존성 주입을 사용했을 때
- 인터페이스를 생성
(생성 목적 : 사용방법을 통일시키기 위해 / 구현객체를 JaVa코드 변경 없이 교체할 수 있다.)- UserDao 인터페이스 내부에는 UserDao 속성이 포함되어 있다.
- Spring에 객체 생성을 의뢰 구현 클래스(UserController / OrderController / UserOOODao)
- @Autowired가 있으면 그 타입의 객체를 찾는다.
- 구현 클래스는 각 DB에 맞게 생성되었다.
- 그러나 다른 종류의 DB로 변경해도 Spring의 설정 변경을 통해 다른 DB의 구현클래스를 생성을 의뢰할 수 있다.
- 그렇게 코드 변경 없이 사용하는 객체를 변경할 수 있다.
주의 점
- 인터페이스에 의존해야 한다!
- Controller에 구체적인 클래스 이름이 등장하지 않아야 한다.(직접 만들면 안된다!)
- 클래스가 클래스를 의존하게 하면 안된다! (인터페이스를 의존해야 한다!)
- 인터페이스를 의존해야 어떤 DB와도 연결이 가능하다.
핵심
- controller가 의존하는 객체를 코드 변경 없이 변경할 수 있다!
- controller는 직접 클래스(객체)생성을 하면 안된다.
- controller가 구체적인 클래스를 의존하게 하면 안된다.(인터페이스를 의존해야 한다.)
- 클래스-클래스 간의 의존(강한 결함)x , 클래스-인터페이스 간의 의존(느슨한 결합)O
Advice클래스
- 로그/TransactionManager를 만들고 각각의 공통관심사항이 포함된 Advice 클래스를 만든다.
- 각각의 프로그램에 Target을 지정한다.
- Target은 어떤 Advice 적용 대상을 지정해준다.
- Advice와 Target은 한 세트!
Advice의 작성 예
- "@Aspect"(관점)을 적는다.
- "@Autowired"(의존성 주입)를 적는다.
- 공통관심사항 실행시점(@Before) : ~전에
- 공통관심사항 적용대상("within(com.sample.service.'Service)") : (com.smple.service 클래스 안의 모든 Servcie가 실행 될 때)
- 공통 관심사항(public void logging() {logger.info("로그출력")}) : (실행해라.)
- 스프링의 관점지향 프로그래밍
- AOP관련 @어노테이션을 이용해서 설정한다.
- @Aspect: 관점지향 프로그래밍 관련 객체임을 나타내는 어노테이션이다.
- @Before: 공통관심사항을 실행할 시점을 나타내는 어노테이션이다.
- @Before, @After, @AfterReturning, @AfterThrowing, @Around
- "within(com.sample.service."Service)" : 포인트컷(Pointcut Expression)이다.
- 포인트컷은 공통관심사항 적용대상을 나타내는 표현식이다.
- 예제의 표현식은 패키지명이 com.sample.service이고,
- 클래스명이 Service로 끝나는 모든 클래스의 메소드가 적용대상이다.
- 핵심기능이 구형된 메소드에서 공통관심사항 코드를 제거할 수 있다.(코드중복이 제거된다.)
- 핵심기능이 구현된 메소드의 코드 변경없이 공통관심사항을 추가/삭제할 수 있다.
- 핵심기능에 대한 유지 보수가 쉬워진다.
- 핵심기능의 재사용성도 높아진다.
(핵심기능밖에 없어도 특별한 라이브러리(로그출력라이브러리 등))
- 자바의 프로젝트 관리 도구다.
- 프로젝트의 라이브러리 의존성, 소스 커파일, 패키징, 배포 등의 작업을 자동화 할 수 있다.
- 프로젝트 생성/관리하는 도구다.
* 메이븐 프로젝트는 pom.xml 파일을 포함하고 있다.
- pom.xml 파일은 프로젝츠 정보를 표현하는 파일이다.
- pom.xml 파일은 프로젝트의 최상위 폴더에 위치하고 있다.
- pom.xml의 POM(Porject Object Model)을 설정하는 파일이다.
- POM은 메이븐에서 프로젝트를 표현하는 객체다.
* pom.xml의 주요 구성 요소
- 프로젝트 정보
<groupId />
프로젝트를 생성하는 조직 또는 그룹명을 나타낸다.
보통 URL의 역순으로 지정한다.
<artifactId />
프로젝트의 고유한 아이디다.
프로젝트 산출물의 교유한 아이디다.
프로젝트의 명과 같은 이름이다.
<version />
애플리케이션의 버전을 나타낸다.
release는 출시 버전 /
<packaging />
프로젝트 패키징 유형을 나타낸다.
jar, war, ear, pom 중 하나를 지정한다. 지정하지 않으면 jar다.
<name />
프로젝트 명이다.
<description />
프로젝트에 대한 설명이다.
<url />
프로젝트를 찾을 수 잇는 URL이다.
<properties />
pom.xml에서 중복해서 사용되는 설정값을 지정한다.
- 의존성 라이브러리 정보
의존성 라이브러리를 정의하는 부분이다.
프로젝트에서 사용하는 라이브러리 정보를 정의한다.
라이브러리정보는 groupId, artifactId, version 정보가 필요하다.
- 빌드 정보
프로젝트의 빌드/배포와 관련된 설정정보를 정의하는 부분이다.
제일 중요한 것은 스프링의 의존성 주입과 관점지향 프로그래밍이다!