[Spring] DI

betty214·2022년 2월 17일
0

CS

목록 보기
20/21

CS 공부 17일차. 오늘은 Spring의 중요 개념 중 하나인 DI가 실제로 어떻게 적용되는지를 위주로 토비의 스프링 3.1을 읽고 내용을 정리해 보았습니다.

DI란?

  • Bean Object 사이의 관계를 주입
  • Bean외의 Object나 단순 값을 주입

@로 DI하기 위해 필요한 것

<context : annotation-config/>
  • @Resource와 같은 애노테이션 의존관계 정보를 읽어서 메타정보를 추가해주는 기능을 가진 빈 후처리기를 등록해주는 전용 태그
<context : component-scan/>
  • annotation-config로 만들어지는 빈을 함께 등록해주며, 빈 스캐닝을 통한 빈 등록방법을 지정하는 전용 태그

  • AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext : 빈 스캐너와 애노테이션 의존관계 정보를 읽는 후처리기를 내장한 ApplicationContext

Bean 의존관계 설정

  • Bean 등록방법과 Bean 의존관계 설정 방법은 같지 않아도 된다.

  • DI할 Bean의 id 직접 지정

  • Autowiring : 명시적으로 프로퍼티나 생성자 파라미터를 지정하지 않고 미리 정해진 규칙을 이용해 자동으로 DI 설정을 Container가 추가하도록 만드는 것이다.

수정자 주입

<bean>
	<property name=“sample” ref=“sample” />
	<property name=“age” value=“30” />
</bean>
  • value에 넣을 수 있는 값의 타입에는 제한이 없으며 타입에 맞게 자동 변환해준다. (Ex: “30”-> 30)

생성자 주입

  • XML 자동 와이어링 : XML의 양을 줄일 수 있어 편리하나, 코드만 봐서는 어떤 DI가 일어나는지 알기 어렵고 하나의 빈에 대해서 한가지 방식으로 밖에 지정이 안되는 단점이 있다.
<constructor-arg type=“java.lang.String” value=“Spring” />
<constructor-arg type=“springbook.learningtest.spring.ioc.bean.Printer” ref=“printer” />

  1. byName : property이름과 DI할 bean의 이름이 같은 관례를 이용하는 방법.
<bean id=“hello” class=“springbook.learningtest.spring.ioc.bean.Hello" autowire=“byName">
	//<property name=“sample” ref=“sample” />는 자동으로 추가됨
	<property name=“age” value=30/>
</bean>
  • Hello 클래스의 프로퍼티의 이름과 동일한 빈을 찾아서 자동으로 프로퍼티로 등록해준다.
<beans default-autowire=“byName”>
	<bean>...</bean>
...
</beans>
  • 위와 같이 한번에 해도 된다.

  1. byType: byName과 동일한 방식으로 byType을 넣어주면 적용된다. 빈의 이름에 신경쓰지 않아도 되어서 편리하나 타입이 같은 빈이 두 개 이상 존재하는 경우 적용되지 못하는 단점이 있다. 또한 byName보다 느리다.

@Resource

  • byName autowire

  • 수정자(setter) 메소드

@Resource(name=“sample”)
public void setSample(Sample sample){
	this.sample=sample;
}
  • 필드
@Resource(name=“sample”)
private Sample sample;
  • 필드 주입이라고 한다.

  • setter를 만들면 단위테스트에 편리하고 통합테스트에는 setter없이 필드주입만 사용해도 괜찮다.(ex : DAO에 DataSource를 DI하는 경우)

  • 필드와 setter모두 name 생략 가능

  • XML의 Autowiring과 @Resource는 XML은 해당하는 빈이 없으면 무시하고 넘어가지만 @Resource는 예외를 발생시키는 차이점이 있다.

@Autowired

  • byType autowire

  • @Autowired는 스프링 전용이며 이와 유사한 @Inject는 다른 Java 프레임워크에서도 사용 가능

  • @Autowired는 XML byType Autowired를 생성자, 필드, 수정자 메소드, 일반 메소드로 확장한 것이다.

  • 가장 유연하면서 강력한 기능을 가진 DI 설정 방법

  • 테스트 클래스의 Object에 @을 이용한 의존관계 설정을 해준다.

  • 필드

@Autowired
private ClassService classService;
  • @Resource와 다른 점은 이름 대신 필드나 프로퍼티 타입을 이용해 후보 빈을 찾는 다는 것이다.

  • 수정자 메소드

@Autowired
public ClassController(ClassService classService) {
	this.classService=classService;
}
  • 생성자
@Autowired
Collection<ClassService> classService;

