프로그래밍 언어/Spring

[Spring]Spring Framework기초, IOC,DI

좨랭이 2022. 1. 12. 03:00

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의  구성  모듈

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 동작 구조

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. @어노테이션으로 설정