[Spring]Spring Framework기초, IOC,DI
Spring Framework란?
- 자바 애플리케이션 개발을 위한 오픈소스 프레임워크
- 웹애플리케이션 개발에 한정되어있지 않다. -> 여러가지 프로그램 개발 가능
- 스프링을 사용하면 애플리케이션 쉽게 개발하고 테스트도 쉽게 가능
- 낮은 결합도를 이룰 수 있다.
Spring Framework 특징
DI (Dependency Injection) 의존성 주입 |
설정 파일이나 어노테이션을 통해 객체간의 의존 관계를 설정하여 개발자가 직접 의존하는 객체를 생성할 필요가 없다. (기존에는 개발자가 직접 관계를 설정함 -> 프레임워크가 관계를 설정) => 결합도를 낮출 수 있다. |
Spring AOP (Aspect Oriented Programming) 관점 지향 프로그래밍 |
트랜잭션, 로깅, 보안 등 여러 모듈, 여러 계층에서 공통으로 필요로 하는 기능의 경우 해당 기능들을 분리하여 관리한다. (로깅이나 트랜젝션, 보안같은 공통기능) => 비지니스로직에 더 집중할 수 있다. |
POJO (Plain Old Java Object) |
일반적인 J2EE 프레임워크에 비해 특정 라이브러리를 사용할 필요가 없어 개발이 쉬우며, 기존 라이브러리의 지원이 용이하다. |
IOC (Inversion of Control) 제어 반전 |
- 컨트롤의 제어권이 개발자가 아니라 프레임워크에 있다는 뜻으로 객체의 생성부터 모든 생명주기의 관리까지 프레임워크가 주도하고 있다. - 객체를 생성하고, 직접 호출하는 프로그램이 아니라, 만들어둔 자원을 호출 해서 사용한다. |
Spring JDBC | Mybatis나 Hibernate 등의 데이터베이스를 처리하는 영속성 프레임워크와 연결할 수 있는 인터페이스를 제공한다. |
Spring MVC | MVC 디자인 패턴을 통해 웹 어플리케이션의 Model, View, Controller 사이 의 의존 관계를 DI 컨테이너에서 관리하여 개발자가 아닌 서버가 객체들을 관리하는 웹 애플리케이션을 구축 할 수 있다. (MVC를 구현할 수 있는 모듈 제공) |
PSA (Portable Service Abstraction) |
- 스프링은 다른 여러 모듈을 사용함에 있어 별도의 추상화 레이어를 제공한다. - 예를 들어 JPA를 사용할 때에서 Spring JPA를 사용하여 추상화하므로 실제 구현에 있어서 Hibernate를 사용하든 EclipseLink를 사용하든 개발자는 이 모듈의 의존 없이 프로그램에 집중할 수 있다. (사용하는 기술이 변화하여도 비지니스로직에 변화가 없다.) |
Spring의 구성 모듈
Data 접근 계층 : JDBC나 데이터베이스에 연결하는 모듈로, Data 트랜잭션에 해당하는 기능을 담당하여 영속성 프레임워크의 연결을 담당한다.
Web 계층 (MVC / Remoting) :
- Spring Framework에서 Servlet, Struts 등 웹 구현 기술과의 연결을 Spring MVC 구성으로 지원하기 위 해 제공되는 모듈 계층이다.
- 또한 스프링의 리모팅 기술로 RMI, Hessian, Burlap, JAX-WS, HTTP 호출자 그리고 REST API 모듈을 제공 한다.
AOP 계층 : Spring에서 각 흐름 간 공통된 코드를 한 쪽으로 빼내어 필요한 시점에 해당 코드를 첨부하게 하기 위해 지원하는 계층으로, 별도의 proxy를 두어 동작한다. 이를 통해 객체간의 결합도를 낮출 수 있다.
Core Container 계층 :
- Spring의 핵심 부분이라고 할 수 있으며 모든 스프링 관련 모듈은 이 Core Container 기반으로 구축된다.
- Spring의 근간이 되는 IoC(또는 DI) 기능을 지원하는 영역을 담당하고 있다.
- BeanFactory를 기반으로 Bean 클래스들을 제어할 수 있는 기능을 지원한다.
Spring 동작 구조
- IOC / DI 프레임워크에서 객체관리 -> 모든 객체를 프레임워크에서 관리할 필요는 없음
=> 프레임워크에게 객체의 설정, 객체간 관계를 spring=context.xml에 기록
- spring에서 관리하는 객체를 bean이라고 부른다.
Spring IOC(제어 반전)이란?
- IoC란, Inversion of Control의 약자로 프로그램을 구동하는데 필요한 객체에 대한 생성, 변경 등의
관리를 프로그램을 개발하는 사람이 아닌 프로그램을 구동하는 컨테이너에서 직접 관리하는 것을 말한다.
- 스프링은 IoC 구조를 통해 구동 시 필요한 객체의 생성부터 생명주기까지 해당 객체에 대한 관리를 직접 수행한다.
-> 결합도를 낮추기 위해
IoC 컨테이너
스프링에서 관리하는 객체를 ‘Bean(빈)’이라고 하고, 해당 빈들을 관리한다는 의미로 컨테이너를 ‘Bean Factory’라고 한다.
- 최상위에 BeanFactory가있고 여러가지 기능을 추가하여 ApplicationContext(BeanFactory상속) 만들어진다.
IoC 컨테이너의 역할
1. 객체의 생명주기와 의존성을 관리한다.
2. VO (DTO / POJO) 객체의 생성, 초기화, 소멸 등의 처리를 담당한다.
3. 개발자가 직접 객체를 생성할 수 있지만 해당 권한을 컨테이너에 맡김으로써 소스 코드 구현의 시간을 단축할 수 있다.
IoC 컨테이너와 Bean 객체
Bean 빈 |
- 스프링이 IoC 방식으로 관리하는 Class - 스프링이 직접 생성과 제어를 담당하는 객체 |
Bean Factory 빈 팩토리 |
- 스프링의 IoC를 담당하는 핵심 컨테이너 - Bean을 등록, 생성, 조회, 반환하는 기능을 담당 |
ApplicationContext 애플리케이션 컨텍스트 |
- BeanFactory를 확장한 IoC 컨테이너 - Bean을 등록하고 관리하는 기능은 BeanFactory와 동일하지만 스프링이 제공하는 각종 부가 서비스를 추가로 제공함 (애플리케이션에서 사용하는 객체관리 ) |
GenericXmlApplication Context |
- ApplicationContext 를 구현한 Class - 일반적인 XML 형태의 문서를 읽어 컨테이너 역할을 수행 |
Configuration metadata 설정 메타 정보 |
- ApplicationContext 또는 BeanFactory가 IoC를 적용하기 위해 사용하는 설정 정보 - 설정 메타 정보는 IoC 컨테이너에 의해 관리되는 Bean 객체를 생성하고 구성할 때 사용 (xml,java형태) |
Spring DI (Dependency Injection)란?
DI란, Dependency Injection의 약자로 IoC 구현의 핵심 기술이라고 할 수 있다.
사용하는 객체를 직접 생성하여 만드는 것이 아니라 컨테이너가 빈의 설정 정보를 읽어와 자동으로 해당 객체에 연결하는 것을 의미한다.
-> 의존성을 주입 받게 되면 이후 해당 객체를 수정해야 할 상황이 발생했을 때 소스 코드의 수정을 최소화 할 수 있다.
- 개발자가 작성해야 할 코드가 단순해진다.
- 각 객체 간의 종속 관계(결합도)를 해소할 수 있다.
* 객체간의 종속 관계 (결합도) : 한 클래스에서 필드 객체를 생성할 때 발생하는 두 객체 간의 관계를 말하며,
각 객체간의 내용이 수정될 경우 영향을 미치는 정도를 나타낸다.
Spring DI (Dependency Injection) 종류
- Setter 메소드를 통한 의존성 주입 : 의존성을 주입 받는 Setter 메소드를 만들고, 이를 통해 의존성을 주입
- 생성자를 통한 의존성 주입 : 필요한 의존성을 포함하는 클래스에 생성자를 만들고, 이를 통해 의존성을 주입
- 메소드를 통한 의존성 주입 : 의존성을 입력 받는 일반 메소드를 만들고 이를 통해 의존성을 주입
>> 실습 pom.xml설정
1. 프로젝트 생성
Spring legacy project - Spring MVC Project - top-level package(com.kh.프로젝트명) ** 도메인의 역순
Spring 프로젝트 구조
- resources : 프로젝트관련 필요한 환경설정, 자원들 위치
- webapp : 웹관련 파일(html, css, javascript, img)
메인 구조
webapp 구조
- main > resources : propertice등 프로젝트실행에 대한 설정파일
- WEB-INF 밑에 views가 있음 : WEB-INF를 직접접근 할 수 없으므로 (jsp는 가능)
- spring : spring 설정
- webapp > resources : 웹관련
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kh</groupId>
<artifactId>di</artifactId>
<name>02_SpringDI</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<!-- 자바 버전 및 스프링 프레임워크 버전을 변경 -->
<java-version>11</java-version>
<org.springframework-version>5.3.14</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- JSTL -->
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-impl</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-spec</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-jstlel</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>org.apache.taglibs</groupId>
<artifactId>taglibs-standard-compat</artifactId>
<version>1.2.5</version>
</dependency>
<!-- lombok 라이브러리 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.21.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.10</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
1. java-version(11) 확인
2. spring 최신 버전 확인 spring 홈 - Current / GA(정식버전) , Maven repository
3. Servlet 최신 버전 (Servlet API, javaServer Pages(TM) API)
4. jstl (taglibs) - 4개 MVC할때 했던) -> spring에서 jstl라이브러리 찾기 못함(500에러)
WEB-INF에 lib폴더 생성 - 안에 jar파일 복붙
5. maven-eclipse-plugin 최산 버전
6. source, target을 ${java-version}
7. plugin 최신 버전
8. lombok, junit(test관련) 라이브러리 추가
인코딩 (스프링에서 제공되는 인코딩 필터를 등록해야한다.)
web.xml
<!--
UTF-8 인코딩 필터
필터를 직접 만들어서 등록해도 되지만, 스프링에서 인코딩 필터를 제공하고 있기 때문에 web.xml에 필터를 등록해 주기만 하면 된다.
-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> // 스프링에서 제공
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern> // /* 모든 url에 대해서 인코딩필터를 타게끔
</filter-mapping>
- forceEncoding true : 인코딩될 대상(request, response)를 강제로 인코딩
** MVC 구조 (간단하게 설명)
현재 보이는 화면 views - home.jsp 출력
- home.jsp 직접 연것이 아님! -> WEB-INF 사용자가 직접접근하는 것을 허용하지 않음
- 그럼 누가 처리?? - >HomeController가 요청을 처리!
>> DI 실습
Owner와 Dog로 결합도가 높은 테스트 코드를 작성하였다. (하나를 수정하면 연결되어있는 모든 부분을 일일이 수정)
-> DI를 하여 의존성을 주입해야 한다.!!
DI는 Bean(스프링에서 관리하는 객체 - 자동!) 모든 객체를 자동으로 생성하는 것이아니라 개발자가 알려줘야함
알려주는 방법 3가지
1. xml을 통해서 설정
2. java설정파일을 통해서 설정 config
3. @어노테이션으로 설정