스프링 원리

김수정·2020년 6월 29일
1

스프링/스프링부트

목록 보기
1/11

1. 스프링이란?

자바 웹프레임워크입니다. 비즈니스 로직에만 집중할 수 있도록 환경을 조성해주어 자바개발자들이 꼭 사용하는 툴입니다.
스프링의 큰 특징들을 살펴보며 스프링을 이해해 보겠습니다.

2. Inversion of Control

의존성을 역전시킨다는 뜻입니다.

의존성이란 예를 들어 자식이 이세상에 태어나서 자라기 위해서 부모가 꼭 있어야 하죠? 자식은 부모에게 의존성을 갖고 있습니다.
코드적으로 얘기하면 A객체가 존재하기 위해서 B객체가 꼭 있어야 한다면 A객체는 B객체에 의존성이 있는 것입니다.
보통 new 생성자를 통해 의존성이 탄생합니다.

그런데 로직은 비슷한데 어떤 대상을 생성해내느냐만 다르다면 무수한 조건문과 중복 코드들이 발생할 것입니다.
이를 해결하기 위해 A객체에서 생성자를 실행하지 않고 어떤 형태의 객체를 받을지만 지정해놓습니다.
이렇게 의존성을 역전하게 되면 객체 간의 결합도를 줄이고 유연한 코드를 작성하게하여 가독성 및 코드의 중복, 유지보수를 편하게 해줍니다.
상세한 예는 이 글에서 확인하시면 좋습니다.

// 일반적인 제어방법
class OwnerController {
   private OwnerRepository repository = new OwnerRepository();
}
// IoC
class OwnerController {
   private OwnerRepository repo;

   public OwnerController(OwnerRepository repo) {
       this.repo = repo;
   } 

   // repo를 사용합니다.
}

Container

IoC Container를 이해하기 위한 사전 지식을 좀 봅시다.
컨테이너란 특정 객체의 생성과 관리를 담당하여 객체 운용에 필요한 다양한 기능을 제공합니다.
스프링 컨테이너는 bean저장소에 해당하는 XML설정 파일을 참조하여 bean의 생명주기를 관리하고 여러가지 서비스를 제공합니다.

BeanFactory
스프링 설정파일(applicationContext.xml)에 등록된 bean객체를 생성하고 관리. 클라이언트로부터 요청이 있을때만 객체를 생성.

ApplicationContext
BeanFactory 컨테이너를 확장하여 트랜잭션이나 다국어 처리등의 기능을 추가 지원합니다.

Bean

스프링이 관리하는 객체입니다. 의존성을 주입해줄 수 있는 객체입니다.
Bean의 범위는 인스턴스의 갯수에 따라 나뉩니다.

싱글턴 - 딱 하나의 유일한 인스턴스만 제공. default
프로토타입 - 빈을 가져올 때마다 다른 인스턴스를 제공.

appContext.xml에서 빈에게 scope 속성으로 명시해 주면 됩니다.

<bean id="knifePlayer" class="com.tutorial.spring.Player" scope="prototype">
  <property name="weapon" ref="knife"/>
</bean>

IoC Container

Bean을 만들고 엮어주며 제공해줍니다.
빈 만이 의존성 주입이 가능합니다. 즉 IoC 컨테이너에 담긴 객체들만 의존관계 주입이 가능합니다.

3. Dependency Injection

의존성 주입은 객체가 필요로하는 어떤 객체를 생성자 혹은 Setter를 통해서 주입하는 것입니다.
의존성 역전의 법칙을 지키면서 어떻게 의존성을 주입하는지, 즉 스프링에서 B객체에 의존성이 있는 A객체가 어떻게 B객체를 받아오는지를 살펴봅시다.

Bean 등록

등록하면서 의존성을 주입하는 방법은 두 가지(생성자로 주입, Setter로 주입)입니다.

1) applicationContext.xml 방식

src/main/resources에 적당한 이름으로 .xml파일을 만들어줍니다. 통상 applicationContext.xml로 합니다.
규칙은 id값과 class값을 bean태그에 속성으로 넣어줍니다.
id는 bean의 식별자이고, class는 실질적인 class입니다.
DI를 할 때 생성자의 방식이라면 <constructor-arg>를 Setter라면 <property>태그로 주입하고,
주입할 bean객체는 ref="<id명>"으로 입력합니다.

<-- appContext.xml -->
<-- 스프링 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="gun" class="com.tutorial.spring.Gun"/>
    <bean id="knife" class="com.tutorial.spring.Knife"/>
    <bean id="spike" class="com.tutorial.spring.Spike"/>

    <bean id="gunPlayer" class="com.tutorial.spring.Player"> <!-- 생성자 DI -->
        <constructor-arg ref="gun"/>
    </bean>
    <bean id="knifePlayer" class="com.tutorial.spring.Player"> <!-- setter DI -->
        <property name="weapon" ref="knife"/>
    </bean>
    <bean id="spikePlayer" class="com.tutorial.spring.Player">
        <property name="weapon" ref="spike"/>
    </bean>

</beans>

출처: https://engkimbs.tistory.com/677?category=767795 [새로비]

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appContext.xml");

Player gunPlayer = ctx.getBean("gunPlayer", Player.class);
gunPlayer.usePlayerWeapon();

2) java config

3) annotation 방식

Automatic Dependency Injection 방식입니다.
스프링 설정 파일(xml)에서 <constuctor-arg> 혹은 <property>태그를 쓰지 않고 자동으로 스프링이 의존성을 주입해 줍니다.

