구조 


 

 

 

 

 

환경 설정


 

 

 

 

 

 

 

 

Chap01-bean-factory : section01

 

 

 

 

 

 Application

package com.greedy.section01.xmlconfig;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {

	public static void main(String[] args) {
		
		/* BeanFactory란?
		 * 스프링 컨테이너의 최상위 컨테이너이며, ApplicationContext와 함께 
         스프링 컨테이너라고 한다.
		 * Bean의 생성과 설정, 관리 등의 역할을 맡고 있다.
		 * */
		
		/* MemberDTO(POJO) 클래스와 spring-context(Configuration) XML 설정 정보를 이용해서
		 * bean 등록, 생성 예제 확인
		 * */
		
		/* ApplicationContext의 하위 구현체인 GenericXmlApplicationContext는 
        XML 설정 메타정보를 읽어와서
		 * BeanFactory를 동작 시킨다.
		 * GenericXmlApplicationContext는 설정 메타 정보가 담긴 XML 파일의 경로를 
         클래스패스 하위 경로 전부 기술해야 설정 파일을 읽어온다. 
		 * */
         
		ApplicationContext context 
        = new GenericXmlApplicationContext("com/greedy/section01/xmlconfig/spring-context.xml");
		
		/* 1. bean의 id를 이용해 bean을 가져오는 방법
		 * id를 이용하는 경우 bean의 정확한 타입을 유추할 수 없기 때문에 Object 타입으로 
         반환하므로 다운캐스팅 필요 
		 * */
		//MemberDTO member = (MemberDTO)context.getBean("member");
		
		/* 2. bean의 클래스 메타 정보를 전달하여 가져오는 방법
		 * 가져오려는 bean의 타입이 명확하기 때문에 형변환이 필요 없다.
		 * */
		//MemberDTO member = context.getBean(MemberDTO.class);
		
		/* 3. bean의 id와 클래스 메타 정보를 전달하여 가져오는 방법
		 * */
		MemberDTO member = context.getBean("member", MemberDTO.class);
		
		System.out.println(member);
		
		
	}

}

 

 

 

 


 

  • ApplicationContext은 BeanFactory 를 확장한 여러 인터페이스를 통합해서 상속받은 인터페이스
  • 인터페이스이다보니 그 자체로 실질적인 어떤 구현체를 생성할 수 없음
  • 해서 ApplicationContext 안에있는 강제화된 기능들을 구현해놓은 구현체인 GenericXmlApplicationContext
  • GenericXmlApplicationContext는 XML 설정파일을 읽어서 구동이 되는 클래스

 

정의되어있지않기에 뜨는 화면

 

 

 

  • 우선 Spring Context를 추가한다. 그 안에  ApplicationContext 과 GenericXmlApplicationContext 등이 정의되어있음
  • mvn 레파지토리에서 라이브러리를 다운받아옴으로서 추가 해 볼 것이다. 

 

 

mvnrepository.com

 

 

  • release 된 버전 중 가장 사용 빈도가 높은 5.2.9 버전을 클릭한 후 .jar  파일을 다운 받는다. 
  • * 유의할 점, Spring 모듈 끼리는 버전을 맞춰주어야 한다. 현재 5.2.9 버전을 사용한다면 앞으로 추가하는 모듈들 끼리의 버전은 5.2.9버전으로 맞춰 주어야 한다는 뜻이다.  그래야 충돌을 미연에 방지할 수 있다. 

 

 

 

  • 이후 프로젝트 내 lib라는 폴더를 만들어 다운 받은 파일을 옮겨 붙여 준다. 

 

 

  • 이렇게 해줄 시 물리적으론 jar 파일이 프로젝트 내 존재하는 것은 맞지만, 실질적인 이 프로젝트의 사용 라이브러리로 등록되어있는 것은 아니다. 

 

 

  • 프로젝트 우클릭 > Properties > Java Build Path 카테고리 > Library 탭 > Classpath 선택 > Add JARs... 선택

 

  • 물리적으로 존재하는 폴더 내 .jar 파일을 선택 후 확인을 눌러준다. 

추가된 모습

 

 

  • 라이브러리 빌드 등록 후 두가지 기능이 정상적으로 import 가 가능해지는 것을 확인할 수 있다. 

 

 

  • 생성을 할 인스턴트 쪽에 설정 메타정보를 기재해 준다. 
  • 여기에 기재된 정보는 spring-context.xml 로 만든 bean configuration 파일이다. 
  • IoC 컨테이너를 만들때 이러한 설정정보를 쓰라고 전달하는 의미이다. 

 

 

  • 그런데, 작성한 설정 정보에 에러줄이 발생한다. 왜일까? 이는 스프링의 구성모듈과 관련있다. 

 

 

  • 방금 Context를 추가를 했는데 다음으로 Context 내에서 Core 안에있는 어떤 기능을 쓰려고 한다. 
  • xml 파일이 읽어 올때, 리소스를 처리할 수 있는 기능이 이 Core 안에 기재되어있기 때문에 사실상 Context 만으로는 동작하기 어렵다. 
  • 즉, 좀 더 추가해야하는 기능들이 더 있다는 의미이다. 

 

더보기

Spring의 구성모듈

 

 

 

 

 

 

 

Spring Core 추가

 

  • 마찬가지로 mvn 레파지토리를 이용한다.
  • 5.2.9 버전을 jar 파일을 동일하게 다운 받은 후 lib 물리 구조에 붙여넣기 한다. 

 

 

  • 추가이후 build path를 통해 라이브러리 등록을 해준다. 

 

 

 

  • 이후 사라진 에러를 확인할 수 있다. 
  • 이 설정정보를 전달받은 스프링 컨테이너가 생성될 수 있는지를 테스트 해보자.

 

 

콘솔창의 에러를 확인한다. 현재 springframework 아래 beans 라는 경로를 찾지못했음을 알 수 있다. 

 

 

  • Beans 가 없다는 의미이다.
  • 이런식으로 콘솔창을 통해 어떤 기능이 포함되지못했는지 하나씩 유추해가는 방식이 필요하다. 

 

 

  • MVN 레파지 토리에서 Spring Beans를 가져온다. 
  • 버전을 맞추어 다운 받는 것에 유의한다. 
  • 앞서 했던 것과 마찬가지로 lib 에 다운받은 파일을 추가후 build path 에서 추가해준다. 

 

 

  • 추가 이후 다시 실행했더니 다음과같은 에러가 콘솔창에 떴다. 

 

 

 

  • 마찬가지로 MVN에서 commons logging을 가져오도록 한다. 

 

 

  • 1.2 버전을 다운받는다. 마찬가지로 빌드 패스까지 마무리 지어준다.

 

  • 파싱처리에 필요한 Spring expression 이 없음을 확인할 수 있다. 
  • 마찬가지로 다운받은 후 빌드패스까지 해준다.

 

  • 이와같이 라이브러리 추가를 완료한 후 실행해 주었을때 (이전 에러 출력값이 사라지고) 콘솔창에 아무것도 뜨지않음으로서 GenericXmlApplicationContext 의 객체가 성공적으로 생성되었음을 알 수 있다. 

 

 

정리

- ApplicationContext의 하위 구현체인 GenericXmlApplicationContext는 XML 설정 메타정보를 읽어와서 BeanFactory를 동작 시킨다.
- GenericXmlApplicationContext는 설정 메타 정보가 담긴 XML 파일의 경로를 클래스패스 하위 경로 전부 기술해야 설정 파일을 읽어온다. 

 

 

 

  • 여기까지 왔을 때, 이 설정정보가 잘 만들어졌음을 어떻게 알 수 있을까? 
  • 현재 spring-context.xml 안에는 bean이 있는데, 이 bean 이 잘 등록되어, 생성되었는지를 확인 해본다.

 

  • bean을 꺼내오는 첫번째) getBean 메소드
  • bean에는 고유 아이디가 있는데, 이때 "member"라는 아이디를 가진 bean을 리턴하도록 한다.

 

  • 타입 미스매치 에러가 뜬다. 이유는 고유 id만으로 타입을 유추할 수 없기 때문이다. (타입=/=아이디)
  • 유추할 수 없는 타입은 Object로 리턴이 되기 때문에, 원하는 타입으로 리턴값을 담기위해서는 다운캐스팅이 필요하다. 

 

 

  • 객체가 잘 등록되어서 생성되었다는 것을 콘솔창에서 확인 해 볼 수 있다.

 

 

  • 우리는 다음의 과정을 거치면서 MemberDTO member = new MemberDTO(1, "user01"...) 과 같은 객체를 생성한 적이 없다.
  • 그러나 콘솔창을 보면 생성되었음을 알게되는데, 이건 누가 해준걸까? 바로 ApplicationContext 이다.
  • spring-context 안에 MemberDTO를 다음과같이 등록한다는 정보를 작성해주었기 때문이다. 
  • 이로서 빈을 생성했고, 잘 읽어 올 수 있었음을 확인하였다.

