1. Spring이란?
- Spring Framework. JAVA 기반의 오픈소스 애플리케이션 프레임워크
- 원하는 부분만 가져다 사용할 수 있도록 모듈화가 잘 되어있음
- 가벼운 솔루션. 경량 컨테이너로 자바 객체를 담고 직접 관리함
- IoC (Inversion of Control), 제어의 역전. 객체의 생성부터 소멸까지 객체 생성주기 관리를 사용자가 아닌 특별한 객체에게 맡기는 것
- DI (Dependency Injection), 의존성 주입. 객체를 외부(Spring)에서 생성해서 사용하려는 주체 객체에 주입시키는 방식
- AOP (Aspect Oriented Programming), 관점 지향 프로그래밍. 여러 모듈에서 공통적으로 사용하는 기능을 분리하여 관리하고, 재사용성을 높여주는 프로그래밍 기법
- MVC (Model-View-Controller) 패턴
- WAS에 독립적인 개발 환경. Tomcat과 같은 WAS가 내장되어 있어 자바 웹 애플리케이션을 구동할 수 있음

2. IoC / DI Container
컨테이너(Container)란?
- 인스턴스의 생명주기를 관리함
- 생성된 인스턴스들에게 추가적인 기능을 제공함
- WAS는 Servlet 컨테이너를 갖고 있음. 웹 브라우저로부터 Servlet URL에 해당하는 요청을 받으면, 해당 Servlet을 메모리에 올린 후 실행함. 개발자가 Servlet 클래스를 작성했지만, 실제로 Servlet을 메모리에 올리고 실행하는 것은 WAS가 갖고 있는 Servlet 컨테이너가 수행함. 기존에 메모리에 올라간 Servlet은 다시 메모리에 올리지 않고 등등 실행해서 결과를 웹 브라우저에 전달함. JSP도 마찬가지. 얘가 Servlet으로 바뀌어 똑같이 수행됨.
IoC란?
- Inversion of Control. 제어의 역전
- 개발자는 프로그램의 흐름을 제어하는 코드를 작성함. 근데 이 흐름의 제어를 개발자가 하는 것이 아니라, 다른 프로그램이 그 흐름을 제어하는 것을 IoC라고 함
DI란?
- Dependency Injection. 의존성 주입
- 공장이 인스턴스를 만들었다면, 그 인스턴스를 사용해야 함. 어떻게 그 인스턴스를 가져올까? -> DI
- 클래스 사이의 의존 관계를 Bean 설정 정보를 바탕으로 컨테이너가 자동으로 연결해 주는 것을 의미
Spring에서 제공하는 IoC / DI Container
- 공장 역할
- BeanFactory: IoC / DI에 대한 기본 기능을 갖고 있음
- Application Context: BeanFactory의 모든 기능을 포함하며, 일반적으로 BeanFactory보다 추천됨. 트랜잭션 처리, AOP에 대한 처리 등을 할 수 있음.
3. IoC / DI 예제 - xml 파일 기반
예제 1
# UserBean.java
package com.example.diexam01;
public class UserBean {
/*
* 일반적인 Java 클래스 == Bean 클래스
* 기본 생성자를 갖고 있음
* 필드는 private으로 선언함
* getter, setter 메소드를 가짐
*/
private String name;
private int age;
private boolean male;
public UserBean() {}
public UserBean(String name, int age, boolean male) {
this.name = name;
this.age = age;
this.male = male;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isMale() {
return male;
}
public void setMale(boolean male) {
this.male = male;
}
}
# DiExam01Application
<?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="userBean" class="com.example.diexam01.UserBean"></bean>
</beans>
# ApplicationContextExam01
package com.example.diexam01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationContextExam01 {
public static void main(String[] args) {
// 스프링 공장
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
System.out.println("초기화 완료");
UserBean userBean = (UserBean)ac.getBean("userBean");
userBean.setName("Jeon");
System.out.println(userBean.getName());
// 싱글톤 패턴 확인
UserBean userBean2 = (UserBean)ac.getBean("userBean");
System.out.println(userBean.getName());
}
}
예제 2
Engine.java
package com.example.diexam01;
public class Engine {
public Engine() {
System.out.println("Engine 생성자");
}
public void exec() {
System.out.println("엔진 동작");
}
}
Car.java
package com.example.diexam01;
public class Car {
private Engine v8;
public Car() {
System.out.println("Car 생성자");
}
public void setEngine(Engine e) {
this.v8 = e;
}
public void run() {
System.out.println("엔진을 이용하여 자동차 달림");
v8.exec();
}
public static void main(String[] args) {
// 제어의 역전으로, Spring IoC 컨테이너가 아래와 같은 일들을 수행함
// Engine e = new Engine();
// Car c = new Car();
// c.setEngine(e);
// c.run();
}
}
# applicationContext.xml
<bean id="e" class="com.example.diexam01.Engine" />
<bean id="c" class="com.example.diexam01.Car">
<property name="engine" ref="e"></property> <!-- getter, setter가 property. Car를 사용하기 위해 Engine을 set하기 위해 -->
</bean>
예제 3
# ApplicationContextExam02.java
package com.example.diexam01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationContextExam02 {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Car car = (Car)ac.getBean("c");
car.run();
}
}

