📌 결론: 객체들이 서로 독립적으로 존재하면서도 외부의 조율에 따라 협력합니다.
// 예시: 인터페이스 정의
public interface PaymentService {
void pay(int amount);
}
// 구현체 생성
public class CreditCardPaymentService implements PaymentService {
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card.");
}
}
// DI를 이용한 주입
@Service
public class OrderService {
private final PaymentService paymentService;
@Autowired
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public void processOrder(int amount) {
paymentService.pay(amount);
}
}
PaymentService 인터페이스에 의존하며, 어떤 구현체(CreditCardPaymentService)를 사용할지는 외부 컨테이너가 결정합니다.유연성
테스트 용이성
유지보수성 향상
스프링에서는 객체 간의 의존 관계를 XML 설정 또는 Java Configuration을 통해 지정할 수 있습니다.
<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">
<!-- PaymentService 구현체 등록 -->
<bean id="paymentService" class="com.example.CreditCardPaymentService" />
<!-- OrderService에 PaymentService 주입 -->
<bean id="orderService" class="com.example.OrderService">
<constructor-arg ref="paymentService" />
</bean>
</beans>
OrderService 객체가 사용할 PaymentService를 XML 설정에서 주입합니다.@Configuration
public class AppConfig {
@Bean
public PaymentService paymentService() {
return new CreditCardPaymentService();
}
@Bean
public OrderService orderService() {
return new OrderService(paymentService());
}
}
@Configuration과 @Bean 애노테이션을 활용해 객체를 선언합니다. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// OrderService 객체를 가져와 사용
OrderService orderService = context.getBean("orderService", OrderService.class);
orderService.processOrder(1000);
ApplicationContext를 사용해 XML 설정을 로드하고 필요한 객체를 가져오는 예시입니다.getBean() 메서드로 스프링 컨테이너에서 관리하는 OrderService 객체를 쉽게 호출할 수 있습니다.생명주기 관리:
스프링 컨테이너가 객체의 생성과 소멸을 자동으로 관리합니다.
유연한 설정:
XML과 Java 설정을 모두 지원해 상황에 맞게 구성 변경이 용이합니다.
확장성:
인터페이스 기반의 의존성 주입으로, 구현체 변경 시 코드 수정 없이 대체가 가능합니다.
스프링 빈은 싱글톤과 프로토타입의 두 가지 스코프로 관리됩니다. 한 번 생성 후 공유할지, 요청할 때마다 새로 생성할지 지금 바로 알아보세요!
@Component
public class HelloService {
public String sayHello() {
return "Hello, Singleton!";
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloService service1 = context.getBean(HelloService.class);
HelloService service2 = context.getBean(HelloService.class);
System.out.println(service1); // 같은 인스턴스 반환
System.out.println(service2); // 동일한 해시코드 출력
com.example.HelloService@54afc369
com.example.HelloService@54afc369
getBean() 호출에서 같은 객체 인스턴스가 반환되었습니다. @Component
@Scope("prototype")
public class HelloService {
public String sayHello() {
return "Hello, Prototype!";
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloService service1 = context.getBean(HelloService.class);
HelloService service2 = context.getBean(HelloService.class);
System.out.println(service1); // 서로 다른 인스턴스 반환
System.out.println(service2); // 다른 해시코드 출력
com.example.HelloService@1d6a883
com.example.HelloService@7b6fabc
getBean() 호출에서 다른 객체 인스턴스가 반환된 것을 볼 수 있습니다. <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">
<!-- Singleton 빈 -->
<bean id="singletonService" class="com.example.HelloService" scope="singleton" />
<!-- Prototype 빈 -->
<bean id="prototypeService" class="com.example.HelloService" scope="prototype" />
</beans>
Singleton
Prototype
@Component
public class SingletonService {
public void doSomething() {
System.out.println("Singleton instance");
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SingletonService service1 = context.getBean(SingletonService.class);
SingletonService service2 = context.getBean(SingletonService.class);
System.out.println(service1); // 동일한 인스턴스
System.out.println(service2); // 동일한 인스턴스
com.example.SingletonService@54afc369
com.example.SingletonService@54afc369
@Component
@Scope("prototype")
public class PrototypeService {
public void doSomething() {
System.out.println("Prototype instance");
}
}
PrototypeService service1 = context.getBean(PrototypeService.class);
PrototypeService service2 = context.getBean(PrototypeService.class);
System.out.println(service1); // 서로 다른 인스턴스
System.out.println(service2); // 서로 다른 해시코드
com.example.PrototypeService@1d6a883
com.example.PrototypeService@7b6fabc
@Component
@Scope("request")
public class RequestService {
public void handleRequest() {
System.out.println("New request instance");
}
}
@Component
@Scope("session")
public class SessionService {
public void manageSession() {
System.out.println("New session instance");
}
}
| 범위 | 설명 |
|---|---|
singleton | 스프링 컨테이너당 하나의 인스턴스 빈 생성 (기본 설정) |
prototype | 요청할 때마다 새로운 인스턴스 생성 |
request | HTTP Request마다 새로운 인스턴스 생성 |
session | HTTP Session마다 새로운 인스턴스 생성 |
Singleton
Prototype
Request
Session
스프링 프레임워크에서 빈(Bean)은 애플리케이션의 핵심 구성 요소입니다. 스프링은 다양한 방식을 통해 빈을 정의하고, 이 정보는 IoC(Inversion of Control) Container가 관리합니다. 이 과정에서 Bean Definition Meta Data가 중요한 역할을 합니다. 아래에서 빈 설정의 메타 정보가 생성되고 전달되는 흐름을 설명합니다.
스프링에서는 빈의 메타 정보를 세 가지 방식으로 표현할 수 있습니다:
XML Document
applicationContext.xml과 같은 설정 파일에서 빈의 생성, 의존성, 스코프를 정의합니다.<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="myService" class="com.example.MyService" scope="singleton"/>
</beans>
Annotation (애노테이션)
@Component, @Service, @Controller, @Repository와 같은 스테레오타입 애노테이션을 사용합니다.@Component
public class MyService {
public void doService() {
System.out.println("Service is running.");
}
}
Java Code (자바 코드 설정)
@Configuration과 @Bean 애노테이션을 사용해 프로그램적으로 빈을 등록하는 방식입니다.@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
스프링은 XML, 애노테이션, 자바 설정으로 정의된 정보를 Bean Definition Meta Data로 변환합니다.
이 메타 데이터는 각 빈의 타입, 이름, 의존 관계, 스코프 등을 포함하며, IoC 컨테이너에 전달됩니다.
빈 이름: myService
클래스: com.example.MyService
스코프: singleton
의존성 정보: 해당 클래스가 필요로 하는 다른 빈들
이 정보는 스프링 컨테이너가 빈 생성과 의존성 주입을 관리하는 데 사용됩니다.
스프링 프레임워크에서 XML 파일은 애플리케이션의 빈(Bean)과 그 의존성을 구성하는 대표적인 방법입니다. XML 설정을 사용하면 코드와 설정을 분리해 구조화된 관리가 가능하며, 각 빈의 세부적인 속성을 명확히 기술할 수 있습니다. 아래에서 XML 빈 설정의 핵심 개념과 일반적인 예제를 살펴보겠습니다.
XML을 통해 스프링의 각 빈을 정의하고 의존성 주입을 수행할 수 있습니다. 이 방법은 특히 코드와 설정을 분리해 관리하려는 경우에 유용합니다.
<bean> 태그를 사용해 빈의 세밀한 제어가 가능합니다.<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">
<!-- DataSource 빈 설정 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<!-- DAO 빈 설정 -->
<bean id="userDao" class="com.example.dao.UserDaoImpl">
<constructor-arg ref="dataSource"/>
</bean>
<!-- Service 빈 설정 -->
<bean id="userService" class="com.example.service.UserServiceImpl">
<constructor-arg ref="userDao"/>
</bean>
<!-- Controller 빈 설정 -->
<bean id="userController" class="com.example.controller.UserController">
<constructor-arg ref="userService"/>
</bean>
</beans>
DataSource 빈 설정
SimpleDriverDataSource를 사용해 데이터베이스 연결 정보를 설정합니다. property 태그를 사용해 데이터베이스 드라이버, URL, 사용자 이름, 비밀번호와 같은 속성을 설정합니다.DAO 빈 설정
UserDaoImpl 클래스는 데이터 접근을 담당합니다. dataSource 객체를 주입합니다.Service 빈 설정
UserServiceImpl은 비즈니스 로직을 담당합니다. userDao를 생성자 주입 방식으로 받아서 사용합니다.Controller 빈 설정
UserController는 사용자 요청을 처리합니다. userService를 생성자 주입 방식으로 전달받아 비즈니스 로직을 호출합니다.XML 파일 로딩:
applicationContext.xml과 같은 파일을 로드합니다.빈 생성 및 의존성 주입:
빈 관리:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.processRequest();
스프링에서 XML 설정은 코드와 설정을 분리해 관리할 수 있는 좋은 방법입니다. 복잡한 의존성 관계를 명확하게 정의할 수 있으며, 대규모 애플리케이션에서 유용합니다.
XML 설정의 장점과 단점을 이해하고 상황에 맞게 활용하면 스프링 애플리케이션의 구조와 유지보수성을 크게 향상시킬 수 있습니다.
@Autowired 애노테이션은 의존성 주입(Dependency Injection)을 수행합니다.@Repository
public class UserDaoImpl implements UserDao {
private final DataSource dataSource;
private final DBUtil dbUtil;
@Autowired
public UserDaoImpl(DataSource dataSource, DBUtil dbUtil) {
this.dataSource = dataSource;
this.dbUtil = dbUtil;
}
}
DataSource와 DBUtil 빈이 주입됩니다.<beans xmlns="http://www.springframework.org/schema/beans"
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">
<context:component-scan base-package="com.example"/>
</beans>
com.example 패키지 아래의 모든 클래스가 스캔 대상이 됩니다.@Repository, @Service, @Controller 등 스테레오타입 애노테이션이 부여된 클래스를 자동으로 빈으로 등록합니다.스테레오타입 애노테이션은 클래스의 역할에 따라 빈을 구분해 등록합니다.
| Stereotype | 적용 대상 |
|---|---|
@Repository | 데이터 접근 계층(DAO) 클래스에 사용. AOP와 결합해 예외를 처리합니다. |
@Service | 비즈니스 로직 계층(Service Layer) 클래스에 사용합니다. |
@Controller | MVC 패턴의 컨트롤러로 사용, 웹 요청을 처리합니다. |
@Component | 일반적으로 계층 구분이 어려운 클래스에 사용합니다. |
@Service
public class UserServiceImpl implements UserService {
// 비즈니스 로직 구현
}
@Controller
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
public String handleRequest() {
return "User Request Handled";
}
}
스프링의 Annotation 기반 빈 설정은 코드와 설정을 통합해 관리의 효율성을 높입니다. @Autowired와 같은 애노테이션을 통해 의존성 주입이 간단해지며, 스테레오타입 애노테이션을 사용해 계층별로 구조화된 애플리케이션을 만들 수 있습니다.
@Configuration 클래스는 스프링 컨테이너가 빈으로 등록할 설정을 포함합니다.@Configuration
@ComponentScan(basePackages = {"com.example"})
public class ApplicationConfig {
@Bean
public DataSource getDataSource() {
SimpleDriverDataSource sdds = new SimpleDriverDataSource();
sdds.setDriverClass(com.mysql.cj.jdbc.Driver.class);
sdds.setUrl("jdbc:mysql://127.0.0.1:3306/mydb?serverTimezone=UTC&useUnicode=yes&characterEncoding=UTF-8");
sdds.setUsername("root");
sdds.setPassword("password");
return sdds;
}
}
@Configuration:
@ComponentScan:
com.example 패키지 아래에 있는 @Component, @Service, @Repository 등이 자동으로 등록됩니다.@Bean:
SimpleDriverDataSource 설정:
DataSource를 빈으로 제공합니다.유연한 구성:
유지보수 용이성:
XML의 대체:
| XML 설정 | Java Configuration 설정 |
|---|---|
| 외부 XML 파일에 빈을 정의합니다. | 자바 코드에서 빈을 정의합니다. |
| 구성이 명확하지만 복잡해질 수 있습니다. | 코드 내에서 유연한 구성이 가능합니다. |
| 타입 안전성이 부족합니다. | 컴파일 시 타입 오류 확인이 가능합니다. |
Java Configuration은 자바 코드로 스프링 빈을 정의하여 더 유연하고 안전한 구성을 제공합니다. XML 설정의 복잡도를 줄이고, 조건에 따라 동적으로 빈을 구성할 수 있습니다. @Configuration과 @Bean을 적절히 활용하면 강력한 애플리케이션 구조를 구현할 수 있습니다.
<beans> 태그가 모든 빈 정의를 감쌉니다.applicationContext.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.xsd">
</beans>
<bean> 태그를 사용해 빈을 정의하고, 필요한 의존성을 주입할 수 있습니다.<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="userDao" class="com.example.dao.UserDaoImpl">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="userService" class="com.example.service.UserServiceImpl">
<constructor-arg ref="userDao"/>
</bean>
<bean id="userController" class="com.example.controller.UserController">
<constructor-arg ref="userService"/>
</bean>
<bean> 태그
기본 속성:
<constructor-arg> 태그:
ref 속성을 통해 다른 빈을 참조합니다.XML 파일 로딩:
applicationContext.xml 파일을 로드합니다.빈 생성 및 의존성 주입:
빈 사용:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.handleRequest();
UserController 빈을 가져와 웹 요청을 처리합니다.스프링의 XML 설정은 빈과 의존성을 명확하게 정의하고 코드와 설정을 분리할 수 있는 좋은 방법입니다. 특히 대규모 애플리케이션에서 복잡한 의존 관계를 쉽게 관리할 수 있습니다. 하지만, XML 설정의 복잡도를 줄이기 위해 Java Configuration 또는 Annotation 설정과 함께 사용하는 것이 좋습니다.
이제 XML 설정을 활용해 스프링 애플리케이션을 더 구조화된 형태로 만들어보세요!
빈 생성과 의존성 주입을 명확하게 정의해 유지보수와 확장성이 뛰어난 코드를 작성할 수 있습니다. 🌱
스프링에서는 XML 파일을 활용해 빈 객체를 생성하고 의존 관계를 설정할 수 있습니다. 아래에서는 빈 객체를 가져오는 방법과 생성자 주입(Dependency Injection)을 통한 의존성 설정을 설명합니다.
아래는 일반적인 예제로 수정한 내용입니다.
스프링의 IoC 컨테이너는 XML 설정 파일에 정의된 대로 빈 객체를 생성하고 의존성을 주입합니다. 이를 통해 애플리케이션에서 빈을 가져와 사용할 수 있습니다.
ApplicationContext context =
new ClassPathXmlApplicationContext("com/example/configuration/applicationContext.xml");
UserController userController = context.getBean("userController", UserController.class);
userController.processRequest();
ClassPathXmlApplicationContext를 통해 스프링 XML 설정 파일을 로드합니다.userController 빈을 가져옵니다.생성자 주입은 객체가 생성될 때 필수 의존성을 주입하는 방식입니다. XML 파일에서 <constructor-arg> 태그를 통해 의존성을 정의할 수 있습니다.
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
<bean id="userDao" class="com.example.dao.UserDaoImpl">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="userService" class="com.example.service.UserServiceImpl">
<constructor-arg ref="userDao"/>
</bean>
<bean id="userController" class="com.example.controller.UserController">
<constructor-arg ref="userService"/>
</bean>
userDao는 dataSource 객체를 생성자 주입받습니다.userService는 userDao를 의존성으로 주입받습니다.userController는 userService를 주입받아 사용자 요청을 처리합니다.public class UserServiceImpl implements UserService {
private final UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
@Override
public String processUserData(String userId) {
return userDao.getUserById(userId);
}
}
UserServiceImpl 클래스는 생성자를 통해 UserDao 객체를 주입받습니다.processUserData() 메서드는 주입받은 userDao 객체를 사용해 사용자 데이터를 처리합니다.getBean() 메서드를 통해 빈을 가져와 사용합니다.스프링에서는 XML 설정을 통해 객체의 의존성을 주입할 수 있으며, 이 중 하나가 Property Injection(프로퍼티 주입)입니다. 프로퍼티 주입은 Setter 메서드를 통해 객체에 값을 설정하는 방식으로, 주로 단순한 데이터나 빈 객체를 주입할 때 사용됩니다.
<property> 태그를 사용해 해당 객체에 값을 주입합니다.<bean id="userService" class="com.example.service.UserServiceImpl">
<property name="serviceName" value="User Management Service"/>
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.example.dao.UserDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</bean>
userService 객체는 serviceName에 문자열 값을 주입받고, userDao 객체를 참조합니다.userDao 객체는 dataSource 객체를 참조합니다.dataSource 객체는 데이터베이스 연결 정보를 주입받습니다.하위 태그(ref, value) 사용:
<property name="userDao" ref="userDao"/><value>Some String Value</value>속성 방식 사용:
<property name="userDao" ref="userDao"/><property name="serviceName" value="User Service"/>XML Namespace를 사용한 설정:
p 네임스페이스를 등록하면, 더 간결하게 설정할 수 있습니다.<bean id="adminService" class="com.example.AdminServiceImpl"
p:name="Admin Service" p:adminDao-ref="adminDao"/>
public class UserServiceImpl implements UserService {
private String serviceName;
private UserDao userDao;
// Setter for serviceName
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
// Setter for userDao
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void process() {
System.out.println("Service: " + serviceName);
userDao.getUser();
}
}
UserServiceImpl 클래스는 setter 메서드를 통해 serviceName과 userDao를 주입받습니다.필수 의존성 주입이란, 객체가 정상적으로 동작하기 위해 반드시 필요한 의존 객체를 주입하는 것을 의미합니다. 해당 의존성이 주입되지 않으면 객체가 제대로 작동하지 않기 때문에 주입이 필수적입니다. 필수 의존성은 주로 생성자 주입(Constructor Injection)을 통해 강제되며, 주입이 누락되면 컴파일 시점 혹은 애플리케이션 초기화 시점에 오류가 발생합니다.
생성자 주입은 객체가 생성될 때 필수적으로 필요한 의존성을 전달하는 방법입니다. 스프링에서 생성자 주입은 주입할 객체가 없으면 애플리케이션이 실행되지 않도록 설계됩니다.
XML 설정:
<bean id="userDao" class="com.example.dao.UserDaoImpl"/>
<bean id="userService" class="com.example.service.UserServiceImpl">
<constructor-arg ref="userDao"/>
</bean>
Java 클래스:
public class UserServiceImpl implements UserService {
private final UserDao userDao;
// 생성자 주입: 필수 의존성 보장
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
public void performService() {
System.out.println("Using UserDao: " + userDao);
}
}
UserServiceImpl 클래스는 생성자를 통해 UserDao 의존성을 필수로 주입받습니다.userDao가 주입되지 않으면 스프링 컨테이너가 객체를 생성할 수 없으므로 오류가 발생합니다.필수 의존성 주입 (생성자 주입 사용):
선택적 의존성 주입 (Setter 주입 사용):
Setter 주입 예시:
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void performService() {
if (userDao == null) {
System.out.println("UserDao not initialized!");
} else {
System.out.println("Using UserDao: " + userDao);
}
}
}
스프링 프레임워크에서는 Annotation을 사용하여 의존성 주입(Dependency Injection, DI)을 간결하고 명확하게 수행할 수 있습니다. 애노테이션은 Setter 메서드 작성 없이도 멤버 변수나 생성자에 직접 주입할 수 있으며, 주로 @Autowired, @Resource, @Inject 같은 애노테이션이 사용됩니다. 각 애노테이션의 특성과 사용 방법을 아래에서 자세히 설명합니다.
| Annotation | 설명 |
|---|---|
| @Autowired | 스프링 전용 애노테이션. 스프링 컨텍스트에서 자동으로 의존성을 주입합니다. |
| @Resource | JSR-250 표준 애노테이션. 자원을 이름으로 주입하며, 주로 JNDI 리소스 주입에 사용됩니다. |
| @Inject | JSR-330 표준 애노테이션. 특정 프레임워크에 종속되지 않는 의존성 주입을 수행합니다. |
@Autowired는 스프링 프레임워크에서 제공하는 의존성 주입 애노테이션으로, 타입에 맞는 빈을 자동으로 찾아 주입합니다.
@Service
public class UserService {
@Autowired
private UserDao userDao; // 타입 매칭으로 의존성 주입
public void performService() {
userDao.getUser();
}
}
@Resource는 JSR-250 표준 애노테이션으로, 스프링 2.5부터 지원됩니다. 주로 JNDI 리소스나 환경 설정 값과 같은 자원을 주입할 때 사용됩니다. 이름으로 매칭하여 주입되므로 주입하려는 빈의 이름을 명확히 설정해야 합니다.
@Service
public class UserService {
@Resource(name = "userDao") // 이름으로 빈 매칭
private UserDao userDao;
public void performService() {
userDao.getUser();
}
}
@Inject는 JSR-330 표준에 따른 애노테이션으로, 특정 프레임워크에 종속되지 않는 애플리케이션을 설계할 때 사용됩니다. 스프링뿐만 아니라 다른 DI 프레임워크에서도 사용할 수 있습니다.
public class UserService {
@Inject
private UserDao userDao;
public void performService() {
userDao.getUser();
}
}
스프링에서 Annotation을 활성화하려면 XML 설정 파일에서 관련 설정을 추가해야 합니다.
<beans xmlns="http://www.springframework.org/schema/beans"
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.xsd">
<context:annotation-config/> <!-- 애노테이션 설정 활성화 -->
</beans>
| Annotation | 지원 버전 | 매칭 기준 | 주요 사용처 | 종속성 |
|---|---|---|---|---|
| @Autowired | 스프링 2.5+ | 타입 매칭 | 스프링 프레임워크 내부 | 스프링 종속 |
| @Resource | 스프링 2.5+, JSR-250 | 이름 매칭 | JNDI 리소스 또는 환경 설정과 연동 | JNDI 종속 |
| @Inject | 스프링 3.0+, JSR-330 | 타입 매칭 | 프레임워크 비종속 애플리케이션 설계 | Java 표준 |
스프링에서는 Annotation을 통해 빈 객체의 생성 및 의존성 주입을 간단하게 관리할 수 있습니다. Annotation 기반 설정은 유지보수가 쉽고 직관적이며, 코드와 설정의 결합을 최소화할 수 있습니다. 아래에서 다양한 상황에서 Annotation을 사용하는 예제와 함께 설정 방법을 설명합니다.
@ComponentScan은 스프링이 지정된 패키지 내의 클래스들을 자동으로 스캔하고 빈으로 등록하게 합니다.
<context:component-scan base-package="com.example"/>
@Configuration
@ComponentScan(basePackages = {"com.example"})
public class AppConfig {
}
스프링에서는 여러 Annotation을 제공해 객체를 빈으로 등록하고 주입할 수 있습니다. 주요 Annotation과 그 역할은 다음과 같습니다.
@Component
public class EmailService {
public void sendEmail(String message) {
System.out.println("Sending email: " + message);
}
}
@Service
public class UserService {
public String getUserInfo(String userId) {
return "User Info: " + userId;
}
}
@Repository
public class UserRepository {
public void saveUser(String user) {
System.out.println("User saved: " + user);
}
}
@Controller
public class UserController {
@Autowired
private UserService userService;
public String handleRequest(String userId) {
return userService.getUserInfo(userId);
}
}
@Service
public class OrderService {
@Autowired
private UserRepository userRepository;
public void processOrder(String orderId) {
userRepository.saveUser(orderId);
}
}
@Repository
public class ProductRepository {
private final DataSource dataSource;
@Autowired
public ProductRepository(DataSource dataSource) {
this.dataSource = dataSource;
}
}
@Component
public class PaymentService {
private DataSource dataSource;
@Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}
만약 동일한 타입의 빈이 여러 개 있을 경우, @Qualifier를 사용해 특정 빈을 선택할 수 있습니다.
@Service
public class CustomerService {
@Autowired
@Qualifier("premiumCustomerRepository")
private CustomerRepository customerRepository;
}
@Qualifier를 사용해 특정 빈을 명시합니다.스프링에서 빈(Bean) 객체의 생성 단위(Scope)와 Factory Method를 활용한 객체 생성은 유연한 애플리케이션 설계를 돕습니다. 아래에서 범위(Scope)의 종류와 Factory Method를 통한 빈 생성 방법을 일반적인 예시와 함께 자세히 설명합니다.
스프링은 빈의 범위(Scope)를 설정해 객체가 어떻게 생성되고 관리될지를 정의합니다. 기본적으로 singleton 범위를 사용하지만, 상황에 따라 prototype, request, session 범위를 설정할 수 있습니다.
| Scope | 설명 |
|---|---|
| singleton | 컨테이너당 하나의 인스턴스만 생성하여 사용합니다. (기본값) |
| prototype | 빈을 요청할 때마다 새로운 인스턴스가 생성됩니다. |
| request | HTTP Request마다 새로운 인스턴스가 생성됩니다. |
| session | HTTP Session마다 새로운 인스턴스가 생성됩니다. |
request와session범위는 웹 애플리케이션 컨텍스트(WebApplicationContext)에서만 사용할 수 있습니다.
<bean id="userService" class="com.example.UserService" scope="singleton"/>
<bean id="orderService" class="com.example.OrderService" scope="prototype"/>
userService 빈은 singleton 범위로 설정되어 컨테이너 내에서 하나의 인스턴스만 사용됩니다.orderService 빈은 prototype 범위로 설정되어 빈을 요청할 때마다 새로운 인스턴스가 생성됩니다.ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService1 = context.getBean("userService", UserService.class);
UserService userService2 = context.getBean("userService", UserService.class);
System.out.println(userService1 == userService2); // true (singleton)
OrderService orderService1 = context.getBean("orderService", OrderService.class);
OrderService orderService2 = context.getBean("orderService", OrderService.class);
System.out.println(orderService1 == orderService2); // false (prototype)
스프링에서는 Factory Method를 사용해 객체를 생성할 수 있습니다. 이 방법은 Singleton 패턴을 사용해 한 개의 인스턴스만 생성하거나, 복잡한 초기화 과정을 수행할 때 유용합니다.
public class DatabaseConnection {
private static DatabaseConnection instance;
// Private 생성자: 외부에서 직접 생성 불가
private DatabaseConnection() {}
// Static Factory Method를 통한 객체 생성
public static DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
}
getInstance() 메서드는 Singleton 패턴을 구현하여 하나의 인스턴스만 생성합니다.<bean id="dbConnection" class="com.example.DatabaseConnection" factory-method="getInstance"/>
getInstance() 메서드를 호출해 객체를 생성합니다.ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
DatabaseConnection dbConnection1 = context.getBean("dbConnection", DatabaseConnection.class);
DatabaseConnection dbConnection2 = context.getBean("dbConnection", DatabaseConnection.class);
System.out.println(dbConnection1 == dbConnection2); // true (같은 인스턴스)
dbConnection 빈은 Factory Method를 통해 생성되며, Singleton 패턴에 따라 동일한 인스턴스를 반환합니다.스프링 컨테이너에 의해 관리되는 빈(Bean) 객체는 특정한 생명 주기를 따릅니다. 빈의 생명 주기는 객체가 생성되고 의존성이 주입된 후, 애플리케이션이 종료될 때까지 다양한 단계로 구성됩니다. 스프링은 이 생명 주기 동안 개발자가 필요한 메서드를 호출할 수 있게 하여 초기화와 소멸 등의 과정을 관리합니다.
아래에서는 스프링 빈의 생명 주기를 전체적으로 설명하고, 각 단계가 어떤 역할을 하는지 자세히 다룹니다.
빈 생성:
의존성 주입:
초기화 메서드(init-method) 실행:
@PostConstruct 혹은 XML의 init-method)가 호출됩니다.빈 사용:
소멸 메서드(destroy-method) 실행:
@PreDestroy 어노테이션이나 XML의 destroy-method를 사용합니다.빈 소멸:
설정 파일 읽기:
빈 속성 설정:
setBeanName() 호출:
setBeanFactory() 또는 setApplicationContext() 호출:
postProcessBeforeInitialization() 호출:
afterPropertiesSet() 호출:
커스텀 초기화 메서드 실행:
init-method나 @PostConstruct 메서드가 실행됩니다.빈 사용:
postProcessAfterInitialization() 호출:
destroy() 호출 및 소멸 메서드 실행:
destroy() 메서드나 @PreDestroy 메서드가 호출됩니다.import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class UserService {
@PostConstruct
public void init() {
System.out.println("UserService 초기화 완료!");
}
public void useService() {
System.out.println("UserService 사용 중...");
}
@PreDestroy
public void destroy() {
System.out.println("UserService 소멸 중...");
}
}
<bean id="userService" class="com.example.UserService"
init-method="init" destroy-method="destroy"/>
init() 메서드는 빈이 생성된 후 초기화 작업을 수행합니다.destroy() 메서드는 애플리케이션 종료 시 빈을 정리합니다.public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Before Initialization: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("After Initialization: " + beanName);
return bean;
}
}
스프링의 빈 생명 주기는 객체가 생성되고 소멸될 때까지의 모든 과정을 포함합니다. 생명 주기 중에 개발자가 초기화 작업과 소멸 작업을 정의할 수 있으며, 이를 통해 애플리케이션의 안정성과 유지보수성을 높일 수 있습니다.
스프링의 생명 주기 관리를 활용해 애플리케이션의 자원 효율성을 극대화하세요! 🚀