spring-context.xml

 

 

 

 

Bean 가져오는 방법 세가지


1. bean의 id를 이용해 bean을 가져오는 방법 
- id를 이용하는 경우 bean의 정확한 타입을 유추할 수 없기 때문에 Object 타입으로 반환하므로 다운캐스팅 필요 
MemberDTO member = (MemberDTO)context.getBean("member");

 

 

2. bean의 클래스 메타 정보를 전달하여 가져오는 방법
- 가져오려는 bean의 타입이 명확하기 때문에 형변환이 필요 없다.
  • 애초에 MemberDTO 타입의 bean을 달라는 의미이다. 
  • 즉, 반환타입이 Object 가 아니므로 다운캐스팅이 필요없다.

 

 

3. bean의 id와 클래스 메타 정보를 전달하여 가져오는 방법
   MemberDTO member = context.getBean("member", MemberDTO.class);
   System.out.println(member);
  • 만약,  MemberDTO 타입의 bean이 여러개라면, 2번의 방법이 무의미하다.
  • 이럴때 빈의 아이디와 클래스 정보를 둘 다 기입한다. 역시 클래스를 기입해주었으므로 다운캐스팅은 필요없다.

 

 

 

정리

1. 제어의 역전을 구현하기 위해 Bean Factory에 빈을 등록하여 사용한다.
2. GenericXmlApplicationContext는 설정 메타 정보가 XML 에 만들어져있는 환경이다. 

 

 

 

 

 

 

 

 

 


 

 

 

  • XML에 설정 메타정보가 기입되었던것과 마찬가지로, java-config 파일에서도 똑같이 동작하는지 그 방법과 결과를 살펴보도록 한다.
  • 테스트할 클래스를 만들어준다. 

 

 

  • 동일한 테스트를 위해 MemberDTO 파일을 복사해와 경로만 수정해준다. 
  • 이 DTO 파일이라는 오브젝트를 사용하기위해 설정 메타 정보라는 것이 필요하다.
  • 아까는 그 정보를 XML에 파일에 작성했다면 이번엔 자바 클래스에 만들어 보도록 한다.

 

 

  • 컨테이너를 만들때 전달할 설정정보를 정의할 클래스 정의

 

 

  • 다음과같이 생성된 ContextConfiguration 파일에 @Configuration 이라는 어노테이션을 붙인다.
  • 즉, 이 클래스가 설정 메타 정보를 가지고 있다는 의미를 가진 어노테이션을 추가한다.
  • 컨테이너를 생성할 시 해당 어노테이션이 달린 클래스를 먼저 인식하여 컨테이너를 설정한다.

 

 

  • xml 파일에서 빈을 등록했듯이, 자바 클래스 파일에서도 빈을 등록할 수 있어야 한다.
  • 여기서는 '메소드' 형식을 사용한다.
  • 리턴타입이 MemberDTO, 리턴타입의 객체에 원하는 정보를 new 생성자를 통해 설정한다.

 

  • bean을 등록하기 위해서는 @Bean 어노테이션을 이용한다.
  • 즉, 메소드 위에 'Bean'임을 알 수 있도록 @Bean 어노테이션을 붙여준다.

 

  • 앞서 xml에서 빈의 정보를 id로 알았다. 여기서는 어떻게 해야 id의 역할을 할 수 있을까?
  • 이름을 등록하기 위해 @Bean(name="member") 와 같이 사용한다.
  • 만일 bean에대한 아이디를 지정하지 않으면 [메소드명]을 사용하게되니 유의한다.

 

 

  • 다음과같이 작성이 되어야한다.
@Configuration
public class ContextConfiguration {

	@Bean(name="member")
	public MemberDTO getMember() {
		
		return new MemberDTO(1, "user01", "pass01", "배산임수");
	}

}

 

 

정리

- @Bean(name="myName") 혹은 @Bean("myName")을 이용하여 bean의 id를 설정할 수 있다.
- 이 때 bean의 이름을 지정하지 않으면 메소드의 이름을 bean의 id로 자동 인식한다.

 

 


 

 

 

  • Application 에서실행하여 마찬가지로 빈이 잘 생성되고 등록되었는지 확인한다. 
  • 똑같이 스프링 컨테이너를 만들기 위해 ApplicationContext context 을 사용하는 것은 동일하다. 
  • 그러나 앞서 xml 파일로 테스트 했다면 이번엔 자바 클래스 파일을 통해서 테스트 하는 것이기 때문에 메타 정보를 연결하는 객체가 달라야 한다. 그러한 설정정보를 읽어왔을때 사용하는 구현체도 달라진다. 
  • 즉, GenericXmlApplicationContext 구현체가 아닌  AnnotationConfigApplicationContext 을 사용하게 된다. 
  • 여기에 방금작성한 설정정보가 담긴 ContextConfiguration.class 라는 클래스(타입)을 전달한다.

 

 

- AnnotationConfigApplicationContext라는 어노테이션 설정 정보를 읽어서 컨테이너 설정을 하는 구현체 이용한다.
- 인자로 @Configuration 어노테이션이 달린 설정 클래스의 메타 정보를 전달하여 인스턴스를 생성한다.

 

 

  • Bean이 잘 등록됐는지 확인하기 위해 context를 통해 빈을 꺼내온다.
  • 앞서 했던 빈을 꺼내오는 세가지 방법중 이름과 타입을 정확히 기입해서 꺼내오는 방법을 사용

 

 

  • 위를 실행할시 콘솔창에 다음과같이 aop가 없음을 확인할 수 있다.
  • AnnotationConfigApplicationContext 의 기능을 이용하기 위해서 스프링의 aop라는 기능이 필요함을 알 수 있다.

 

  • 앞서 해왔던 대로 MVN 레파지 토리 -> Spring AOP 검색 -> 5.2.9 버전 다운 로드 -> Build Path 등록

 

  • 라이브러리가 잘 build path 등록되었다면 콘솔창에서 다음과같은 결과를 확인할 수 있다.
  • xml-config 에서 확인했던것과 마찬가지로 컨테이너에서 빈이 잘 생성되고 등록된것을 알 수 있다.

 

 

 

정리 

- 제어의 역전, 빈 팩토리를 통해서 빈을 등록할 수 있다. 
- 빈 등록은 xml 을 통한 방식도 있고 자바 클래스를 통한 방식도 있다. 
- 각 방식에 따라서 실제 내부적인 구현체 역시 달라진다. 
- 그렇지만 구현체가 달라져도 다음 사실은 동일하다 : 설정메타정보를 읽어와서 생성이 된 컨테이너 안에는 -개발자가 직접적으로 객체를 생성하는 것이 아니라- 컨테이너 안에서 관리되는 Bean 객체로서 존재를 하게 된다. 

 

 

Configuration Metadata를 작성하는 방법에 대해 서술된 부분을 보자

 

 

 

  • 다음으로 Component Scan을 통해 Bean이 등록되는 모습을 살펴보자.
  • 특정 어노테이션을 이용해 Bean으로 등록해줄 것을 표시할 수 있는데 바로 @Component 이다. 

 

 

 

 

 

 

 

 

MemberDTO

public class MemberDTO {
	
	private int sequence;
	private String id;
	private String pwd;
	private String name;
	
	public MemberDTO() {}

	public MemberDTO(int sequence, String id, String pwd, String name) {
		super();
		this.sequence = sequence;
		this.id = id;
		this.pwd = pwd;
		this.name = name;
	}

	public int getSequence() {
		return sequence;
	}

	public void setSequence(int sequence) {
		this.sequence = sequence;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "MemberDTO [sequence=" 
        + sequence + ", id=" + id + ", pwd=" + pwd + ", name=" + name + "]";
	}
	
	

}

 

 

 

spring-context.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">

	<!-- MemberDTO bean 등록 -->
	
	<bean id="member" class="com.greedy.section01.xmlconfig.MemberDTO">
		<constructor-arg index="0" value="1"/>
		<constructor-arg name="id" value="user01"/>
		<constructor-arg index="2"><value>pass01</value></constructor-arg>
		<constructor-arg name="name"><value>홍길동</value></constructor-arg>
	</bean>

</beans>

 

 

 

 

 

 

 

 


 

 

 

 

 

Chap01-bean-factory : section02

 

 

 

 

 

