Spring 프레임워크

이강용·2024년 1월 17일
0

CS

목록 보기
28/109

Spring 프레임워크이 나오기전에는?

  • Spring 프레임워크가 등장하기 이전 EJB가 존재했는데 먼저 EJB가 무엇인지 알아보자.

간단한 특징

  • 엔터프라이즈급 애플리케이션 개발 : EJB는 Java EE 플랫폼의 일부로, 서버 측 애플리케이션 개발을 위한 컴포넌트 모델을 제공함
  • 선언적 프로그래밍 모델 : EJB는 복잡한 서버 사이드 로직을 구현하는데 필요한 선언전 트랜잭션관리, 보안 설정 등을 지원함
  • 편리한 서비스 : 거래 처리, 보안, 분산 컴퓨팅 등의 기능을 제공하여 미들 웨어 수준의 복합한 개발 작업을 단순화함 (미들웨어보다)

단점

  • 복잡성과 무거움 : EJB는 사용법이 복잡하고 러닝 커프가 높으며, 무거운 컨테이너가 필요함
  • 유연성 부족 : 특정 서버 및 플랫폼에 종속되는 경향이 있어, 유연성이 부족함
  • 개발 및 배포의 복잡함 : EJB 애플리케이션의 개발 및 배포 과정이 상대적으로 복잡함

Spring 프레임워크의 등장

EJB의 대안으로 등장 : 로드 존슨(Rod Johnson)은 자신의 책 "Expert One-On-One : J2EE Design and Development"에서 EJB의 복잡성을 해결하는 간단하고 가벼운 대안으로 Spring프레임워크를 소개함
프로그래밍의 단순화 : Spring은 EJB의 복잡함 대신 POJO(Plain Old Java Object)를 사용하여 비지니스 로직을 구현할 수 있게 함으로써, 개발자에게 친숙한 방식으로 개발을 단순화함
유연한 종속성 관리 : Spring의 종속성 주입(Dependency Injection)은 컴포넌트 간의 결합도를 낮추고, 더 유연하고 테스트하기 쉬운 코드 작성을 가능하게 함
경량 컨테이너 및 테스트 용이성 : Spring의 경량 컨테이너는 애플리케이션의 시작 시간을 단축하고, 개발 및 배포 프로세스를 간소화함. 또한, 단위 테스트와 통합 테스트를 쉽게 수행할 수 있음
AOP 및 선언적 트랜잭션 관리 : Spring은 AOP(Aspect-Oriented Programming)를 지원하며, 선언적 트랜잭션 관리를 통해 개발자가 비지니스 로직에 집중할 수 있게 함
다양한 기술과의 통합 : Spring은 다양한 데이터베이스, ORM 프레임워크, 웹 서비스, 보안 프레임워크 등과 쉽게 통합될 수있음

Bean이란?

  • Bean은 스프링 IOC(Inversion of Control)컨테이너에 의해 관리되는 객체를 의미함, 이러한 Bean은 스프링 프레임워크의 핵심 개념 중 하나로, 스프링이 제공하는 종속성 주입(Dependency Injection) 기능을 통해 다루어짐

종속성 주입이란?

  • 디자인 패턴을 사용하여 객체 간의 종속성을 관리하는 프로세스를 말함
  • 이 패턴의 핵심은 객체가 필요로 하는 의존성(즉, 다른 객체)을 스스로 생성하지 않고, 외부에서 주입받는 것
  • 종속성 주입의 주요 목적과 장점은 다음과 같다.
  1. 객체 간 결합도 감소 : 객체가 직접적으로 종속성을 생성하지 않고 외부에서 주입받기 때문에, 객체 간의 결합도가 낮아짐 → 코드의 재사용성과 유지보수성을 향상시킴
  2. 코드의 테스트 용이성 : 종속성 주입을 사용하면, 테스트 중에 실제 구현 대시 모의 객체(Mock) 또는 다른 구현을 쉽게 주입할 수 있음 → 테스트를 보다 단순하고 유연하게 만듦
  3. 유연한 코드 구조 : 종속성 주입을 사용하면, 구성 요소 간의 관계를 런타임에 설정할 수 있어, 애플리케이션의 유연성이 증가함
  • Java에서 인스턴스 생성
    • 프로그래머가 직접 인스턴스를 생성함
Book book = new Book();
  • Bean은 Container가 관리하는 객체
    • 객체의 생명주기를 컨테이너가 관리한다.
    • 객체를 Singleton으로 만들것인지, 프로토타입으로 만들것인지

Spring의 핵심 기능

  • 관점지향 컨테이너
    • Bean을 생성, 관리
    • 관점지향(AOP, Aspect-oriented programming)

Book.java

package programmers;

public class Book { //Book 클래스
	
	private String title; // title 인스턴스 field(속성)
	private int price; // price 인스턴스 field(속성)
	
    // Book생성자
	public Book(String title, int price) {
		this.title = title;
		this.price = price;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public int getPrice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}
	
}

Book 클래스의 인스턴스 생성

Book book1 = new Book("즐거운 자바", 20000);

1) new Book("즐거운 자바",20000)

  • 생성자가 호출되면 Heap메모리에 인스턴스가 생성
    2) book1은 1)에서 생성한 인스턴스를 참조한다.
  • book1 참조변수

즉, 프로그래머가 직접 인스턴스를 생성하는 것은 Bean이 아니다.

프로그래머가 직접 인스턴스 생성 사용


public class BookExam01 {
	public static void main(String[] args){
		Book book = new Book("Java",10000);
        System.out.println(book.getTitle());
        System.out.println(book.getPrice());
	}

}

Bean을 만들 때 규칙

  • 기본 생성자가 있어야 한다.

ApplicationContext