applicationConfig.xml에 <context:annotation-config /> 구문을 추가해야 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    <context:annotation-config/>
...
</beans>

Bean 사용

1)번 방식으로 등록한 Bean을 가져오려면 빈 정보를 등록한 xml파일에서 getBean메소드로 꺼내옵니다.
getBean의 파라미터는 주입할 Bean, 주입당할 클래스 순입니다.

import org.springframework.context.support.GenericXmlApplicationContext;

public class LearnSpringApplication {

    public static void main(String[] args) {
      	GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("classpath:appContext.xml");
      	Player gunPlayer = ctx.getBean("gunPlayer", Player.class);
      	gunPlayer.usePlayerWeapon();
    }
}

3)번 방식으로 등록한 Bean을 가져오려면

@Autowired
주입하려는 객체의 타입이 일치하는 객체를 찾아 자동 주입. 없으면 @Autowired에 위치한 속성명이 일치하는 bean을 컨테이너에서 찾음. 이름이 없으면 @Qualifier 유무를 찾아 그 속성에 의존성을 주입.
생성자(권장이지만 순환참조 시엔 불가능한 방법입니다.), 필드, 세터에 선언하여 꺼내올 수 있습니다.

타입 => 이름 => Aualifier => Fail

@Resource
이름을 기준으로 찾음. 이름이 없으면 타입을 기준으로 찾음.

이름 => 타입 => Qualifier => Fail

@Inject
Autowired와 동일한 기준으로 찾지만 찾는 순서가 다름.

타입 => Qualifier => 이름 => Fail


이전글

프로젝트 구조, flow

맞는지는 모르겠지만, 스프링에서 제공하는 프로젝트를 깃에서 클론받은 구조로 이해를 해보겠습니다.
https://github.com/spring-projects/spring-petclinic

작업의 시작은 src에서 시작됩니다.
IDE에서 화면을 run하면 run관련 터미널에 로그들이 뜹니다. 그 로그들을 보면 자바 어디에서 어떤 클래스가 동작되었는지 알 수 있습니다.
특이했던 점은 자바스크립트 작업을 할 때는 화면을 보고 작업하다가 콘솔을 봤는데 자바는 콘솔부터 시작된다는 점입니다.

설정

src/resources/application.properties에서는 logging 보이는 정도도 조정할 수 있고,
db내용도 있는 등 앱정보들을 담고 있습니다. 환경설정같은??

자바

src/main/java는 자바소스가 위치한 곳입니다.
음.. 그냥 눈치로 src/main/java안에서 어떤 패키지가 등장하고 그 안에 디렉토리들이 있는데, 그들을 열어보면 파일형식이 대체로 이렇습니다.
1) User.java - @Entity
2) UserController.java - @Controller
3) UserRepository.java - 없음

조금씩 다른 것들도 있지만 대체로 이런 형식이었습니다. 아무래도 중심역할을 하는 1)파일과 그것을 조절하는 컨트롤러파일, db와 연계되는 레파지토리 파일이 연결되는 것 같습니다.

해당 클래스 위쪽에 @~~ 로 선언하는 문구는 스프링 annotation이라는 문법이네요.
1)은 entity역할을 하는 파일이었어요!
@Entity는 실제 DB테이블과 매칭될 클래스임을 명시합니다.
음 디비와 연관이 많은 클래스라는 소리겠네요.

Controller

class OwnerController {
	@GetMapping("/owners/find")
	public String initFindForm(Map<String, Object> model) {
		model.put("owner", new Owner());
		return "owners/findOwners";
	}
}

이런 형태가 많이 보입니다.
@GetMapping은 @RequestMapping(value = "/", method="...")를 축약한 annotation입니다.
음 그렇다면 http요청과 관련된 일이겠고, 이는 url과 연관이 많겠네요.
rest API가 아니라면 브라우저의 url과 연관이 많을 것 같아요.

model.put()은 뷰에 전달할 모델 생성. 첫번재 인자의 변수로 두번쨰 인자의 값을 담아 뷰에 보냅니다.
이는 model.addAttribute()로도 동일한 기능이 가능합니다.

그리고 컨트롤러의 메서드가 반환하는 값은 화면 주소입니다.

프론트, 뷰

src/resources/template 화면(view)파일이 위치한 곳입니다.

POJO

Plain Old Java Object
기존의 자바는 웹애플리케이션을 설계하려면 Servlet클래스를 상속받아 구현하였습니다.
Servlet클래스를 이용해서 웹서비스를 만드려면 Servlet에서 요구하는 규칙도 많고 비즈니스 로직 외에 개발하는 시간이 많이 걸렸습니다.
그래서 스프링에서는 Servlet을 추상화 시켜 라이브러리로 보내고, 개발은 순수한 자바 객체를 통해 구축할 수 있게 했습니다.

AOP

프로그램 로직 중에 반복되는 코드를 횡으로 분리하여 중복된 코드를 줄여주고 핵심 로직에 대한 가독성을 높입니다.
함수로 기능 나누는 느낌..

PSA


참고
인프런 예제로 배우는 스프링 입문 (개정판)
스프링 선언(annotation)
Mapping annotation
스프링의 흐름
스프링의 원리
스프링 프레임워크란?
IoC와 스프링 컨테이너

profile
정리하는 개발자

0개의 댓글