본문 바로가기
Spring/스프링 퀵 스타트

‘스프링 퀵 스타트’ 정리 1일차

by 유서담 2023. 7. 21.

프레임워크 개념

사전적 의미는 뼈대 혹은 틀의 의미를 갖지만

소프트웨어 관점에서 보면 “아키텍처”에 해당하는 “골격 코드”이다

애플리케이션을 개발할 때 가장 중요한 것은 전체 애플리케이션의 구조를 결정하는 아키텍처 이다.

프레임워크의 장점

  1. 빠른시간내에 구현이 가능하다
  2. 관리가 용이하다
  3. 개발자들의 역량 획일화
  4. 검증된 아키텍처의 재사용과 일관성 유지

POJO ( Plain Old Java Object )

평범한 옛날 자바 객체를 의미.

Not POJO에 해당하는 대표적인 것은 Servlet 클래스

스프링의 특징

  • IoC와 AOP를 지원하는 경량의 컨테이너 프레임워크
  1. 경량
  • 크기 측면에서 가볍고, 여러개의 모듈로 구성되어 있다.
    • 여기서 말하는 모듈은 하나 이상의 JAR 구성되어 있다
      • 이 몇개의 JAR파일만 있으면 개발과 실행이 모두 가능하다
  1. 제어의 역행 ( IoC , Inversion of Control )IoC가 적용되지 않는 경우는 의존관계에 있는 객체 변경시 반드시 자바코드를 수정해야 하지만객체와 객체사이의 의존관계 도한 컨테이너가 처리한다
  2. 이는 결과적으로 소스에 의존관계가 명시되어 있지 않기 때문에 결합도가 떨어져 유지보수에 굉장히 용이하다
  3. IoC가 적용되면 객체생성을 자바코드로 하는 것이 아닌 컨테이너가 대신 처리하기 대문에
  4. : 스프링은 IoC 를 통해 애플리케이션을 구성하는 객체간의 느슨한 결합. 즉, 낮은 결합도를 유지한다.
  5. 관점지향 프로그래밍 ( Aspect Object Programming , AOP )해당 기능을 프로그램 코드에 직접 명시하지 않고 선언적으로 처리하여 적용하는 것이 관점지향 프로그래밍에 기본 개념유지보수 향상이 가능하다
  6. 공통기능을 분리해서 관리하기 때문에 응집도가 높은 비즈니스 컴포넌트를 만들수 있고,
  7. : 공통으로 사용하는 기능들을 외부의 독립된 클래스로 분리.
  8. 컨테이너
  9. : 특정 객체의 생성과 관리를 담당한다. 객체 운용에 필요한 다양한 기능을 제공.

<bean> 엘리먼트

: 사용하려면 클래스 하나 당 하나의 <bean> 설정이 필요하다

<bean id=”tv” class=”polymorphism.SamsungTV”/>

여기서 tv 는 클래스이름을 뜻하고 , polymorphism.SamsungTV 는 패키지 + 클래스이름 이다

스프링 컨테이너 종류

: BeanFactory 와 BeanFactory를 상속한 ApplicationContext

BeanFactory

: 스프링 설정 파일에 등록된 <bean> 객체를 생성하고 관리하는 가장 기본적인 컨테이너 기능만 제공

: 일반적인 스프링 프로젝트에서 BeanFactory를 사용할 일은 전혀 없다

: 클라이언트 요청에 의해서만 <bean> 객체가 생성되는 지연로딩 방식이다.

 

ApplicationContext

: BeanFactory가 제공하는 <bean> 객체 관리 기능외에 트렌젝션 관리, 메시지 기반 다국어처리 등 다양한 기능을 제공한다.

: 컨테이너가 구동되는 시점에 <bean> 등록된 클래스들을 객체 생성하는 즉시 로딩 방식으로 동작한다.

: 웹 애플리케이션 개발도 지원하기에 대부분 프로젝트에서 사용.

 

ApplicationContext에서 가장 많이 사용하는 구현 클래스 2가지

  • GenericXmlApplicationContext : 파일 시스템이나 클래스 경로에 있는 XML 설정 파일을 로딩하여 구동하는 컨테이너
  • XmlWebApplicationContext : 웹 기반의 스프링 애플리케이션을 개발할 때 사용하는 컨테이너

< applicationContext.xml 에 beans 네임스페이스 >

의존성 주입 / 관리

스프링의 의존성 관리방법

: 스프링 프레임워크의 가장 중요한 특징은 객체의 생성과 의존관계를 컨테이너가 자동관리.

