Dependecy Injection은 의존하는 부분의 함수를 DI컨테이너에서 주입하는 것을 의미한다.
Aspect Oriented Programming 은 기능이아닌 예외 처리, 트랜잭션 제어, 출력 기능등 여러곳에서 사용하는 기능들을 프로그램의 여러곳에서 호출 할 수 있도록하고, 사용자는 구현하고자 하는 핵심기능들만 작성할 수 있도록 하는 기능이다. 이로써, 사용자는 여러곳에서 사용하는 기능들을 여러번 작성할 필요가 없다.
의존성 주입을 할수있게 도와주는 역할을 한다.
주입: new키워드를 통해 다른 클래스의 객체를 자신 클래스 안에서 사용하는 것.
만약 new로 직접 의존성을 생성하지 않고, DI컨테이너에게 다른 클래스의 객체 생성을 맡기면, 사용하는 쪽의 클래스 수정 없이 사용되는 쪽의 클래스만 수정해 기능을 바꿀 수 있다.(만약 그렇지 않다면, 둘 다 바꿔야 한다.)
DI컨테이너를 사용하려면 아래 규칙을 지켜야한다.
DI컨테이너가 객체를 생성할 때, 각 계층별로 사용하는 에너테이션이 다르다.
애플리케이션 계층: 클라이언트와 애플리케이션간 요청과 결과 반환
도메인 계층: 비지니스 로직 기술
인프라 계층: DB와 외부서비스와 통신
애플리케이션 계층: @Controller
도메인 계층: @Service
인프라 계층: @Repository
기타 객체 생성: @Component
클라이언트-> 애플리케이션 -> 도메인 -> 인프라 -> DB 순으로 통신된다.
1. 인터페이스 생성
public interface Greet{
String greeting();
}
2. 아침인사 기능구현
import org.springframework.stereotype.Component;
@Component
public class MorningGreet implements Greet{
@Override
public String greeting(){
return "좋은 아침입니다.";
}
}
3. 밤 인사 기능구현
import org.springframework.stereotype.Component;
//@Component : 주석처리(Component가 2개 있으면, 어떤쪽을 객체로 구현할지 몰라서 에러)
public class EveningGreet implements Greet{
@Override
public String greeting(){
return "안녕히 주무세요";
}
}
@Component 애너테이션을 통해, DI컨테이너가 객체를 생성하도록 지정한다.
스프링 이니셜라이저에서 프로젝트를 실행하면 아래처럼 Test클래스가 자동으로 생성된다.

이 파일은 아래처럼 애플리케이션이 시작할때 자동실행되도록 애너테이션이 붙어 있기 때문에, "시작 클래스"라고도 부른다.

이를 이용하여, 사용되는 쪽을 구현해보자.
import com.example.demo.used.Greet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
// 스프링부트를 시작함을 선언한다.(파일이름 + Application조합이다., spring설정 작동)
@SpringBootApplication
public class DiSampleApplication {
public static void main(String[] args){
SpringApplication.run(DiSampleApplication.class, args)
.getBean(DiSampleApplication.class).execute();
}
//생성된 인스턴스를 이용하고자 하는 사용되는 쪽에 @Autowired를 선언한다.
@Autowired
private Greet g; // 인터페이스 type + 객체 g + DI가 객체생성
// @Component로 지정한 객체를 Greet type의 g객체로 만든다.
private void execute(){
String msg = g.greeting();
System.out.println(msg);
}
}
main함수의 run함수와 getBean, execute()의 의미를 알아보자.
1. SpringApplication.run(DiSampleApplication.class, args)
Spring 애플리케이션을 실행한다는 의미이다.
첫번째 인자 = 어떤 클래스부터 실행할 것인가 설정한다.
두번째 인자 = 메인함수의 args를 그대로 넘겨준다.
2. .getBean(DiSampleApplication.class)
Spring에는 DI컨테이너에서 관리하는 객체를 Bean이라고 한다.
첫번째 인자 = DiSampleApplication이라는 클래스에서 Bean객체를 가져온다.
3. .execute()
가져온 Bean(객체)의 execute()함수를 실행한다.
결과
좋은 아침입니다.