Application 

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
	
	public static void main(String[] args) {
		
		/* AnnotationConfigApplicationContext라는 어노테이션 설정 정보를 읽어서
        컨테이너 설정을 하는 구현체 이용한다.
		 * 인자로 @Configuration 어노테이션이 달린 설정 클래스의 메타 정보를
         전달하여 인스턴스를 생성한다.
		 * */
		ApplicationContext context 
        = new AnnotationConfigApplicationContext(ContextConfiguration.class);
		
		MemberDTO member = context.getBean("member", MemberDTO.class);
		
		System.out.println(member);
	}

}

 

 

ContextConfiguration 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/* 이 클래스가 설정 메타 정보를 가지고 있다는 의미를 가진 어노테이션을 추가한다.
 * 컨테이너를 생성할 시 해당 어노테이션이 달린 클래스를 먼저 인식하여 컨테이너를 설정한다.
 * */
@Configuration
public class ContextConfiguration {
	
	/* bean을 등록하기 위해서는 @Bean 어노테이션을 이용한다.
	 * @Bean(name="myName") 혹은 @Bean("myName")을 이용하여 bean의 id를 설정할 수 있다.
	 * 이 때 bean의 이름을 지정하지 않으면 메소드의 이름을 bean의 id로 자동 인식한다.
	 * */
	@Bean(name="member")
	public MemberDTO getMember() {
		
		return new MemberDTO(1, "user01", "pass01", "배산임수");
	}

}

 

 

MemberDTO

public class MemberDTO {
	
	private int sequence;
	private String id;
	private String pwd;
	private String name;
	
	public MemberDTO() {}

	public MemberDTO(int sequence, String id, String pwd, String name) {
		super();
		this.sequence = sequence;
		this.id = id;
		this.pwd = pwd;
		this.name = name;
	}

	public int getSequence() {
		return sequence;
	}

	public void setSequence(int sequence) {
		this.sequence = sequence;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "MemberDTO [sequence=" + sequence + ",
        id=" + id + ", pwd=" + pwd + ", name=" + name + "]";
	}
	
	

}

 

 

 

 

 

 

 

 

 

파일구조 


 

 

 

 

 

 

 

 


 

 

 

 

 

 

chap02-component-scan : section01

 

  • 상단 테스트에서 진행했던 라이브러리를 그대로 가져와 Build Path 지정해주는 작업까지 완료한다. 
  • 코드 작성을 위해 다음과같은 javaconfig 클래스를 작성한다.

 

 

 

ComponentScan 기능을 이용한 bean 등록 설정해보기 


  • ComponentScan이란? base-package로 설정 된 하위 경로에 특정 어노테이션을 가지고 있는 클래스를 이용하여 bean으로 등록한다.
  • @Component 어노테이션이 작성 된 클래스를 인식하여 bean으로 만들게된다.
  • @Component는 좀 더 상위의 개념이며, 특수 목적에 따라 세부 기능을 제공하는 @Controller, @Service, @Repository, @Configuration 등을 인식한다.
  • 즉, @Component 어노테이션이 작성된 클래스의 빈을 스캔하여 그것을 빈으로서 등록해주는 것이다. 

 

  • 테스트를 위한 설정 : MemberDTO 를 그대로 가져와 패키지만 변경해준다. 

 

  • 다음으로 MemberDAO라는 이름의 인터페이스를 작성한다. 

 

 

  • 인터페이스는 추상메소드를 작성하는 공간이며, 구조적인 부분을 강제화 할 수 있는 기능이다. 
  • 여기서는 필요로하는 두가지 기능을 작성해본다.  1) 회원정보 조회 메소드 2) 회원정보 저장 메소드

 

 

  • 인터페이스에서 작성한 내용을 강제화하기 위한 기능인 MemberDAOImpl 을 만들어준다.
  • 인터페이스의 장점 1) 인터페이스를 이용하면 기능을 구현할 것을 강제화할 수 있다는 점과, 2) 기능에 변화가 있을때마다 해당 인터페이스를 사용하는 클래스와의 결합도를 느슨하게 해준다. (유지보수 용이)

 

- 인터페이스로 메소드를 강제화 한 후 구현하여 사용하면 강제성이 부여 된다.
- 또한 결합 관계를 느슨하게 만들 수 있다.


 

 

  • db 연동을 하는 것이 아니므로 데이터를 다음과같이 적어준다.

 

  • 매개변수로 전달받은 회원 번호를 map에서 조회 후 회원 정보를 리턴해주는 용도의 메소드

 

  • 매개변수로 전달받은 회원 정보를 map에 추가하고 성공 실패 여부를 boolean으로 리턴하는 메소드
  • 전달받은 멤버의 정보중에서 시퀀스에 해당하는 값을 키값으로, 나머지 객체값(newMember)은 VALUE 값으로 해서 MAP 에 넣겠다는 것.  
  • MAP은 동일한 값은 중복저장하지 않으므로, 잘 저장되었는지는 MAP의 사이즈 (.size) 를통해서 알아보도록 한다.
  • 사이즈가 늘어났다면 true 를, 그렇지않다면 false 를 반환할 것이다. 

 

 

 

  • 스프링 컨테이너가 스캐닝 기능을 이용하여 해당 클래스를 bean으로 등록할 수 있는 어노테이션을 설정한다. 
  • value 속성을 이용하면 bean의 id를 설정할 수 있으며, value는 생략 가능하다.
  • 이름(id)를 설정하지 않으면 Class의 앞 글자를 소문자로 하여 bean을 생성한다.
  • @Controller, @Service, @Repository와 동일한 기능을 가지지만 각 계층을 표현하는 어노테이션은 특정 용도에 맞는 부가적인 혜택이 있으니 게층별로 구분하여 사용하는 것이 좋다. (계층이 명확하지않다면 @Component를 사용해도 좋다.)

 

클래스 위에 @Component 어노테이션을 붙여준다. 그럼 나중에 이러한 어노테이션이 붙은 대상을 가지고 bean 등록할 수 있다.

 

  • 이때, VALUE 속성을 통해 해당 컴포넌트의 이름을 지어줄 수 있다.
  • 만약, VALUE 속성을 지정해 주지않았다면? 마찬가지로 메소드 명을 빈의 이름으로 자동 지정될 것이다. 
  • memberDAOImpl > 앞글자를 소문자로 만들어 빈의 이름으로 등록했을 것이다. 

 

 

  • 다음으로 필요한 것은 설정파일이다.

 

  • 설정파일임을 스프링 컨테이너에서 알 수 있도록 @Configuration 어노테이션을 붙여준다.
  • 단, MemberDAOImpl 에 작성한 @Component 를 잘 스캔 해 빈으로 등록해주는지 확인하는 것이 이번 테스트의 목적이므로, 해당 설정파일에는 아무것도 적지않는다.

 

 

  • Application1 으로 돌아온다. 만들어야 하는 것은 <스프링 컨테이너>에 해당하는 것이다. 
  • 어노테이션 기반으로 스프링 파일을 읽어와서 스프링 컨테이너를 만들겠다는 의미이다. 
  • 전달한 값은 따로 빈 등록을 하지않은 빈 껍데기 설정파일이다. 
  • 여기서 기대하는 것: @Component 어노테이션이 스캔시 '나를 빈으로 등록해라' 라고 하는 어노테이션이기 때문에 빈으로 잘 등록이 되는지 확인

 

 

  • context 안에 담겨있는, 정의된 빈의 이름들을 배열로 가져온다.
  • 해당 배열안에 어떤 빈들이 등록되어있는지는 반복문을 통해서 출력 해본다.

 

 

  • 실행시 다음과같은 결과를 콘솔창에서 확인할 수 있다.
  • 앞글자가 소문자로 바뀐 설정 파일 클래스는 확인할 수 있지만, 기대했던 클래스는 빈 등록이 되지않은 것 같다.
  • 그렇다면 왜 등록이 되지않은 것일까? 

 

 

  • Context Configuration 은 어떤 기준으로 스캔을 하고 있는걸까? 
  • 본인이 현재 중재하는 경로 기준, 경로가 지엽적이라면 (base package를 설정하지않았다면) 본인의 패키지를 기준으로 스캔을 한다. 즉, 스캔이 안된것이 문제이다. 
  • 그렇다면 base-package에 대한 설정을 추가를 해주도록 한다. 

 

 

  • 다시 설정파일로 돌아와 다음과같은 어노테이션을 추가로 붙여준다. -> @ComponentScan
  • basePackages에 등록되지 않은 패키지는 스캔에서 제외하고, 등록된 패키지 내의 @Component 어노테이션을 탐색한다.
  • 이 때 basePackage를 등록하지 않으면 현 설정 클래스가 존재하는 패키지를 자동 basePackage로 설정한다. 

 

 

  • 위와같은 어노테이션을 붙여줌으로서, 명시적으로 탐색할 기준이 되는 베이스 패키지를 설정해 주게 되었다. 
  • 이제 config 폴더내 설정파일만 탐색하는 것이 아니라, javaconfig 하위의 모든 어노테이션을 탐색할 수 있게 되었다.

 

 

  • 베이스 패키지 설정 후 다음과 같이 MemberDAO 가 빈으로 등록되었음을 확인할 수 있다. 

 

 

  • 빈등록이 잘 되었다면 좀 전에 작성한 메소드를 이용해보는 것도 가능하다. 
  • 1번 멤버 조회와 3번 멤버 인서트, 3번 멤버 조회를 차례로 작성한다.

 

  • 콘솔창에 출력된 모습

 

 

 

 