@Qualifier

  • 타입 외의 정보를 추가해서 자동와이어링을 세밀하게 제어할 수 있는 보조적인 방법

  • 두가지 DB를 사용하는 경우에 두 빈이 모두 DataSource이므로 오류가 나면 아래와 같이 해결한다.

  • 필드, 수정자 메소드, 파라미터에 부여할 수 있으며 생성자와 일반 메소드에 부여하는 것은 의미가 없다.

@Autowired
@Qualifier(“mainDB”)
DataSource dataSource;

<bean id=“oracleDataSource” class=“aDataSource">
	<qualifier value=“mainDB”/>
</bean>
@Autowired
@mainDB
public class OracleDataSource{
...
}

@Configuration+@Bean

  • 메소드로 정의된 다른 빈을 메소드 호출을 통해 참조

  • @Configuration + @Bean로 빈을 생성했을 경우 DI 설정

@Autowired/@Resource
public class Hello{
	@Autowired Printer printer;
}

@Configuration
public class Config{
	@Bean public Hello hello(){
		return new Hello();
	}
	@Bean public Printer printer(){
		return new Printer();
	}
}

//@Autowired가 후처리기로 진행되기 때문에 config에는 bean만 등록해주어도 된다.
  • @Bean 메소드 호출
@Configuration
public class Config {
 @Bean public Hello hello(){
	Hello hello = new Hello();
	hello.setPrinter(printer());
	return hello;
}
@Bean public Printer printer(){
	return new Printer();
}
//직관적. 싱글톤으로 printer가 만들어짐. printer메소드를 직접 실행시켜 DI
  • @Bean과 메소드 자동와이어링
@Configuration
public class Config {
 @Bean public Hello hello(Printer printer){
	Hello hello = new Hello();
	hello.setPrinter(printer);
	return hello;
}
@Bean public Printer printer(){
	return new Printer();
}
//printer()에 의해 Printer 빈이 선언되었으며 이를 파라미터로 지정하여 DI

값 DI 방법

  • property
<bean id=“hello”>
	<property name=“name” value=“Everyone” />
</bean>
  • 전용 태그
<aop:advisor advice-ref=“ref” pointcut=“bean(*Service)” />
  • @Value
@Value({database.username})
private String username;

@Bean
public Hello hello(){
	Hello hello = new Hello();
	hello.setName(this.name);
	return hello;
}
//런타임 시에 외부로부터 주입을 통한 초기화가 존재.

타입 변환

  • PropertyEditor : 자바에서 제공하는 타입 변환기로 기본타입, 오브젝트 타입, 배열등을 변환해준다.

  • ConversionService : Spring에서 제공하는 타입 변환기로 멀티 레드 환경에서 공유해 사용할 수 있으며 propertyEditor보다 작성이 간편하다.

컬렉션

<property name=“names”>
	<list>
		<value>Spring</value>
		<value>IoC</value>
		<value>DI</value>
	</list>
</property>

<property name=“ages”>
	<map>
		<entry key=“Kim” value=“30” />
		<entry key=“Lee” value=“25” />
		<entry key=“Park” value=“20” />
	</map>
</property>

<property name=“ages”>
	<props>
		<prop key=“id”>Spring</prop>
		<prop key=“pw”>Book</prop>
	</props>
</property>

프로퍼티

  • XML에서 일부 설정정보(ex: dataSource)를 파일로 분리하여 프로퍼티 값으로 지정

  • 로컬과 호스팅같이 서버환경이 다를때 다르게 적용해야하는 정보를 분리

  • @Vaule나 value attribute가 프로퍼티 파일을 참조하게 하면 효과적이다.

  1. 수동 변환(PropertyPlaceHolderConfiguerer)
<context:property-placeholder location=“class path:database.properties” />
<property name =“username” value=${db.username} />
@Value(“${db.username}) 
String username;
  • 빈 팩토리 후처리기가 빈 메타정보의 프로퍼티 값 정보에서 db.username을 찾아 변경해준다.
  1. 능동 변환(SpEL : Spring Extension Language)
<bean id=“user”>
	<property name = “name” value=“Spring">
</bean>
<bean id=“names">
	<property name =“username” value=“#{user.name}" />
</bean>
@Component(“user”)
public class User{
	private String name=Spring;
	public String getName(){
		return name;
	}
	public void setName(String name){
		this.name=name;
	}
}

@Value(“#{user.name})
private String username;
  • 에러 검증이 가능하며 빈 후처리기가 프로퍼티 파일에서 값을 찾아서 변경해주기를 기다리지 않고 직접 빈 오브젝트에 접근하여 프로퍼티를 가져오는 방식

컨테이너가 자동등록하는 빈

  • ApplicationContext
  • BeanFactory
  • ResourceLoader
  • ApplicationEventPublisher
  • systmeProperties
  • systemEnvironment
profile
천체관측이 취미

0개의 댓글