package exam;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class ApplicationContext {
	
	Properties props;
	
	
	public ApplicationContext() {
		props = new Properties();
		
		try {
			props.load(new FileInputStream("src/Beans.properties"));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	public Object getBean(String id) throws Exception {
    
			String className = props.getProperty(id);
			// class name에 해당하는 문자열을 가지고 인스턴스를 생성할 수 있음
			// class.forName(className)dms CLASSPATH로부터 className에 해당하는 클래스를 찾은 후
			// 그 클래스 정보를 반환한다.
			Class<?> clazz = Class.forName(className);
			
			// ClassLoader를 이용한 인스턴스 생성. 기본 생성자가 있어야한다.
			Object o = clazz.newInstance(); // clazz정보를 이용해 인스턴스를 생성한다.			
			
		
		
		return o;
	}

}

ApplicationContextMain

package exam;

public class ApplicationContextMain {
	
	public static void main(String[] args) throws Exception {
		
		ApplicationContext context = new ApplicationContext();
		
		Book book = (Book) context.getBean("book1"); //id에 해당하는 인스턴스를 달라
		book.setPrice(5000);
		book.setTitle("즐거운 자바");
		
		System.out.println(book.getPrice());
		System.out.println(book.getTitle());
		
		
		System.out.println("---------");
		Book book2 =(Book)context.getBean("book1");
		System.out.println(book2.getTitle());
		
		if(book == book2) { //참조값이 같을 경우
			System.out.println("같은 인스턴스");
		}else {
			System.out.println("다른 인스턴스");
		}
		
	}
}

그렇다면, 같은 인스턴스를 호출하려면?

ApplicationContext

package exam;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ApplicationContext {
	
	Properties props;
	Map<String, Object> objectMap;
	
	public ApplicationContext() {
		props = new Properties();
		objectMap = new HashMap<>();
		try {
			props.load(new FileInputStream("src/Beans.properties"));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	public Object getBean(String id) throws Exception {
		Object o1 = objectMap.get(id);
		if(o1 == null) {
			String className = props.getProperty(id);
			// class name에 해당하는 문자열을 가지고 인스턴스를 생성할 수 있음
			// class.forName(className) CLASSPATH로부터 className에 해당하는 클래스를 찾은 후
			// 그 클래스 정보를 반환한다.
			Class<?> clazz = Class.forName(className);
			
			// ClassLoader를 이용한 인스턴스 생성. 기본 생성자가 있어야한다.
			Object o = clazz.newInstance(); // clazz정보를 이용해 인스턴스를 생성한다.			
			objectMap.put(id, o);
			o1 = objectMap.get(id);
		}
		
		return o1;
	}

}

객체를 싱글톤으로 생성해주고, 자기 자신도 싱글톤인 ApplicationContext

  • 컨테이너 역할을 수행한다.
  • Spring이 제공하는 컨테이너는 이것보다 훨씬 복잡한 일을 한다.

Singleton Pattern

ApplicationContext

package exam;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ApplicationContext {
	
	//1. 싱글톤 패턴 적용 - 자기 자신을 참조하는 static 필드를 선언한다. 바로 초기화
	private static ApplicationContext instance = new ApplicationContext();
	
	//3. 1.에서 만든 인스턴스를 반환하는 static 메서드를 만든다.
	public static ApplicationContext getInstance() {
		return instance;
	}
	
	
	private Properties props;
	private Map<String, Object> objectMap;
	
	//2. 싱글톤 패턴 적용 - 생성자를 private으로 바꾼다.
	private ApplicationContext() {
		props = new Properties();
		objectMap = new HashMap<>();
		try {
			props.load(new FileInputStream("src/Beans.properties"));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	public Object getBean(String id) throws Exception {
		Object o1 = objectMap.get(id);
		if(o1 == null) {
			String className = props.getProperty(id);
			// class name에 해당하는 문자열을 가지고 인스턴스를 생성할 수 있음
			// class.forName(className) CLASSPATH로부터 className에 해당하는 클래스를 찾은 후
			// 그 클래스 정보를 반환한다.
			Class<?> clazz = Class.forName(className);
			
			// ClassLoader를 이용한 인스턴스 생성. 기본 생성자가 있어야한다.
			Object o = clazz.newInstance(); // clazz정보를 이용해 인스턴스를 생성한다.			
			objectMap.put(id, o);
			o1 = objectMap.get(id);
		}
		
		return o1;
	}

}

ApplicationContextMain

package exam;

public class ApplicationContextMain {
	
	public static void main(String[] args) throws Exception {
		
		ApplicationContext context = ApplicationContext.getInstance();
		ApplicationContext context2 = ApplicationContext.getInstance();
		
		if(context == context2) {
			System.out.println("2개의 context는 같다.");
		}
		
		Book book = (Book) context.getBean("book1"); //id에 해당하는 인스턴스를 달라
		book.setPrice(5000);
		book.setTitle("즐거운 자바");
		
		System.out.println(book.getPrice());
		System.out.println(book.getTitle());
		
		
		System.out.println("---------");
		Book book2 =(Book)context.getBean("book1");
		System.out.println(book2.getTitle());
		
		if(book == book2) { //참조값이 같을 경우
			System.out.println("같은 인스턴스");
		}else {
			System.out.println("다른 인스턴스");
		}
		
	}
}

Spring이란?

  • 💡 엄청 잘 만든 ApplicationContext을 제공해준다.

Bean은 관리된다

  • Bean이 IoC(Inversion of Control) 컨테이너에 의해 관리된다
  • IoC컨테이너는 스프링에서 제공하는 핵심 기능 중 하나로, Bean의 생성, 생명주기 관리, 의존성 주입 등을 담당
profile
HW + SW = 1

0개의 댓글