ComponentScan


스프링 컨테이너는 빈들의 생명주기를 관리하며, 그러한 설정 정보를 설정하는 방식을 지금까지 살펴보았다. 

ComponentScan 어노테이션에 basePackages 외에 더 추가할 수 있는 방법들을 알아보고자 한다.

 

테스트를 위해 별도의 경로를 작성해준다. Application2 라는 이름의 javaconfig 작성

 

 

 

  • 테스트를 위한 ApplicationContext 를 생성한다.
  • 앞선 테스트와같이 설정 정보를 저장하기 위한 Context Configuration를 전달한 뒤 에러밑줄을 선택해 만들어 준다. 

 

  • 만들어진 클래스에는 이것이 [설정정보]임을 나타내는 어노테이션 @Configuration 을 달아준다.
  • 또한 basePackages는 다음과같이 작성한다.

 

  • 추가할 수 있는 기능은 다음과같다. 베이스 패키지를 하나이상 설정할 수 있다는 것 
  • 어노테이션에 추가하는 것은 문법적으로 [ 콤마, ] 로 나타낸다.
  • 만약 단일 값인 경우엔 패키지명을 포함한 클래스이름을 나열하면 되지만, 하나 이상의 베이스 패키지인 경우 {} 중괄호를 이용하여 나열한다. (중괄호=나열)

 

  • 베이스 패키지를 설정하면 그 하위의 파일들은 전부다 스캔이 된다. 그러나 관련없는 클래스까지 스캔하는 것은 어떤 관점에서는 낭비이므로, 임의의 타입은 스캐닝에서 제외시킬 수 있다. 
  • excludeFilter로 스캐닝에서 제외할 타입을 기술하면 해당 타입은 스캐닝에서 제외한다.

 