위처럼 객체의 생성 책임을 DI에게 맡김으로써, 사용하는 쪽의 클래스를 전혀 수정하지 않아도, 사용되는 쪽의 클래스만 @Component로 수정하여 변경사항에 대응할 수 있다.
스프링 프레임워크는 DI컨테이너를 자바 객체를 대신생성하는 기능을 가진다. 이런 인스턴스를 DI컨테이너에 보관하며, DI컨테이너 안에서 관리되는 인스턴스를 bean이라고 부른다. @Bean을 사용할 경우 2개이상의 인스턴스를 DI컨테이너에 보관하는 것이 가능하다.
빈 정의란? 이 클래스를 빈으로 만들겠다고 지시하는 것을 의미한다.
빈 정의 방법
1. 클래스에 에너테이션 부여하기.
2. java Config 클래스에 함수 생성하기
1번방법은 @Component와 @Autowired를 이용하는 것이며, 2번방법을 아래에 기술하고자 한다.
1. 인터페이스 생성
public interface BusinessLogic {
void doLogic();
}
2. 기능구현
import com.example.demo.service.BusinessLogic;
public class TestLogicImpl implements BusinessLogic {
@Override
public void doLogic() {
System.out.println("테스트 중입니다.");
}
}
3. 기능구현
import com.example.demo.service.BusinessLogic;
public class SampleLogicImpl implements BusinessLogic {
@Override
public void doLogic(){
System.out.println("샘플입니다.");
}
}
@Configuration은 아래의 클래스가 java Config 클래스임을 지정한다.
@Bean은 DI컨테이너에 들어갈 객체의 이름을 구분할 수 있도록 지정한다.
import com.example.demo.service.BusinessLogic;
import com.example.demo.service.impl.SampleLogicImpl;
import com.example.demo.service.impl.TestLogicImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration// 해당 클래스가 설정 클래스임을 나타낸다.
public class AppConfig {
@Bean(name="test") //함수가 Bean을 반환함을 선언한다.
public BusinessLogic dataLogic(){ // TestLogicImpl을 test라는 이름의
빈으로 등록하여 컨테이너에 넣는다.
return new TestLogicImpl();
}
@Bean(name = "sample") //sample이라는 빈이름으로, DI컨테이너에 SampleLogicImpl을 등록한다.
public BusinessLogic viewLogic() {
return new SampleLogicImpl();
}
}
@Autowired는 객체를 주입할 곳을 지정한다.
@Qualifier는 @Bean으로 지정한 이름의 Bean을 DI컨테이너로 부터 불러와서 객체를 생성한다.
import com.example.demo.service.BusinessLogic;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class JavaConfigSampleApplication {
public static void main(String[] args){
SpringApplication.run(JavaConfigSampleApplication.class, args)
.getBean(JavaConfigSampleApplication.class).exe();
}
@Autowired
@Qualifier("test") //빈의 이름을 불러온다.
private BusinessLogic business1; // business1객체가 생성
@Autowired
@Qualifier("sample")
private BusinessLogic business2;
public void exe(){
business1.doLogic();
business2.doLogic();
}
}
결과
테스트 중입니다.
샘플입니다.
객체 주입은 @Autowired를 통해 이루어진다. 이런 주입방법은 3가지로 이루어진다.
@Autowired
private SomeService someService;
private SomeService someService;
@Autowired
public setSomeService(SomeService someService){
this.somService = someService;
private final SomeService someService; //객체에 불변성 주입
@Autowired //생략가능
public setSomeService(SomeService someService){
this.somService = someService;
1. 인터페이스
public interface Example {
void run();
}
@Component
public class FieldInjectionExample implements Example {
//변수(필드) 주입
@Autowired
private SomeService someService;
@Override
public void run() {
someService.doService();
}
}
객체 위에 @Autowired를 사용함으로써, 객체변수에 주입한다.
//@Component
public class SetterInjectionExample implements Example {
private SomeService someService;
//Setter 주입
@Autowired
public void setSomeService(SomeService someService){
this.someService = someService;
}
public void run() {
someService.doService();
}
}
setter함수 위에 @Autowired를 사용하여, 객체를 주입시킨다.
//@Component
public class ConstructorInjectionExample implements Example {
private final SomeService someService;
@Autowired
public ConstructorInjectionExample(SomeService someService){
this.someService = someService;
}
public void run() {
someService.doService();
}
}
생성자를 통해 객체를 주입한다. 이 때 객체선언시 final을 사용해준다.
@RequiredArgsConstructor
public class ConstructOrInjectionOmitLombokExample implements Example {
private final SomeService someService;
// 생성자 생략가능
public void run() {
someService.doService();
}
}
@RequiredArgsConstructor 는 롬복이 자동으로 final이 붙은 필드만 인수로 받는 생성자를 생성해준다.
@SpringBootApplication
class InjectionSampleApplication {
public static void main(String[] args) {
SpringApplication.run(InjectionSampleApplication.class, args)
.getBean(InjectionSampleApplication.class).exe();
}
@Autowired
private Example example;
private void exe(){
example.run();
}
}
결과
어떤 서비스