Bean 을 문자열로 출력한다면?
전략 패턴은 인터페이스를 사용해, 추상클래스를 사용한 상속은 아니지만, 마치 상속을 한 것과 비슷한 분리를 만들어내는 디자인 패턴이다.
클래스 다이어그램으로 그려졌듯이, Output
이라는 인터페이스를 구현한 FileOutput
과 ConsoleOutput
이라는 구현체가 있고,
MessageBean
이라는 인터페이스를 구현한 MessageBeanImpl
이라는 구현체가 있다.
MessageBeanImpl
구현체 내에는 Output 인터페이스를 인스턴스 필드로 받는데, 이 필드 데이터로 FileOutput
혹은 ConsoleOutput
구현체를 bean 으로 생성한 객체가 주입된다.
bean에 String 이 아닌 객체를 주입할 때에는
이 때, super() 와 같은 형식으로
하나의 클래스 내에서 인스턴스 필드로 또다른 객체를 받을 수도 있다.
그런데, 이렇게 xml 파일로 bean 들을 관리하다보면, 프로젝트의 크기가 커질수록 입력해야 할 내용들도 많아지고 번거로워 진다.
특히 c:employee-ref="bean_id" 와 같이, bean으로 생성된 객체를 주입할 경우
자동적으로 주입할 수 있도록 하는 속성이 존재한다.
그것이 바로 autowired
이다.
자동주입(자동으로 의존 객체
를 주입하는 기능) 기능이다.
명시적인 언급 없이도 Bean이 주입될 수 있다.
XML : 의존관계를 파악하는 것이 용이하지만, 프로젝트의 사이즈가 커질수록 양이 너무 많아지기 때문에 관리가 어려워진다.
그래서 이를 개선하기 위해 등장한 방식이 Auto-Wireing 방식이다.
Auto-Wireing
에는 3가지
방식이 있다.
<bean autowire="byName" />
autowire 속성 추가 시, bean의 식별자(bean의 id)를 가지고 주입하게 된다.
만약 TestBean 이라는 클래스 내부에 setData1()
이 존재하지 않거나 혹은 setData3()
이라는 setter 가 있는데 xml 내부의 bean id
가 data1
이라는 등, setter의 name 과 주입할 bean 의 id 가 일치하지 않는다면, autowire 로 주입이 이루어지지 않는다.
그렇다면 testBean 의 instance field 이름을 기준으로 찾는 것일까, 아니면 setter 의 인자 이름을 기준으로 찾는 것일까?
=> bean 의 Id와 instance field 의 식별자 이름이 일치한다면, 자동 주입이 된다.
<bean autowire="byType" />
bean 의 클래스 타입을 가지고 주입하게 된다.
로그를 보면 동일한 getData1() 과 getData2() 를 통해 출력되는 객체 data1 과 data2 가 동일한 객체(primary=true
속성이 부여된 data1 bean
객체 ) 임을 알 수 있다.
<xml>
태그의 속성 안에 default-autowire를 통해 모든 bean 주입에 대해 자동 주입을 설정할 수 있다.
만약 이 설정을 한 뒤, 자동 주입을 하지 않을 bean 이 있다면
authwire="no"
속성을 입력하면 된다.
@Autowired
private Object obj;
어노테이션을 가지고 주입할 때에는 내부적으로 "byType" 방식으로 주입한다.
@Component
라는 어노테이션을 클래스에 입력하게 되면, 해당 클래스 자체를 bean 으로 등록한다.
이 클래스에 대한 정보에 applicationContext 에 저장되는 것이다. 이 클래스를 기반으로 bean 객체가 생성되어 주입된다.
@Component
로 bean 이 등록된다면, xml 파일에서 bean을 생성할 때 입력해야 했던 bean 의 id 값은 자동적으로 클래스의 이름으로 잡히게 된다. 카멜케이스에 의거해 첫글자는 소문자로!
혹은 @Component("id값 입력")
을 통해 id 값을 지정해줄 수도 있다.
Annotaion 설정을 이용하기 위해서는, XML에 특별한 code 를 넣어야 한다. 즉 xml 내부에 설정은 annotaion 으로 하겠다는 선언을 해주는 코드가 필요하다는 의미이다.
자동으로 의존관계를 맺을 때 사용하는 annotation 이다.
사용이 가능한 케이스는 3가지가 있다.
특정 필드에 붙일 수 있다.(가장 자주 쓰이는 방식)
constructor 에 붙일 수 있다.
method 에 붙일 수 있다.
(일반적으로 setter 를 지칭하는데, 일반 method 에도 붙일 수는 있지만 자주 쓰이지는 않는다.)
@Autowired 로 주입하는 방식은 내부적으로 byType
형태로 이루어진다.
만약 같은 데이터 타입이 두 개 이상 bean 이 있으면 field 명
에 일치하는 것이 있는지, 혹은 method 의 parameter 이름
으로 일치하는 것이 있는지 확인한 후 주입을 하게 되는데, 이 과정을 거쳐서도 없다면 error 를 낸다.
byType
에 의해 Food 타입의 bean 객체를 1차적으로 검색
그러나 아래의 xml 파일에서 보면 Food 타입의 bean 객체는 두 개 존재한다.(favoriteFood, unFavoriteFood)
그래서 2차적으로 bean 객체의 id
와 현재 자동 주입하려는 필드의 식별자
를 비교해서 매칭되는 게 존재한다면 그 bean 객체를 주입한다.
context:component-scan base-package="package 주소"
를 통해 @Component
라는 어노테이션이 사용되는 지를 검사할 패키지를 입력해준다.
field 에 autowired 가 붙었다면
1) bean 클래스 타입 == field 의 데이터 타입
2) bean 의 id == field 의 식별자 이름
일반 메소드에 autowired 가 붙었다면
bean 의 id == 메소드가 받는 파라미터의 이름
주의해야 할 점은 intelliJ 에 의해 자동완성으로 schema 를 추가하다보면 p 나 c 를 추가할 경우에는 큰 문제가 발생하지 않았지만 context 를 추가할 때에는 schemaLocation 에도 context 관련 내용을 추가해주어야 한다.
안그럴 경우 아래와 같은 error 를 내뱉는다.
📌 @Autowired(required=false) : 원래 bean에 객체를 자동 주입하는 것이 Autowired 이고, 주입할 bean 객체가 없다면 error 를 내는 것이 기본 값인데
required=false
라는 속성을 통해 만약 bean 객체가 없더라도 정상적으로 생성을 할 수 있도록 한다.
필드에 Autowired 를 걸어놓을 경우, 자동 주입을 할 때 setter 를 이용하지 않고 그대로 주입이 이루어진다. 즉 setter 를 거치지 않고 주입이 이루어진다.
birth 가 bean 으로 등록되어 있지 않을 경우 autowired 는 error 를 낸다.
하지만 autowired(required=false) 설정을 해준다면
birth 는 null 값으로 반환이 이루어진다.(즉 error 가 나지는 않는다.)
생성자는 여러 종류를 오버로딩 할 수 있지만, autowired 어노테이션은 오직 하나의 생성자에만 사용할 수 있다.
@Component 를 통해 빈 객체가 생성될 때에는 default 값으로 기본 생성자를 통해 생성이 되고, @Autowired 어노테이션이 붙은 생성자가 있다면 해당 생성자를 통해 빈 객체를 생성한다. 다만 이 경우, parameter 로 받게 되는 객체 역시 빈 객체로 등록되어 있어야 한다.
emp 를 parameter 로 받는 생성자를 autowired 어노테이션을 사용하자, 기본 생성자가 아니라 어노테이션이 붙은 생성자로 빈 객체가 생성되었다.
주의할 점으로 생성자에는 @Autuwired(required=false) 는 적용되지 않는다.
생성자의 parameter 로 들어오는 객체가 autowired 가 불가능할 경우 ( bean 객체로 등록이 안되어 있을 경우 )
오류가 발생한다.
즉, autowired 어노테이션이 붙은 생성자의 parameter 로 들어오는 객체는 bean 객체로 등록이 되어 있어야만 한다.
기본 생성자로 빈 객체를 생성 한 후 autowired 어노테이션이 설정된 인스턴스 필드와 맞는 타입/name 의 빈 객체를 찾아 객체를 주입한다.
다만 그 과정에서 setter 메소드를 거치는 것이 아니다.
@Autowired 어노테이션과 같이 사용되는 어노테이션이다.
Bean 을 이름을 이용해 주입할 때 사용한다.
@Autowired와 기능은 동일하다. 자동 주입을 해주는 것.
차이점은 @authwired
는 byType
으로 주입하지만
@Resource
의 경우에는 byName
을 이용해 자동 주입이 이루어진다.
Bean 의 scope 를 지정해주는 어노테이션.
위치는 @Component 아래, 즉 class 단위로 사용이 이루어진다.
기본값은 singleton 이고, prototype 으로 명시하게 되면 Bean 객체가 요청에 따라 생성이 이루어진다.