11 알아두면 유용한 스프링 활용법

개발 99·2025년 4월 27일

11.1 타입 기반 주입

@Autowired 애너테이션을 이용한 의존성 주입은 타입을 기반으로 동작을 한다.
(의존성 주입이 필요한 경우 스프링 컨테이너는 타입을 기반으로 Bean을 찾는다.)

만약 찾지 못할 경우, NoSuchBeanDefinitionException 에러 발생

@Service
@RequiredArgsConstructor
public class NotificationService{
	private final NotificationChannel notificationChannel;
}
public interface NotificationChannel {
	void notify(Account account, String message);
}
@Component
public class EmailNotificationChannel implements NotificationChannel {
	
    @Override
    public void notify(Account account, String message){...}
}

NotificationService 컴포넌트의 멤버 변수 notificationChannel에는 EmailNotification Channel 빈이 들어간다.
(타입 기반으로 Bean을 찾기 때문이다.)

만약 이 추상 타입을 상속하거나 구현하는 빈이 여러 개라면?

어떤 빈을 주입할지 몰라서, NoUniqueBeanDefinitionException 에러를 발생한다.
따라서 @Qualifier나 @Primary 어노테이션을 사용한다.

추상 타입이 존재하고 이를 상속하거나 구현한 빈이 여러개라 가정시, 이때 주입받으려는 변수가 List<추상타입>이라면 뭘 넣지???

@Service
@RequiredArgsConstructor
public class NotificationService{
	private final List<NotificationChannel> notificationChannels;
}

타입과 일치하는 모든 스프링 빈을 찾아 List의 요소로 넣어주는 방식으로 처리를 한다.

@Service
@RequiredArgsConstructor
public class NotificationService{
	private final EmailNotificationChannel emailNotificationChannel;
    ...
    
    public void notify(Account account, String message){
    	switch(account.getNotificationType()){
        	case EMAIL:
            	...
            case SLACK:
            	...
            case CHAT:
            	...
                
            ...
            // 이런식의 Switch - Case는 OCP를 위반한다.
            // 새로운 필드가 추가될 때마다 case가 늘어난다.
            
        }
    }
}

위 코드를 switch가 아닌 for문으로 하자!

@Service
public class NotificationService{
	
    private final List<NotificationChannel> notificationChannels;
    
    public void notify(Account account, String message){
    	for(NotificationChannel notificationChannel : notificationChannels){
        	...
        }
    }
}
public interface Notification{
	...
}

EmailNotificationChannel, SlackNotificationChannel, ChatlNotificationChannel 모두 Notification을 구현한다.
(그러면 알아서 List NotificaitonChannel에 들어간다.)

11.2 자가 호출

어떤 객체가 메소드를 처리하는 와중에 자신이 갖고 있는 다른 메소드를 호출하는 상황을 의미한다.


class Something {
	public void doSomething1(){
    	doSomething2();
    }
    
    public void doSomething2(){...}
}

스프링의 빈 메소드에서 발생하는 자가 호출은 개발자의 의도와 다르게 작동할 수 있다.
특히 AOP 어노테이션에서 문제가 된다.

@Service
@RequiredArgsConstructor
class MyService{
	public void doSomething1(){
    	doSomething2();
    }
    
    @Transactional
    public void doSomething2(){
    	// do Something...
    }
    
}

자가 호출이 발생하면 호출된 메소드에 적용된 AOP 어노테이션이 동작하지 않을 수 있으므로
트랜잭션이 제대로 동작하지 않을 수 있다.

왜냐하면 AOP는 프록시를 기반으로 동작하기 때문이다.
MyController -> MyServiceProxy -> MyService 구조임.
따라서, 자가 호출로 트랜잭션을 실행시킬 수 없다.

profile
구구구구구!

0개의 댓글