기록/Spring framework

@Autowired의 스프링 빈 필수여부( null 값 전달.), 의존 자동주입과 수동주입의 우선순위. 2021-11-18

최동훈1 2021. 11. 18. 17:51

 그런데 앞서 클래스에서 @Autowired로 주입하려는 객체가 스프링 컨테이너에 빈으로 등록되어 있지 않을 경우, 어떤 일이 일어날까? 

우선 익셉션이 바로 난다.

 우선 예시를 보여주기 위해서 가상의 FakeAutowired 클래스를 빈으로 등록하고, @Autowired를 통해 빈 설정클래스에 등록되어있지 않은 P라는 클래스를 맴버로 설정하였다.

public class FakeAutowired {

	private practice p;
    //빈 에 등록되어있지 않은 객체 P.

	public FakeAutowired() {
		// TODO Auto-generated constructor stub
	}

	@Autowired
	public void setP(practice p) {
		this.p = p;
	}

	public void printP() {
		if (this.p == null) {
			System.out.println("현재 P의 값은 null 입니다.");
		} else {
			System.out.println("현재 P의 값은 Null 값이 아닙니다.");
		}
	}
}

 

스프링 설정 클래스에서 FakeAutowired를 빈으로 설정함.

@Configuration
public class AppCtx2 {
	
	
	@Bean
	public MemberPrinter printer() {
		MemberPrinter printer=new MemberPrinter();
		//printer.setMemberDao(memberdao);
		
		return printer;
	}
	@Bean
	public FakeAutowired fake() {
		FakeAutowired fake=new FakeAutowired();
		return fake;
	}
	
}

세터메서드를 @Autowired를 통해 practice 클래스를 자동주입 하기 때문에 굳이 쓰지 않았다.

이렇게 @Autowired를 통해 빈에 등록되어있지 않은 객체를 자동주입 하려고 컴파일 하면 오류가 난다.

 

 Error creating bean with name 'fake': Unsatisfied dependency expressed through method 'setP' parameter 0; 

 

그렇다면, 이렇게 익셉션이 컴파일 단계에서 나오지 않으면서, 만약 @Autowired를통해 주입하려는 빈 타입과 일치하는 빈이 스프링 컨테이너에 존재하지 않을경우, 그대로 진행시키는 방법은 없을까?

 

총 3가지의 방법이 있는데,

첫번째는, @Autowired(required = false) 방법은 일치하는 빈이 없을 경우 @Autowired가 붙은 메서드나 필드 자체를 수행하지 않는다(자동의존주입, 호출 하지 않는다.) 예시를 보이겠다.

public class FakeAutowired {

	private practice p;

	public FakeAutowired() {
		// TODO Auto-generated constructor stub
		p=new practice();
			
	}
	@Autowired(required = false)
	
	public void setP( practice p) {
		this.p = p;
	}

	public void printP() {
		if (this.p == null) {
			System.out.println("현재 P의 값은 null 입니다.");
		} else {
			System.out.println("현재 P의 값은 Null 값이 아닙니다.");
		}
	}
}

만약 일치하는 practice 객체가 없으면, 기본적으로 생성자에서 만들어진 기본 p 객체를 사용한다.(null 전달 x). 또한 세터 메서드 자체를 호출하지 않는다.

생성자에서 만들어진 practice 클래스를 그대로 넣어짐.

 

두번째는, 의존자동주입 하려는 필드나 메서드의 타입으로 Optinal을 사용한 경우이다.(JAVA 8버전부터 가능) 

이 경우 의존자동주입하려는 빈과 일치하는 타입이 없는경우, 값이 없는 Optional을 인자로 전달한다.

 

 

세번째는, @Autowired 애너테이션 밑에 @Nullable 애너테이션을 사용하는 것이다.

그렇다면 일치하는 빈이 없는경우, Null을 인자로 전달한다. 예시를 보이겠다.

 

public class FakeAutowired {

	private practice p;

	public FakeAutowired() {
		// TODO Auto-generated constructor stub
         p=new practice();
	}

	@Autowired
	
	public void setP(@Nullable practice p) {
		this.p = p;
	}
    //의존주입할 파라미터 바로 앞에 @Nullable 애너테이션을 전달.

	public void printP() {
		if (this.p == null) {
			System.out.println("현재 P의 값은 null 입니다.");
		} else {
			System.out.println("현재 P의 값은 Null 값이 아닙니다.");
		}
	}
}

이렇게 한다면, 만약 practice 타입의 빈이 없더라도 에러를 내지 않고 Null 값을 인자로 전달한다.

null값전달.

 

또한 의존 자동주입이랑 세터 메서드, 생성자 주입방식을 통한 수동주입 방식중 무엇이 더 우선되는 가가 중요한데 

 

의존자동주입 >> 수동 DI(생성자, 세터메서드 방식) 이다. 즉, 의존자동주입을 통한 DI 객체가 더 우선적으로 적용된다. (비록 설정 클래스에서 수동으로 또다른 객체를 DI 했더라도)

 

그래서 자동주입을 하는 코드와 수동으로 주입하는 코드가 섞여 있으면 주입을 제대로 하지 않아서 Nullpointer익셉션이 발생했을때, 오류를 찾기 어렵기때문에, 자동 DI를 사용한다면 일관되게 사용해야 한다.

 

공부시간 1시간.

순공부시간 40분.

 

오늘은 그래도 어제 정리 못끝낸 포스팅을 마무리 할 수 있어서 좋았다. 공부 열심히 해서 좋고 안정적인 직장에 꼭 가고 싶다.

최종수정 : 2021-11-19