Spring과목 학원 수강도하고 따로 Spring Boot와 Docker, Kubernetes를 이용해 Microservices Architecture로 서비스를 구축하는 프로젝트를 진행했지만 Spring에 대한 뚜렷한 개념이 잡혀있지 않았던 것 같다. 그 때문에 프로젝트를 진행하였어도 내가 "Spring을 잘한다"라는 생각을 나 스스로도 갖지 못했다. 그 때문에 앞으로 한동안은 Spring에 대한 공부를하며 포스팅을 할 예정이다.
항상 그랬듯 왜 사용하는지 어떤 배경을 가지고있는지를 먼저 파악하면 공부를 하는데에 많은 도움이 되는것 같다. 또한 어떤 부분에 목적을 두고 공부를 해야하는지 역시 알 수 있기 때문에 더 빠르고 올바른 방향으로 공부를 해나아갈 수 있는것 같다.
1.1 Spring(스프링)을 사용하는 이유?
Spring을 왜 써야할까? Spring은 개발자라면 한번 쯤 들어봤을 어플리케이션 개발 프레임워크
이다. JSP, Servlet, PHP, 등등 그냥 웹을 개발할 수도 있는데 왜 Spring이라는 프레임워크를 사용해야 할까? 먼저 스프링이 나타나기 이전 2000년대 초반의 자자 Enterprise Project중 80%가 실패했다. 엔터프라이즈 시스템 개발이 너무 복잡했기 때문이다. 그렇다면 왜 복잡했을까. 시스템 개발시 비즈니스 로직이외에도 고려할 사항들이 많다
(타시스템과의 연계, 분산 트랜잭션 지원, 보안 등) 또한 개발이 진행됨에 따라 비지니스 로직이 점점 복잡
해지고 잦은 변경이 요구
되기 때문이다.
스프링은 위와같은 복잡함을 해결하기 위한 다양한 특징을 가지고 있다. DI , AOP, PSA
가 바로 그것이다. 각각을 조금 더 상세히 살펴보자.
1.2 Spring의 특징
1.2.1 DI(Dependency Injection)
*의존성
프로그램 개발을 진행하다 보면 객체간의 의존성이 생기기 마련이다. 그렇다면 의존성이란 무엇일까? 아래와 같은 코드를 보자.
Cook(요리사)
클래스는 cook()메소드를 실행 할 때에 cut()을 위해서 Knife
클래스가 필요하다 이러한 상황을 Cook 클래스가 Knife에 의존성을 가지고 있다(의존하고 있다)
라고한다. 그렇다면 의존성이라는것이 왜 안좋은것일까? 의존성에 의한 문제점들은 아래와 같다
1. Unit Test가 어려워진다.
- 내부에서 직접 생성하는 객체에 대해서, mocking을 할 방법이 없습니다. 따라서 그만큼 단위테스트를 하기가 까다로워집니다.
2. Code의 변경이 어려워진다.
- Cook 클래스는 생성자에서 Knife객체를 직접 생성하여 사용하고 있다. 만약 나중에 Knife라는 클래스가 Rose Knife(장미칼)
등으로 바뀐다면 지금 처럼 Knife 클래스에 의존하고 있는 Cook의 클래스도 직접 같이 변경
해주어야 한다. 즉, 객체간의 강한 결합력
이 생긴다. 소프트웨어 모듈화의 목적인 낮은 결합력과 높은 응집도
에 해가 가는 행위가 되는 것이다.
*의존성 주입(Spring 사용 전)
위와 같은 문제점 때문에 의존성 주입
이 생겨났다. 의존성을 주입하지 않는 경우는 위와 같이 직접 필요한 객체를 생성하는 경우라고 보면 된다. 의존성 주입을 하는 경우는 다음과 같은 경우가 있다.
1. 생성자를 통해 전달받음
2. setter를 통해 전달 받음
그럼 위와 같은 방법을 사용하면 왜 좋을까?
바로 코드의 수정이 용이
하다는 것이다. 앞서 말했듯이 Knife
클래스를 RoseKnife
클래스로 변경을 해야하는 상황일 때. 의존성을 주입하지 않는다면 Cook
클래스의 직접 Knife를 생성하는 부분을 바꾸어주어야 한다. 의존성을 주입하는 상황에서도 주입하는 코드를 변경해주어야 하는것은 똑같지만 한 클래스를 수정했을 때 다른 클래스를 수정해야 하는 상황
을 막아준다.
*DI(Spring 사용)
위와 같은 이유로 스프링은 DI라는 방식을 이용하여 모듈간의 결합도를 낮추어준다. DI
란 IOC Container
가 개발자 대신 xml
파일에 정의된 대로Bean
객체를 생성하고 의존성을 대신 주입
하는 것을 의미한다. IOC
란 제어의 역전 이라는 말로 사용자가 직접 객체를 생성하고 관리하던 것을 spring의 IOC Container가 대신 해준다는 말이다.
DI를 통해 개발자가 해야하는 일은 다음과 같아졌다.
- Bean class 작성
- 주입을 위한 설정(xml파일 기술 또는 @(어노테이션) 기술)
*IOC Container(Spring Container)
IOC Container
란 사용자가 작성한 메타데이터(xml 파일 또는 @(어노테이션))에 따라 Bean클래스를 생성 및 관리 하는 Spring의 핵심 컴포넌트.
자세한 설명 : https://blog.outsider.ne.kr/735
IOC Container의 설정 방법
1. XML 파일 기술
- XML 파일을 이용하여 설정하게 된다면 Code와 의존성을 주입하는 부분을 분리할 수 있다. 따라서 유지보수성을 높일 수 있다. 하지만 시스템이 거대해지다 보면 XML파일이 너무 많아
지게 되어 오히려 유지보수가 어려워진다
.
장점 : 각 객체들관의 의존관계를 한눈에 볼 수 있다.
단점 : 규모가 커짐에 따라 XML에 기술할 내용이 많아지면 생산성이 저하 된다.
2. @(어노테이션) 사용
- 프로그램의 규모가 커지면서 XML에 기술할 내용이 많아졌다. 그 때문에 오히려 유지 보수성이 떨어지는 XML 때문에 Annontation(@)이 등장했다.
장점 : 보다 더 직관적인 코드 작성이 가능해진다.(메타데이터와 소스코드를 같이 기술하기 때문), 개발의 생산성이 증대 된다.
IOC Container의 유형
IOC 컨테이너는 위 그림과 같이 2가지의 유형이 있다.
1. BeanFactory(XmlBeanFactory) // 현재 Deprecated 되었습니다.
- BeanFactory
의 경우 간단한 DI를 하는 경우 사용한다.
2. ApplicationContext(ClassPathXmlApplicationContext)
- 조금 더 복잡하고 진전된 경우에 사용된다.
*DI 예제
먼저 사람
이 있고 사람은 물건
에 따라 다른 행위
를 한다. 물건은 Computer, Book
등이 존재한다. 필요한 클래스는 아래와 같이 정의 했다.
1. Person Class
2. Computer Class
3. Book Class
또한 각각의 물건들은 어떠한 행위를 하도록하기 때문에 Goods
라는 Interface
를 구현하도록 했다.
1. Goods
DI예제 - 1 (XML 사용)
Person Class
xpublic class Person {
private Goods goods;
private String name;
public Person(String name){
this.name = name;
}
public void doSomething() {
this.goods.doSomething();
}
public Goods getGoods() {
return goods;
}
public void setGoods(Goods goods) {
this.goods = goods;
}
}
Goods Interface
xxxxxxxxxx
public interface Goods {
void doSomething();
}
Computer Class
xxxxxxxxxx
public class Computer implements Goods{
public void doSomething() {
System.out.println("Play ComputerGame!");
}
}
Book Class
xxxxxxxxxx
public class Book implements Goods{
public void doSomething() {
System.out.println("Read a book!");
}
}
goods.xml
xxxxxxxxxx
<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">
<!-- Computer Class의 Bean -->
<bean id="computer" class="com.java.ex.Computer"/>
<!-- Book Class의 Bean -->
<bean id="book" class="com.java.ex.Book"/>
<!-- Person Class의 Bean -->
<bean id="person" class="com.java.ex.Person">
<constructor-arg name="name" value="jjy"/>
<property name="goods" ref="book"/>
</bean>
</beans>
Person의 property 태그를 이용하여 Book
Bean을 주입할 수 있는 이유는 Person
Class에 Setter
메소드가 있기 때문이다. 따라서 Setter메소드는 꼭 필요하다.
xml파일 생성시 아래와 같이 resources 디렉토리 하위에 Spring Bean Configuration File
을 생성하면 된다.
main
xxxxxxxxxx
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
String beanXml = "goods.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
Person person = (Person)context.getBean("person");
person.doSomething();
}
}
ClassPathXmlApplicationContext(IOC Container)
를 생성한 뒤 getBean("Bean id")
을 이용하여 IOC Container
에서 컴포넌트를 가져온다. 그 후 XML 파일에 따라 Person이 필요한 Goods
가 주입된다. 이를 통해 결국 사용자는 Java Code를 더이상 수정할 필요가 없고 XML파일만을 수정
하여 프로그램을 변경 할 수 있다. Annotation을 이용해서 의존성을 주입하는 방법이 있는데 다음 포스팅에서 알아보도록 하겠다.
'FrameWork > Spring' 카테고리의 다른 글
Spring - AOP관련 Annotation - 4 (0) | 2019.03.29 |
---|---|
Spring - Spring을 왜 사용하나요?(AOP) - 3 (2) | 2019.03.29 |
Spring - @Bean 어노테이션과 @Component 어노테이션(DI) - 2 (6) | 2019.03.26 |
SpringBoot - JSP 환경 설정(Gradle , Maven) (0) | 2019.01.29 |
톰캣 Error copying file to C:/Program Files/ , Publishing to Tomcat v8.0 Server 에러 (0) | 2018.11.11 |