스프링 IoC의 핵심원리이다.

두가지 형태로 지원하는데 Dependency Look up 형태와 / Dependency Injection 형태이다

대부분 Dependency Injection 형식을 사용한다

Dependency Injection

: 객체사이의 의존관계를 스프링 설정 파일에 등록된 정보를 바탕으로 컨테이너가 자동으로 처리.

의존성 설정을 바꾸고 싶을때 프로그램 코드를 수정하는 것이 아닌 스프링 설정 파일 수정만으로 변경사항을 적용할 수 있어서 유지보수가 향상된다

Dependency Injection은 컨테이너가 직접 객체들 사이에 의존관계를 처리하는 것을 의미한다.

이것은 다시 Setter 메서드를 기반으로 하는 세터 인젝션과 생성자를 기반으로 하는 생성자 인젝션으로 나뉜다

의존성 관계 ( 객체와 객체의 결합관계 )

: 하나의 객체에서 다른 객체의 변수나 메서드를 이용해야 한다면 이용하려는 객체에 대한 생성과 생성된 객체의 래퍼런스 정보가 필요하다

생성자 인젝션 이용하기

스프링 컨테이너 XML 설정파일에 등록된 클래스를 찾아서 객체 생성할 때 기본적으로

매개변수가 없는 기본(Default) 생성자를 호출하지만 컨테이너가 기본 생성자말고

매개변수를 가지는 다른 생성자를 호출하도록 설정할 수 있는데, 이 기능을 이용하여 생성자 인젝션(Constructor Injection)을 처리한다.

생성자 인젝션을 사용하면 생성자의 매개변수로 의존관계에 있는 객체의 주소 정보를 전달할 수 있다.

 

<bean id = "tv" class = "polymorphism.SamsungTV">

<constructor-arg ref = "sony"></constructor-arg>

</bean>

 

<bean id = "sony" class = "polymorphism.SonySpeaker"></bean>

 

생성자 인젝션을 위해서는 SamsungTv 클래스 <bean> 등록 설정에서 시작 태그와 종료태그 사이에 <constructor - arg> 엘리먼트를 추가하면 된다.

그리고 생성자 인자로 전달할 객체의 아이디를 <constructor - arg> 엘리먼트 ref 속성으로 참조한다.

생성자 인젝션에서 초기화해야 할 멤버변수가 여러 개이면, 여러개의 값을 한꺼번에 전달해야한다

