간단한 특징
- 엔터프라이즈급 애플리케이션 개발 : EJB는 Java EE 플랫폼의 일부로, 서버 측 애플리케이션 개발을 위한 컴포넌트 모델을 제공함
- 선언적 프로그래밍 모델 : EJB는 복잡한 서버 사이드 로직을 구현하는데 필요한 선언전 트랜잭션관리, 보안 설정 등을 지원함
- 편리한 서비스 : 거래 처리, 보안, 분산 컴퓨팅 등의 기능을 제공하여 미들 웨어 수준의 복합한 개발 작업을 단순화함 (
미들웨어보다
)
단점
- 복잡성과 무거움 : EJB는 사용법이 복잡하고 러닝 커프가 높으며, 무거운 컨테이너가 필요함
- 유연성 부족 : 특정 서버 및 플랫폼에 종속되는 경향이 있어, 유연성이 부족함
- 개발 및 배포의 복잡함 : EJB 애플리케이션의 개발 및 배포 과정이 상대적으로 복잡함
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
은 스프링 IOC(Inversion of Control)컨테이너에 의해 관리되는 객체를 의미함, 이러한 Bean은 스프링 프레임워크의 핵심 개념 중 하나로, 스프링이 제공하는 종속성 주입(Dependency Injection) 기능을 통해 다루어짐
- 객체 간 결합도 감소 : 객체가 직접적으로 종속성을 생성하지 않고 외부에서 주입받기 때문에, 객체 간의 결합도가 낮아짐 → 코드의 재사용성과 유지보수성을 향상시킴
- 코드의 테스트 용이성 : 종속성 주입을 사용하면, 테스트 중에 실제 구현 대시 모의 객체(Mock) 또는 다른 구현을 쉽게 주입할 수 있음 → 테스트를 보다 단순하고 유연하게 만듦
- 유연한 코드 구조 : 종속성 주입을 사용하면, 구성 요소 간의 관계를 런타임에 설정할 수 있어, 애플리케이션의 유연성이 증가함
Book book = new Book();
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 book1 = new Book("즐거운 자바", 20000);
1) new Book("즐거운 자바",20000)
즉, 프로그래머가 직접 인스턴스를 생성하는 것은 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());
}
}
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;
}
}
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("다른 인스턴스");
}
}
}
ApplicationContext
을 제공해준다.Bean이 IoC(Inversion of Control) 컨테이너에 의해 관리된다
Bean의 생성, 생명주기 관리, 의존성 주입
등을 담당