1. 타입으로 설정

  • ASSIGNABLE_TYPE이란 것은 타입을 지정한다는 것이다.
  • 스캐닝에서 제외할 클래스를 다음과같이 작성해주면 된다.
  • 단, 같은 패키지 하위에 같은 베이스 패키지를 기술하면 오류의 원인이 될 수 있으므로 사전에 중복된 베이스 패키지는 주석 처리한다.
    @Configuration
    @ComponentScan(basePackages="com.greedy.section01.javaconfig", 
         excludeFilters= {
             @ComponentScan.Filter(

             type=FilterType.ASSIGNABLE_TYPE,
             classes= {MemberDAO.class}
     		})
    public class ContextConfiguration2 {
    }

 

  • 앞선 설정파일의 빈 등록 코드를 그대로 가져와 실행해 주면 콘솔창에 다음과같이 뜬다. 
  • MemberDAO.class를 찾을 수 없다는 의미이므로, 컴포넌트 스캔에 잘 제외되었음을 알 수 있다.

 

 

2. 어노테이션 종류로 설정

  • Component  어노테이션이 붙어있는 클래스를 스캔하지않겠다는 의미
    @Configuration
    @ComponentScan(basePackages="com.greedy.section01.javaconfig", 
         excludeFilters= {
             @ComponentScan.Filter(

             type=FilterType.ANNOTATION,
			 classes= {org.springframework.stereotype.Component.class}
             })
    public class ContextConfiguration2 {
    }

 

 

3. 표현식으로 설정

REgular Expression 표현식으로 타입을 설정한 후, section01 하위의 모든 클래스를 제외하겠다는 의미

    @Configuration
    @ComponentScan(basePackages="com.greedy.section01.javaconfig", 
         excludeFilters= {
             @ComponentScan.Filter(

             type=FilterType.REGEX,
			 pattern= {"com.greedy.section01.*"}
             
    public class ContextConfiguration2 {
    }

 

 

정리 

- 컴포넌트 스캔이라는 기술을 사용할 때, base package 하위의 모든 클래스를 스캔하는 것이 시간이 소요될 수 있으니 이 스캐닝과 관련이 없는 대상은 제외해주는 옵션을 사용할 수 있다. : [ , excludeFilters = { } ]
- 그 옵션을 사용하는 방법은 다양한데 세가지만 살펴보았다 : 1. 타입 2. 어노테이션 3. 표현식으로 설정

 

 

 

 

 

또 다른 테스트를 위해 같은 경로 내에 ContextConfiguration3 을 만들어준다. 

 

 

 

  • 설정 메타 정보 클래스를 만드는 것이 용도이다. 
  • 1) basePackages의 기본 설정 경로를 지정하고 2) useDefaultFilters를 false로 하면 모든 어노테이션을 스캔하지 않는다.
  • 이 때 스캔할 대상 클래스만 따로 지정할 수 도 있다.
  • excludeFilters 가 제외하는 방식이라면, includeFilters 는 포함하는 방식이다. 
  • exclude 필터 설정하는 방식과 동일하다
  • useDefaultFilters=false : 기본적으로 필터링 하지 않음을 의미



  • 확인 테스트를 위한 Application3을 만들고 코드는 (1,2) 그대로 유지한다.
  • MemberDAO 만 빈으로 생성되고 등록되었음을 확인할 수 있다.

 

 

 

 

ContextConfiguration 을 XML 형태로 테스트

javaconfig / xmlconfig 호환해서 테스트 해보기 위함

다음 클래스를 작성한다. 

 

 

  • 앞서 작성한 기능을 그대로 사용하여 테스트 해보기 위해 section01 에서 위 코드르를 그대로 가져온다. 
  • 복사 붙여넣기 후 패키지명 변경

 

 

  • xml 설정 정보를 만들기위해 Spring 컨테이너와 그 xml 을 읽어올 수 있는 GenericXmlApplicationContext를 생성한다. 

 

 

 

  • 설정 메타정보 경로 작성

 

  • 경로를 작성한 메타 정보 파일은 실제 존재하지 않으므로 다음과같은 단계를 통해 만들어주도록 한다.

 

  • 해당 xml 파일에 설정하고 싶은 정보는 다음과같다. 
  • @Component 혹은 @Repository 등이 기재된 클래스의 [빈스캐닝]을 해올 것
  • 자바 config 에서 어노테이션을 붙여 작성했다면, xml에서는 태그를 이용해 다음과같이 작성한다. 
  • 컴파일 에러 줄이 뜨는 이유 : Context 의 sckima 스키마가 정의되어있지 않기 때문

 

  • 에러 없애는 법은 다음과 같다. 
  • 하단의 Namespace 클릭 > beans 와 context 체크 선택 > 다시 Source 로 돌아와 에러가 사라진 것을 확인

 

 

  • 스키마 정의 후 이전엔 존재하지 않았던 스키마정의들을 확인할 수 있다. 
  •  context 스키마가 있어야 정의할 수 잇으므로 하단의 namespaces 탭에서 context 스키마를 추가하고 작성할 것

 

  • 이러한 xml 에서의 설정은 하단의 자바 클래스에서 작성한 어노테이션과 의미적으로 다르지않다. 

 

  • 실행하면 다음과같은 콘솔창을 확인할 수 있다. 
  • xml 설정파일의 빈 스캐닝 하기위한 설정에 따라서 xmlconfig 하위의 클래스들을 스캐닝한 후,
  • MemberDAO 에 작성된 어노테이션을 읽어 들여서 ApplicationContext context = ... 가 빈 등록후 생성을 한다. 

 

 

 

 


 

 

  • 앞서 했던 것과 마찬가지로, 자바 클래스가 아닌 xml config 파일에서 includeFilters 와 excludeFilters 를 어떻게 사용하는지 살펴본다. 
  • 1번 파일을 그대로 붙여넣기하여 2번 파일을 생성한다. 

 

  • context: 뒤에 올 알맞은 엘리먼트로 다음과같은 추천이 뜬다. 

 

  • exclude-filter 를 정의하기위해 다음과같이 작성한다. 
  • type = 타입이 무엇인지 / expression = "빈 스캐팅에서 제외할 경로"

 

  • 위 xml 설정과 자바 config 에서 코드로 작성했던 내용을 비교대조 해볼 수 있다. 의미적으론 일치한다.

 

  • 필터링에서 빠지는지 확인할 어플리 케이션 클래스 작성

 

  • exclude 필터를 넣어 빈 스캐닝에서 제외된 것을 확인할 수 있다. 

 

 

 

 

 

 

 

 

 

ContextConfiguration1 

package com.greedy.section01.javaconfig.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/* basePackages에 등록되지 않은 패키지는 스캔에서 제외하고, 등록된 패키지 내의
@Component 어노테이션을 탐색한다.
 * 이 때 basePackage를 등록하지 않으면 현 설정 클래스가 존재하는 패키지를 자동 
 basePackage로 설정한다. */
 
//@Configuration
//@ComponentScan(basePackages="com.greedy.section01.javaconfig")

public class ContextConfiguration1 {

}

 

 

ContextConfiguration2 

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

import com.greedy.section01.javaconfig.MemberDAO;

/* excludeFilter로 스캐닝에서 제외할 타입을 기술하면 해당 타입은 스캐닝에서 제외한다. */
//@Configuration
//@ComponentScan(basePackages="com.greedy.section01.javaconfig", 
//		excludeFilters= {
//			@ComponentScan.Filter(
//					/* 1. 타입으로 설정 */
//					//type=FilterType.ASSIGNABLE_TYPE,
//					//classes= {MemberDAO.class}
//					/* 2. 어노테이션 종류로 설정 */
//					//type=FilterType.ANNOTATION,
//					//classes= {org.springframework.stereotype.Component.class}
//					/* 3. 표현식으로 설정 */
//					//type=FilterType.REGEX,
//					//pattern= {"com.greedy.section01.*"}
//					)
//		})
public class ContextConfiguration2 {

}

 

 

 

ContextConfiguration3

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

import com.greedy.section01.javaconfig.MemberDAO;

/* basePackages의 기본 설정 경로를 지정하고 useDefaultFilters를 false로 
하면 모든 어노테이션을 스캔하지 않는다.
 * 이 때 스캔할 대상 클래스만 따로 지정할 수 도 있다.
 * */
@Configuration
@ComponentScan(basePackages="com.greedy.section01.javaconfig",
			   useDefaultFilters=false,
			   includeFilters= { @ComponentScan.Filter(
					   	/* exclude 필터 설정하는 방식과 동일하다 */
					   	type=FilterType.ASSIGNABLE_TYPE,
					   	classes= {MemberDAO.class}
					   )})
public class ContextConfiguration3 {

}

 

 

 

 

 

 


 

 

 

 

 

 

Application1

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.greedy.section01.javaconfig.config.ContextConfiguration1;

public class Application1 {

	public static void main(String[] args) {
		
		/* ComponentScan 기능을 이용한 bean 등록 설정
		 * ComponentScan이란?
		 * base-package로 설정 된 하위 경로에 특정 어노테이션을 가지고 있는
         클래스를 이용하여 bean으로 등록한다.
		 * @Component 어노테이션이 작성 된 클래스를 인식하여 bean으로 만들게 되며
		 * 특수 목적에 따라 세부 기능을 제공하는 
         @Controller, @Service, @Repository, @Configuration 등을 인식한다.
		 * */
		
		ApplicationContext context 
        = new AnnotationConfigApplicationContext(ContextConfiguration1.class);
		
		String[] beanNames = context.getBeanDefinitionNames();
		for(String beanName : beanNames) {
			System.out.println("beanName : " + beanName);
		}
		
		MemberDAO memberDAO = context.getBean(MemberDAO.class);
		
		System.out.println(memberDAO.selectMember(1));
        
		System.out.println(memberDAO.insertMember(new MemberDTO(
        3, "user03", "pass03", "새로운멤버" )));
        
		System.out.println(memberDAO.selectMember(3));
		
		
	}

}

 

 

 

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.greedy.section01.javaconfig.config.ContextConfiguration2;

public class Application2 {

	public static void main(String[] args) {
		
		ApplicationContext context 
        = new AnnotationConfigApplicationContext(ContextConfiguration2.class);
		
		String[] beanNames = context.getBeanDefinitionNames();
		for(String beanName : beanNames) {
			System.out.println("beanName : " + beanName);
		}
		
		MemberDAO memberDAO = context.getBean(MemberDAO.class);
		
		System.out.println(memberDAO.selectMember(1));
		System.out.println(memberDAO.insertMember(new MemberDTO(
        3, "user03", "pass03", "새로운멤버")));
		System.out.println(memberDAO.selectMember(3));
		
		
	}

}

 

 

Application3

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.greedy.section01.javaconfig.config.ContextConfiguration3;

public class Application3 {

	public static void main(String[] args) {
		
		ApplicationContext context
        = new AnnotationConfigApplicationContext(ContextConfiguration3.class);
		
		String[] beanNames = context.getBeanDefinitionNames();
		for(String beanName : beanNames) {
			System.out.println("beanName : " + beanName);
		}
		
		MemberDAO memberDAO = context.getBean(MemberDAO.class);
		
		System.out.println(memberDAO.selectMember(1));
		System.out.println(memberDAO.insertMember(new MemberDTO(
        3, "user03", "pass03", "새로운멤버")));
		System.out.println(memberDAO.selectMember(3));

	}

}

 

 

 

interface MemberDAO

public interface MemberDAO {
	
	/* 회원 번호로 회원 정보를 조회하는 메소드 */
	MemberDTO selectMember(int sequence);

	/* 회원 정보를 저장하고 결과를 리턴하는 메소드 */
	boolean insertMember(MemberDTO newMember);
	
}

 

 

 

MemberDAOImpl implements MemberDAO

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Repository;

/* 인터페이스로 메소드를 강제화 한 후 구현하여 사용하면 강제성이 부여 된다.
 * 또한 결합 관계를 느슨하게 만들 수 있다.
 * */

/* 스프링 컨테이너가 스캐닝 기능을 이용하여 해당 클래스를 bean으로 등록할
수 있는 어노테이션을 설정한다.
 * value 속성을 이용하면 bean의 id를 설정할 수 있으며, value는 생략 가능하다.
 * 이름(id)를 설정하지 않으면 Class의 앞 글자를 소문자로 하여 bean을 생성한다.
 * @Controller, @Service, @Repository와 동일한 기능을 가지지만 각 계층을 
 표현하는 어노테이션은
 * 특정 용도에 맞는 부가적인 혜택이 있으니 게층별로 구분하여 사용하는 것이 좋다.
 * */
 
//@Component(value="memberDAO")
@Repository(value="memberDAO")
public class MemberDAOImpl implements MemberDAO{
	
	private final Map<Integer, MemberDTO> memberMap;
	
	public MemberDAOImpl() {
		memberMap = new HashMap<>();
		
		memberMap.put(1, new MemberDTO(1, "user01", "pass01", "홍길동"));
		memberMap.put(2, new MemberDTO(2, "user02", "pass02", "유관순"));
	}

	/* 매개변수로 전달받은 회원 번호를 map에서 조회 후 회원 정보를 
    리턴해주는 용도의 메소드 */
	@Override
	public MemberDTO selectMember(int sequence) {
		return memberMap.get(sequence);
	}
	
	/* 매개변수로 전달받은 회원 정보를 map에 추가하고 성공 실패 여부를 
    boolean으로 리턴하는 메소드 */
	@Override
	public boolean insertMember(MemberDTO newMember) {
		
		int before = memberMap.size();
		
		memberMap.put(newMember.getSequence(), newMember);
		
		int after = memberMap.size();
		
		return (after > before) ? true : false;
	}

}

 

 

MemberDTO

public class MemberDTO {
	
	private int sequence;
	private String id;
	private String pwd;
	private String name;
	
	public MemberDTO() {}

	public MemberDTO(int sequence, String id, String pwd, String name) {
		super();
		this.sequence = sequence;
		this.id = id;
		this.pwd = pwd;
		this.name = name;
	}

	public int getSequence() {
		return sequence;
	}

	public void setSequence(int sequence) {
		this.sequence = sequence;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "MemberDTO [sequence=" 
        + sequence + ", id=" + id + ", pwd=" + pwd + ", name=" + name + "]";
	}
	
	

}

 

 

 

 

 

 

 


 

 

 

 

 

chap02-component-scan : section02

 

 

 

spring-context1.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"
	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-4.3.xsd">

	<!-- context 스키마가 있어야 정의할 수 잇으므로 하단의 namespaces 탭에서
    context 스키마를 추가하고 작성할 것 -->
	<context:component-scan base-package="com.greedy.section02.xmlconfig"/>
	
</beans>

 

 

spring-context2.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"
	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-4.3.xsd">

	<!-- context 스키마가 있어야 정의할 수 잇으므로 하단의 namespaces 탭에서
    context 스키마를 추가하고 작성할 것 -->
	<context:component-scan base-package="com.greedy.section02.xmlconfig">
		<context:exclude-filter type="assignable" 
        expression="com.greedy.section02.xmlconfig.MemberDAO"/>
	</context:component-scan>
	
</beans>

 

 

Application1

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application1 {

	public static void main(String[] args) {
		
		ApplicationContext context
  = new GenericXmlApplicationContext("com/greedy/section02/xmlconfig/config/spring-context1.xml");
	
		String[] beanNames = context.getBeanDefinitionNames();
		for(String beanName : beanNames) {
			System.out.println("beanName : " + beanName);
		}
		
		MemberDAO memberDAO = context.getBean(MemberDAO.class);
		
		System.out.println(memberDAO.selectMember(1));
		System.out.println(memberDAO.insertMember(new MemberDTO(
        3, "user03", "pass03", "새로운멤버")));
		System.out.println(memberDAO.selectMember(3));
		
	
	}

}

 

 

Application2 

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

public class Application2 {

	public static void main(String[] args) {

		ApplicationContext context
= new GenericXmlApplicationContext("com/greedy/section02/xmlconfig/config/spring-context2.xml");
	
		String[] beanNames = context.getBeanDefinitionNames();
		for(String beanName : beanNames) {
			System.out.println("beanName : " + beanName);
		}
		
		MemberDAO memberDAO = context.getBean(MemberDAO.class);
		
		System.out.println(memberDAO.selectMember(1));
        
		System.out.println(memberDAO.insertMember(new MemberDTO(
        3, "user03", "pass03", "새로운멤버")));
        
		System.out.println(memberDAO.selectMember(3));
	}

}

 

 

MemberDAO 

public interface MemberDAO {
	
	/* 회원 번호로 회원 정보를 조회하는 메소드 */
	MemberDTO selectMember(int sequence);

	/* 회원 정보를 저장하고 결과를 리턴하는 메소드 */
	boolean insertMember(MemberDTO newMember);
	
}

 

 

 

MemberDAOImpl implements MemberDAO

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Repository;

/* 인터페이스로 메소드를 강제화 한 후 구현하여 사용하면 강제성이 부여 된다.
 * 또한 결합 관계를 느슨하게 만들 수 있다.
 * */

/* 스프링 컨테이너가 스캐닝 기능을 이용하여 해당 클래스를 bean으로 등록할 수 있는 
어노테이션을 설정한다.
 * value 속성을 이용하면 bean의 id를 설정할 수 있으며, value는 생략 가능하다.
 * 이름(id)를 설정하지 않으면 Class의 앞 글자를 소문자로 하여 bean을 생성한다.
 * @Controller, @Service, @Repository와 동일한 기능을 가지지만 각 계층을
 표현하는 어노테이션은
 * 특정 용도에 맞는 부가적인 혜택이 있으니 게층별로 구분하여 사용하는 것이 좋다.
 * */
//@Component(value="memberDAO")
@Repository(value="memberDAO")
public class MemberDAOImpl implements MemberDAO{
	
	private final Map<Integer, MemberDTO> memberMap;
	
	public MemberDAOImpl() {
		memberMap = new HashMap<>();
		
		memberMap.put(1, new MemberDTO(1, "user01", "pass01", "홍길동"));
		memberMap.put(2, new MemberDTO(2, "user02", "pass02", "유관순"));
	}

	/* 매개변수로 전달받은 회원 번호를 map에서 조회 후 회원 정보를 
    리턴해주는 용도의 메소드 */
	@Override
	public MemberDTO selectMember(int sequence) {
		return memberMap.get(sequence);
	}
	
	/* 매개변수로 전달받은 회원 정보를 map에 추가하고 성공 실패 여부를 
    boolean으로 리턴하는 메소드 */
	@Override
	public boolean insertMember(MemberDTO newMember) {
		
		int before = memberMap.size();
		
		memberMap.put(newMember.getSequence(), newMember);
		
		int after = memberMap.size();
		
		return (after > before) ? true : false;
	}

}

 

 

 

MemberDTO

public class MemberDTO {
	
	private int sequence;
	private String id;
	private String pwd;
	private String name;
	
	public MemberDTO() {}

	public MemberDTO(int sequence, String id, String pwd, String name) {
		super();
		this.sequence = sequence;
		this.id = id;
		this.pwd = pwd;
		this.name = name;
	}

	public int getSequence() {
		return sequence;
	}

	public void setSequence(int sequence) {
		this.sequence = sequence;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "MemberDTO [sequence=" 
        + sequence + ", id=" + id + ", pwd=" + pwd + ", name=" + name + "]";
	}
	
	

}

 

 

 

 

 

 

 

 

'Programming > Spring Framework' 카테고리의 다른 글

5. Spring AOP (1)  (0) 2022.04.11
4. Spring DI 관리  (0) 2022.04.07
3. Spring IOC (1)  (0) 2022.04.06
2. Spring Framework  (0) 2022.04.06
1. Apache Maven  (0) 2022.04.06

 

 

 

 

 

 

 

Spring IoC

 

 

 

 

 

 

 

 

IoC (제어의 역행)


  • IoC(Inversion of Control)란, 프로그램을 구동하는데 필요한 객체에 대한 생성, 변경 등의 관리를 프로그램을 개발하는 사람이 아닌 프로그램을 구동하는 컨테이너에서 직접 관리하는 것을 말한다.
  • 스프링은 IoC 구조를 통해 구동 시 필요한 객체의 생성부터 생명 주기까지 해당 객체에 대한 관리를 직접 수행한다.

 

 

 

 

 

 

 

 

IoC 컨테이너


  • 스프링에서는 관리하는 객체를 'Bean(빈)'이라고 한다.
  • 해당 빈들을 관리한다는 의미로 컨테이너를 'Bean Factory'라고 한다.

 

 

▶ 위와 같이 나눠서 확장하는 이유 : 유지보수성을 위해 
별개의 인터페이스를 기능적으로 추가했을때 기존의 인터페이스는 영향받을 일이 없도록 함 최소한의 수정 가능

 

 

 

 

 

 

 

 

 

 

 

 

Spring IOC

 

 

 

 

 

 

 

IoC 컨테이너의 역할


  • 1. 객체의 생명주기와 의존성을 관리한다.
  • 2. VO(DTO/POJO) 객체의 생성, 초기화, 소멸 등의 처리를 담당한다.
  • 3. 개발자가 직접 객체를 생성할 수 있지만 해당 권한을 컨테이너에 맡김으로써 소스 코드 구현의 시간을 단축할 수 있다.

 

Plain Old Java Object
: 특정 설계 규약에 의해서 만들어 진것이 아닌 개발자가 필요에 의해 만든 클래스 (아무런 설계규약에 얽메이지 않음)

 

 

 

 

 

 

 

 

 

 

 

IoC 컨테이너와 Bean 객체


 

 

 

 

 

 

 

 

 

주요 컨테이너 종류


 

 

 

 

 

 

 

 

 

Spring DI

 

 

DI (의존성 주입)


  • DI(Dependency Injection)란 IoC 구현의 핵심 기술로, 사용하는 객체를 직접 생성하여 만드는 것이 아니라 컨테이너가 빈의 설정 정보를 읽어와 자동으로 해당 객체에 연결하는 것을 말한다.
  • 이렇게 의존성을 주입 받게 되면 이후 해당 객체를 수정해야 할 상황이 발생했을 때 소스 코드의 수정을 최소화 할 수 있다.

 

  • IoC는 제어의 역전이며 이 제어권이 개발자가 아닌 프레임 워크에 있다는 의미
  • 개발자는 사용하는 객체를 직접 생성하지 않고, 프레임워크가 맡겨진 객체들을 생성, 소멸 등의 관리를한다. 
  • 이 때, 컨테이너는 빈의 설정 정보를 읽어와서  자동으로 해당 객체에 연결되도록 하는 방법을 사용. B클래스의 객체를 생성시, B클래스에서 사용하는 A객체 역시 자동으로 생성시켜줌을 의미

 

 

 


DI의 장점


  • 1. 개발자가 작성해야 할 코드가 단순해진다.
  • 2. 각 객체 간의 종속 관계(결합도)를 해소할 수 있다.

 

 

 

 

 

 

 

객체간의 종속관계(결합도)


  • 한 클래스에서 필드 객체를 생성 할 때 발생하는 두 객체 간의 관계를 말하며, 각 객체간의 내용이 수정될 경우 영향을 미치는 정도를 나타낸다.
  • 예를 들어 A Class에서 B Class를 생성할 경우, 만약 B Class의 생성자의 매개변수가 변경되거나 제공하는 메소드가 변경될 경우 이를 사용하는 A Class의 일부 정보도 필히 수정해야 하는 상황이 발생하는데 이를 '두 객체간 종속관계(결합도)가 강하다' 라고 표현한다.

 

 

 

 

 

 

 

 

DI 의 종류


- Setter 메소드를 통한 의존성 주입

의존성을 주입받는 Setter 메소드를 만들고, 이를 통해 의존성을 주입


- 생성자를 통한 의존성 주입

필요한 의존성을 포함하는 클래스에 생성자를 만들고, 이를 통해 의존성을 주입


- 메소드를 통한 의존성 주입

의존성을 입력 받는 일반 메소드를 만들고 이를 통해 의존성을 주입

 

 

 

 

 

 

 

 

 

Setter 메소드를 통한 의존성 주입


Setter 메소드를 통해 의존관계가 있는 Bean을 주입하려면 <property> 태그를 사용한다.

 

 

 

 

 

XML 선언 방법


  • name 속성은 Class에서 선언한 필드 변수의 이름을 사용한다.
  • value 속성은 단순 값 또는 Bean이 아닌 객체를 주입할 때 사용한다.
  • ref 속성은 사용하면 Bean 이름을 이용해 주입할 Bean을 찾는다.

 

    <bean id="객체의 이름" class="클래스 풀네임">
        <property name="name" value="OOO" />
        <property name="name" ref="OOO" />
    </bean>

 

 

 

 

 

 

Setter 메소드를 통한 의존성 주입 예시


    <bean id="student"
        class="com.greedy.firstSpring.person.model.vo.Student">
            <property name="name" value="홍길동" />
            <property name="wallet" ref="money" />
    </bean>

    <bean id="money" class="com.greedy.firstSpring.wallet.model.vo.Wallet" />

 

 

 

 

 

 

 

 

생성자를 통한 의존성 주입


Constructor를 통해 의존관계가 있는 Bean을 주입하려면 <constructor-arg> 태그를 사용한다.

 

 

 

 

XML 선언 방법


  • Constructor 주입방식은 생성자의 파라미터를 이용하기 때문에 한번에 여러 개의 객체를 주입할 수 있다.
  • 필드 선언 순서에 따라 index 속성을 통해서도 접근이 가능하다.

 

    <bean id="불러 올 객체" class="클래스 풀네임">
        <constructor-arg index="0" value="OOO"/>
        <constructor-arg name="OOO" ref="OOO"/>
    </bean>

 

 

 

 

생성자를 통한 의존성 주입 예시


    <bean id="student"

    class="com.greedy.firstSpring.person.model.vo.Student">
        <constructor-arg index=“0” value=“홍길동”/>
        <constructor-arg index=“1” ref=“money”/>
    </bean>

    <bean id="money" class="com.greedy.firstSpring.wallet.model.vo.Wallet"/>

 

 

 

 

 

 

 

 

 

 

 

Spring DI 실습

 

 

 

Person Class


Spring DI 실습을 위한 Person VO 객체를 만든다.

 

 

 

 

 

 

 

Job Interface


Spring DI 실습을 위한 Job Interface 를 만든다.

 

 

 

 

 

 

Developer Class


Job 인터페이스를 상속 받는 Developer 객체를 만든다.

 

 

 

 

 

 

 

GenericXmlApplicationContext 생성


  • resources 폴더를 우클릭하여 Spring Bean Configuration File 을 클릭한다.
  • 만약 해당 목록이 보이지 않는다면 Other... 를 선택하여 spring tab에 있는 목록을 통해 진행

 

 

 

 

 

 

 

  • resources 폴더 경로를 확인하고, 파일의 이름을 bean.xml로 지은 뒤 Next
  • 사용할 xml 파일의 이름은 반드시 같지 않아도 된다.

 

 

 

 

 

 

  • spring에서 제공하는 네임스페이스 중 Beans 를 선택
  • 버전은 최신버전을 선택한 뒤 Finish

 

 

 

 

 

 

 

 

  • 생성된 xml 을 확인 한 뒤, 다음과 같은 내용을 추가한다.

 

    <!-- 생성자를 사용하여 DI를 적용할 경우 -->
    <bean id="person" class="com.greedy.testSpring.person.model.vo.Person">
        <constructor-arg index="0" value="홍길동"/>
        <constructor-arg index="1" ref="job"/> <!-- name 속성도 가능 -->
    </bean>

    <!-- Setter를 사용하여 DI를 적용할 경우 -->
    <bean id="person2" class="com.greedy.testSpring.person.model.vo.Person">
        <!-- setName() -->
        <property name="name" value="이순신" />
        <!-- setmyJob() -->
        <property name="myJob" ref="job" />
    </bean>

    <bean id="job" class="com.greedy.testSpring.job.model.vo.Job" />

 

 

 

 

 

 

 

MyPersonTest 생성


생성된 xml 을 확인 한 뒤, 다음과 같은 내용을 추가한다.

 

public class MyPersonTest {
    public static void main(String[] args) {
        // 1. IoC Container 생성
        ApplicationContext context =
        new GenericXmlApplicationContext("config/beans.xml");

        // 2. Person 객체 생성
        Person p1 = (Person) context.getBean("person1");

        // 3. Job객체 가져오기
        Job myJob = context.getBean("job", Job.class);

        // 4. 생성한 객체를 싱글톤 패턴으로 가져옴을 확인
        Person p2= (Person) context.getBean("person2", Person.class);
    }
}

 

 

 

 

 

 

 

 

 

 

'Programming > Spring Framework' 카테고리의 다른 글

5. Spring AOP (1)  (0) 2022.04.11
4. Spring DI 관리  (0) 2022.04.07
3. Spring IOC (2)  (0) 2022.04.06
2. Spring Framework  (0) 2022.04.06
1. Apache Maven  (0) 2022.04.06

 

 

 

 

 

 

 

 

 

Spring Framework

 

 

 

 

 


Spring Framework란?


  • 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로서 간단히스프링(Spring)이라고도 불린다.
  • 동적인 웹 사이트를 개발하기 위한 여러 가지 서비스를 제공하고 있으며 대한민국 공공기관의 웹 서비스 개발 시 사용을 권장하고 있는 전자정부 표준프레임워크의 기반 기술로서 쓰이고 있 다.
  • Spring 공식 사이트 : https://spring.io/
 

Spring makes Java simple.

Level up your Java code and explore what Spring can do for you.

spring.io

 

 

 

 

 

 

 

 

 

Spring의 특징


 

Ⅰ. DI ( Dependancy Injection / 의존성 주입)

설정 파일이나 어노테이션을 통해 객체간 의존 관계를 설정하여 개발자가 직접 의존하는 객체를생성할 필요가 없다.

 


Ⅱ. Spring AOP ( 관점 지향 프로그래밍)

Database의 트랜잭션처리나 로깅처리와 같이 여러 모듈에서 공통으로 필요로 하는 기능의 경우 해당 기능을 분리하여 관리한다.

 


Ⅲ. Spring JDBC

Mybatis나 Hibernate 등의 데이터베이스를 처리하는 영속성 프레임워크와 연결할 수 있는 인터페이스를 제공한다.

 


Ⅳ. Spring MVC

MVC 디자인 패턴을 통해 웹 어플리케이션의 Model, View, Controller 사이의 의존 관계를 DI 컨테이너에서 관리하여 개발자가 아닌 서버가 객체들을 관리하는 웹 어플리케이션을 구축할 수 있다.

 

 

 

 

▼ 스프링 삼각형 ▼
더보기

 

 

스프링 삼각형

:스프링의 핵심가치 세가지

 

 

IoC : 제어의 역전 


  • 라이브러리와 프레임워크의 차이

: 라이브러리는 JSON 라이브러리를 쓰고싶다면 다음과 같은 객체를 작성, Gson은 만들어져 있는 객체이고 이 만들어진 것들 가져다 쓴다. 즉, 개발자에게 주도권이 있는 상황

 

프레임 워크는 만들어져있는 틀이 이미있고 개발자는 new MemberLoginServlet 같은 객체를 생성한 적이 없다. 서블릿들은 톰갯이라는 was 서버에서 관리된다. was의 서블릿 콘테이너에서 관리. 

 

 

 

DI


: 결합단계를 낮춤으로서 유지보수성을 증가시킨다. 

 

 

AOP


: 관점지향 프로그래밍

- 관점 : 공통 관심사, 만든 클래스들이 모두 어떤 동일한 코드를 작성해야한다고 가정했을때 매 클래스에 전부 써주는 것보다 공통관심사를 한번 작성해 분리 해 놓고, 이 코드가 필요한 순간에 삽입시켜 동작시켜 주는 것이 효율적이다. 

즉, 응집도를 높이고 결합도를 낮춘다. 생산성과 유지보수성 증가

 

 

 

PSA (Portable Service Abstraction) 


- 가진 서비스의 특정 기술을 숨긴다. 사용한 어떤 특정기술이 업데이트 되더라도 숨겨놓음으로서 업데이트에 대한 부분만 수정되면 되지 이 기술변화에 대해서 개발자는 대응을 할 필요 없도록 함 프레임워크를 사용한 개발자의 비즈니스 로직은 변화되지않도록 함

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Spring의 구성 모듈


 

 

 

 

 

 

 

 

Core Container


  • Spring의 근간이 되는 IoC(또는 DI) 기능을 지원하는 영역을 담당하고 있다.
  • BeanFactory를 기반으로 Bean 클래스들을 제어할 수 있는 기능을 지원한다.

 

- Bean : 클래스, 스프링 프레임워크에 관리를 맡긴 클래스등을 이야기함 생성과 소멸들의 권한이 컨테이너에 있는 것
- Bean Factory : 위와같이 맡겨진 Bean 들을 관리 

 

 

 


Data 접근 계층


JDBC나 데이터 베이스에 연결하는 모듈, Data 트랜잭션에 해당하는 기능을 담당하여 영속성 프레임워크의 연결을 담당한다.

 

 

 

 

 

 

 

 

 

 

 

 

STS 설치

 

 

 

 

 

STS란?


  • Spring Tool Suite의 약자로, Spring Framework를 사용하기 위한 개발 툴을 말한다. 
  • 일반적으로는 별도의 설치 도구를 통해 설치하여 사용하나, 이클립스IDE에서 제공하는 STS plug-in을 통해 간단히 설치할 수 있다.
  • STS 공식 설치 사이트 : https://spring.io/tools/sts/all

 

 

 

 

 

 

 

 

Eclipse STS 설치


  • 이클립스 메뉴에서 [ Help ] - [ Eclipse Marketplace ]를 클릭하고 Find : sts 입력
  • [ Go ] 클릭 후 Spring Tool Suite 를 설치한다.

 

 

 

 

 

 

 

 

  • 설치 시 나오는 항목을 모두 선택하고, 설치가 완료되면 이클립스를 재실행한다.

 

 

 

 

 

 

 

  • 재 실행 시 다음과 같은 Spring Welcome page가 첫 화면에 보인다면 설치가 정상적으로 이루어 진 것이다.

 

 

 

 

 

 

 

 

 

 

 

 

 

Spring MVC

 

 

 

 

 

Spring MVC


  • Spring Framework 에서는 클라이언트의 화면을 표현하기 위한 View와 서비스를 수행하기 위한 개발 로직 부분(Model)을 나누는 MVC 2 패턴을 지원한다. 
  • 또한 Model, View, Controller사이의 의존 관계를 DI 컨테이너에서 관리하여 유연한 웹 어플리케이션을 쉽게 구현 및 개발할수 있다.

 

 

 

 

 

 

 

Spring MVC 요청 처리 과정


 

 

 

 

 

 

 

Spring MVC 구성 요소


 

 

 

 

 

 

  • 이클립스 [Window] - [Perspective] - [Customize Perspective]를 클릭

 

 

 

 

 

 

 

 

  • Shortcuts 탭에서 Spring Legacy Project를 선택하고 OK 클릭

 

 

 

 

 

 

 

 

  • Project Explorer 창에서 [New] - [Spring Legacy Project] 선택

 

 

 

 

 

 

 

 

 

  • 프로젝트 이름을 정하고, Template에서 Spring MVC를 선택 후 [Next]
  • 패키지 생성 창에서 'com.00000.프로젝트 명' 으로 패키지 생성

 

 

 

 

 

  • 생성이 완료된 프로젝트를 서버에 추가하고 프로젝트 명으로 접속한다.

 

 

 

 

 

 

 

 

  • 생성이 완료된 프로젝트를 서버에 추가하고 프로젝트 명으로 접속한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Spring 프로젝트 구조

 

 

 

 

 

 

Spring 폴더 구조


Spring Framework는 다음과 같은 폴더 구조를 가진다.

 

 

 

 

 

 

 

 

 

main folder


main 폴더는 다음과 같은 구성을 가진다.

 

 

 

 

 

 

 

 

 

webapp folder


웹 상의 루트 역할인 webapp 폴더는 다음과 같은 구성을 가진다.

 

 

 

 

 

 

'Programming > Spring Framework' 카테고리의 다른 글

5. Spring AOP (1)  (0) 2022.04.11
4. Spring DI 관리  (0) 2022.04.07
3. Spring IOC (2)  (0) 2022.04.06
3. Spring IOC (1)  (0) 2022.04.06
1. Apache Maven  (0) 2022.04.06

 

 

 

 

 

 

 

 

Apache Maven

 

 

 

 

Maven이란?


Maven이란 자바용 프로젝트 관리 도구로, project object model(POM) XML 문서를 통해 해당 프로젝트의 버전 정보 및 라이브러리 정보들을 통합하여 관리하는 프레임워크이다.

 

 

 

 

 


라이브러리 종속성


일반적인 프로젝트는 개발자가 필요한 라이브러리를 직접 찾아서 추가해야 하지만, Maven을 사용하면 pom.xml 문서에 사용하고자 하는 라이브러리를 등록하여 자동으로 프로젝트에 추가되게 하여 라이브러리 관리의 편리성을 제공해 준다.

 

 

 

 

 

 

 

 

Maven의 종속성


이제까지 프로젝트 내 lib 폴더에 사용할 라이브러리를 직접 추가하여 관리 해왔다면, maven은 pom.xml 문서 하나 만으로 필요한 라이브러리를 찾아서 자동으로 설치하고 관리할 수 있다.

 

 

 

 

 

 

 

 

POM이란?


POM(Project Object Model)은 하나의 프로젝트에서 사용하는 자바 버전, 라이브러리, 플러그인 구성을 통합하여 관리할 수 있게 각 설정 정보를 XML 문서화 한 것을 말한다.

 

 

 

 

 

 

 

POM.XML 의 구성


 

 

 

 

 

 

 

 

 

 

Apache Maven 설치하기


하기 경로를 통해 Apache Maven 사이트에 접속한다.

 

 

https://maven.apache.org/index.html

 

Maven – Welcome to Apache Maven

Welcome to Apache Maven Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project's build, reporting and documentation from a central piece of information. If you

maven.apache.org

 

 

 

 

 

 

 

 

  • 다운로드 받은 압축 파일을 dev 폴더에 압축 해제 한 뒤, 같은 경로에 repository라는 저장소 역할의 새 폴더를 하나 만들고, conf 폴더로 접근하여 settings.xml 파일을 열람한다.

 

 

 

 

Apache Maven 라이브러리 저장소 설정


settings.xml 문서에서 localRepository 부분을 찾아 주석 바깥으로 뺀 뒤, 저장소로 이용하고자 하는 폴더로 설정한다.

 

 

 

 

 

 

 

 

 

 

 

Eclipse와 Maven 연동


  • Eclipse를 실행하여 [Window] - [Preferences] - [Maven] - [User Settings] 에 접근
  • User Settings의 값을 이전에 설정한 conf 의 settings.xml의 위치로 변경한다.

 

 

 

 

 

 

 

 

 

Maven target 폴더


  • Maven을 사용할 경우 프로젝트 컴파일 시 target/classes 안에 컴파일 된 클래스 파일들이 위치하게 된다.
  • 일반적으로 maven clean 옵션을 사용하면 제거되어 문제는 없지만, 이후 형상관리를 위해 프로젝트 를 공유할 시 컴파일 된 결과까지 공유할 필요는 없기 때문에 target 폴더를 공유 목록에서 제외하는 Ignore 작업을 설정

 

 

 

 

 

 

 

Eclipse target 폴더 제외


  • [Window] - [Preferences]를 선택
  • [Team] - [Ignored Resources] 에서 [Add Pattern]을 누른 뒤, */target/* 을 추가

 

 

 

 

 

 

 

 

 

'Programming > Spring Framework' 카테고리의 다른 글

5. Spring AOP (1)  (0) 2022.04.11
4. Spring DI 관리  (0) 2022.04.07
3. Spring IOC (2)  (0) 2022.04.06
3. Spring IOC (1)  (0) 2022.04.06
2. Spring Framework  (0) 2022.04.06

+ Recent posts