DI
- 객체에게 객체를 주입함
- 사용자는 Engine을 모르고 Car 클래스만 알고 있어도 Spring 컨테이너가 자동으로 DI를 해줌
4. IoC / DI 예제 - Java Config 기반
예제 1
# ApplicationConfig.java
package com.example.diexam01;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ApplicationConfig {
@Bean
public Car car(Engine e) {
Car c = new Car();
return c;
}
@Bean
public Engine engine() {
return new Engine();
}
}
- xml 파일이 아닌 @Configuration 을 통해 Bean 정보를 보관함
- 싱글톤으로 관리할 수 있게 함
# ApplicationContextExam03.java
package com.example.diexam01;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class ApplicationContextExam03 {
public static void main(String[] args) {
// 설정 정보를 불러 읽어옴
ApplicationContext ac = new AnnotationConfigApplicationContext(ApplicationConfig.class);
// Car car = (Car)ac.getBean("Car");
Car car = (Car)ac.getBean(Car.class);
car.run();
}
}
예제 2
# ApplicationConfig2.java
package com.example.diexam01;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan // 알아서 Bean 정보를 등록해
public class ApplicationConfig2 {
}
# Engine.java
package com.example.diexam01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component // 추가됨
public class Engine {
public Engine() {
System.out.println("Engine 생성자");
}
public void exec() {
System.out.println("엔진 동작");
}
}
# Car.java
package com.example.diexam01;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Car {
@Autowired // Car 객체 내 Engine 객체를 알아서 주입해줘. 이제 setter는 없어도 됨
// @Qualifier("engine") // Engine이라는 인터페이스를 상속받은 클래스가 여러 개라면 명시해야 함
private Engine v8;
public Car() {
System.out.println("Car 생성자");
}
public void run() {
System.out.println("엔진을 이용하여 자동차 달림");
v8.exec();
}
public static void main(String[] args) {
// 제어의 역전으로, Spring IoC 컨테이너가 아래와 같은 일들을 수행함
// Engine e = new Engine();
// Car c = new Car();
// c.setEngine(e);
// c.run();
}
}
- @ComponentScan, @Component, @Autowired를 사용하여 DI
5. 정리
지극히 주관적인 정리
Car 객체가 Engine 객체에 의존한다면?!
객체들을 생성하고 관리하는 것을 Spring 컨테이너에게 맡김
-> IoC. 제어의 역전. 프로그램의 흐름을 개발자가 아닌 다른 프로그램에게 맡김
이때 Spring 컨테이너가 관리하는 자바 객체를 Bean이라고 함
그럼 Spring 컨테이너는 관리할 자바 객체 정보를 어떻게 얻을까?
1. @Configuration을 통해 해당 파일 하위에 @Bean을 사용하여 등록하고자 하는 클래스를 찾음
2. @ComponentScan을 통해 @Component, @Controller, @Service, @Repository 등을 모두 찾아 Bean으로 등록해 줌
3. Car 클래스와 Engine 클래스를 정의할 때 미리 @Component를 붙여줘야겠지~
4. Car의 경우에는 Engine에 의존하기에 @Autowired로 알려줌
5. 그럼 이제 Spring 컨테이너인 ApplicationContext(Bean Factory를 상속받은)를 통해 위와 같이 설정한 정보들을 불러 읽어온다.
각 클래스 사이에 필요한 의존관계를 Bean 설정 정보를 바탕으로 Spring 컨테이너가 자동으로 연결해 줌
이게 DI. 의존성 주입.
'강의 노트 > 웹 프로그래밍(풀스택)' 카테고리의 다른 글
[boostcourse] 3.9. Spring MVC - BE (1) (0) | 2023.06.26 |
---|---|
[boostcourse] 3.8. Spring JDBC - BE (0) | 2023.06.25 |
[boostcourse] 2.11. Web API - BE (0) | 2023.06.21 |
[boostcourse] 2.10. JDBC - BE (0) | 2023.06.20 |
[boostcourse] 2.5. Scope - BE (0) | 2023.06.20 |