public class SamsungTV implements TV { private SonySpeaker speaker;

public SamsungTV(Sonyspeaker speaker , int price) {
	System.out.println("==> SamsungTV(3) 객체생성");
	this.speaker = speaker;
	this.price = price;

스프링 설정 파일에 <constructor - arg> 엘리먼트를 매개변수의 개수만큼 추가해야한다

 

<bean id = "tv" class = "polymorphism.SamsungTV">

<constructor-arg ref = "sony"></constructor-arg>

<constructor-arg value = "2700000"></constructor-arg>

</bean>

<bean id = "sony" class = "polymorphism.SonySpeaker"></bean>

 

<constructor - arg> 엘리먼트에는 ref와 value속성을 사용하여 생성자 매개변수로 전달할 값을 지정할 수 있다 인자로 전달될 데이터가 <bean>으로 등록된 다른 객체일 때는 ref 속성을 이용하여 해당 객체의 아이디나 이름을 참조. 고정된 문자열이나 정수 같은 기본형 데이터일때는 value 속성을 사용한다

Setter 인젝션 이용하기

위에서 말한 생성자 인젝션은 생성자를 이용하여 의존성을 처리한다. 하지만 setter 인젝션은 setter메소드를 호출하여 의존성을 처리하는 방법이다.

생성자와 setter 뭘 사용하든 상관은 없지만 대부분 setter 인젝션방법을 사용한다

setter인젝션은 <constructor - arg>을 사용하는 것이 아닌 <property> 엘리먼트를 사용한다

 

<bean id = "tv" class = "polymorphism.SamsungTV">

<property name = "speaker" ref = "apple"></property>

<property name = "price" value = "250000"></property>

</bean>

<bean id = "sony" class = "polymorphism.SonySpeaker"></bean>

<bean id = "apple" class = "polymorphism.AppleSpeaker"></bean>

컴포넌트 스캔(component-scan)설정

스프링 설정 파일에 애플리케이션에서 사용할 객체들을 <bean> 등록하지 않고 자동으로 생성하려면 context:component-scan/이라는 엘리먼트를 정의해야 한다 이 설정을 추가하면 스프링 컨테이너는 클래스 패스에 있는 클래스들을 스캔하여

@Component가 설정된 클래스들을 자동으로 객체 생성한다.

@Component

context:component-scan를 설정했으면 이제 스프링 설정 파일에 클래스들을 일일이 <bean>엘리먼트로 등록할 필요가 없다. @Component만 클래스 선언부 위에 설정하면 된다

의존성 주입 어노테이션

@AutoWired : 주로 변수 위에 설정하여 해당 타입의 객체를 찾아서 자동으로 할당한다 @Qualifier : 특정 객체의 이름을 이용하여 의존성 주입할 때 사용한다 @Inject : @Autowired와 동일한 기능을 제공한다 @Resource : @Autowired와 @Qualifier의 기능을 결합한 어노테이션이다

스프링 컨테이너가 생성하는 객체를 XML 설정으로 처리할 수 있고, 어노테이션으로도 처리할 수 있다. 그러나 XML 설정만으로 사용하기에는 <bean> 등록을 많이 해야하고, 의존관계 설정도 부담스럽다. 그렇다고 어노테이션만 사용하자니 자바 소스를 수정해야 의존 관계를 변경할 수 있다.

따라서 이 두가지를 적절히 병행하여 사용하는 것이 가장 현실적인 방법이다.

변경되지 않는 객체는 어노테이션으로 설정하여 사용하고, 변경될 가능성이 있는 객체는 XML 설정으로 사용한다

추가 어노테이션

이 구조에서 가장 핵심 요소는 Controller , ServiceImpl, DAO 클래스이다. Controller 클래스는 사용자의 요청을 제어하며, ServiceImpl 클래스는 실질적인 비즈니스 로직을 처리한다. DAO 클래스는 데이터베이스 연동을 담당한다

@Component를 이용하여 스프링 컨테이너가 해당 클래스 객체를 생성하도록 설정할 수 있지만 시스템을 구성하는 모든 클래스에 @Component를 할당하면 어떤 클래스가 어떤 역할을 수행하는지 파악하기 어렵다

 

스프핑 프레임워크에서는 이런 클래스들을 분류하기 위해서 @Component를 상속하여 세 개의 어노테이션을 추가로 제공한다

@Service : 비즈니스 로직을 처리하는 Servie 클래스 ( 위치 : XXXServiceImpl )

@Repository : 데이터베이스 연동을 처리하는 DAO 클래스 ( 위치 : XXXDAO )

@Controller : 사용자 요청을 제어하는 Contoller 클래스 ( 위치 : XXXController )

Value Object 클래스 작성

VO 클래스는 레이어와 레이어 사이에서 관련된 데이터를 주고 받을 목적으로 사용하는 클래스.

DTO(Data Transfer Object)라고도 한다

(난 배울때 DTO로 배웠기 때문에 앞으로 모든 메모에서는 DTO로 하겠다)

DTO 클래스를 작성하려면 먼저 데이터베이스에 생성되어 있는 테이블의 구조를 확인해야한다

BOARD 테이블에 포함된 칼럼과 같은 이름의 멤버변수를 private 접근제어자로 선언하고 멤버변수의 접근하는 Getter / Setter 메소드로 선언하면 된다

예시) 테이블에 포함된 칼럼과 같은 이름의 멤버변수를 선언한 예시

DAO 클래스

DAO( Data Access Object ) 클래스는 데이터베이스 연동을 담당한다.

DAO 클래스에서는 CRUD ( Create , Read , Update , Delete ) 기능의 메소드가 구현이 되어야한다

위에서 예시로 올린 boardDTO 객체를 매개변수와 리턴타입으로 사용하면서 테이블과 CRUD 기능을 처리할 DAO클래스를 작성한다

DAO 클래스 객체를 스프링 컨테이너가 생성할 수 있도록 클래스 선언부에 @Repository 어노테이션을 설정한다. ( @Component 어노테이션을 사용해도 무관하지만 DAO 기능 클래스에서는 @Repository가 적합하다 )

CRUD 기능 메서드 이름의 일관성을 유지하기 위해 규칙을 적용한다

예시 )

등록 insert 테이블명

수정 update 테이블명
삭제 delete 테이블명
상세조회 get 테이블명 ( 혹은 select 테이블명 )
목록검색 get 테이블명 List ( 혹은 select 테이블명 List )