[Spring] 빈을 설정하는 3가지 방법 - XML, JAVA, Component Scan

Summary

1. 고전적인 방법 - Spring Bean XML 설정 파일
2. JAVA 설정 파일의 사용
3. JAVA 설정 파일 + Component Scan

 


 

고전적인 방법 - Spring Bean XML 설정 파일

resources 폴더에 'application.xml' 이름으로 Spring Config XML 파일을 만든다.

 

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="testService" class="com.test.mong.TestService"/>
 
	<bean id="testRepository" class="com.test.mong.TestRepository"/>
    
</beans>

<bean>에 빈을 등록 해주면 된다. id, class 속성은 필수 속성이다.

id에 빈의 id를, class에 빈으로 등록 할 클래스의 패키지명 포함 전체 이름을 넣어준다.


여기까지 설정한 내용은 TestService와 TestRepository를 빈으로 만들라는 것이다.

 

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
	<bean id="testService" class="com.test.mong.TestService">
		<property name="testRepository" ref="testRepository" />
	</bean>
 
	<bean id="testRepository" class="com.test.mong.TestRepository" />
    
</beans>

빈 주입은 주입받을 빈의 <bean> 태그 하위에 <property> 태그를 이용해서 설정하면 된다.

<property>의 name 속성에 프로퍼티(setter) 이름을, ref속성에는 주입할 빈의 id를 지정한다.

등록한 빈은 ApplicationContext를 통해 사용할 수 있다.

 

TestApplication.java

public class TestApplication {
	public static void main(String[] args) {
		
		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
		String[] beanDefinitionNames = context.getBeanDefinitionNames();
		System.out.println(Arrays.toString(beanDefinitionNames));

	}
}

----------------------------------------------------------------------------------------
[testService, testRepository]

ClassPathXmlApplicationContext()에 application.xml 파일을 넘겨 ApplicationContext를 생성한다.

ApplicationContext의 getBeanDefinitionNames()는 IoC 컨테이너에 등록된 빈의 id 목록을 가져온다.

ApplicationContext의 getBean()으로 빈을 꺼낼 수 있다. String 타입 파라미터에 빈의 id를 넘긴다. (testService, testRepository)

 

TestApplication.java

public class TestApplication {

	public static void main(String[] args) {
		
		ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
		String[] beanDefinitionNames = context.getBeanDefinitionNames();
		System.out.println(Arrays.toString(beanDefinitionNames));

		TestService testService = (TestService) context.getBean("testService");
		System.out.println(testService.testRepository != null);

	}

}

----------------------------------------------------------------------------------------
[testService, testRepository]
true

위에 작성한 xml 설정 파일에 의해 TestService 가 testRepositry 빈을 주입받은 것이다.

이 방법은 모든 빈을 <bean>으로 일일이 등록해줘야 해서 굉장히 번거롭다.

그래서 다음으로 등장한 것이 component scan이다. application.xml을 다음과 같이 설정한다.

 

application.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
 
	<context:component-scan base-package="com.test.mong"/>
 
</beans>

위 설정은 base-package에 지정한 패키지에서부터 모든 하위 패키지를 scanning해서 빈으로 등록 한다.

당연히 모든 클래스를 빈으로 등록하는 건 아니고 @Component 어노테이션이 붙은 클래스를 빈으로 등록한다.

@Component를 확장한 몇가지 어노테이션이 더 있는데 그중 @Service, @Repository, @Controller가 있다.

이러한 @Component를 확장한 어노테이션을 사용해도 마찬가지로 빈으로 등록된다.

 

TestService.java

@Service
public class TestService {
	
	TestRepository testRepository;

	public void setTestRepository(TestRepository testRepository) {
		this.testRepository = testRepository;
	}

}

TestRepository.java

@Repository
public class TestRepository {

}

이렇게 TestService 와 TestRepository 클래스에 각각 @Service, @Repository 어노테이션을 붙여준다.

그러면 두 클래스가 component-scan에 의해 빈으로 등록된다.

의존성 주입은 @Autowired 어노테이션을 사용한다.

 

TestService.java

@Service
public class TestService {

	@Autowired
	TestRepository testRepository;

	public void setTestRepository(TestRepository testRepository) {
		this.testRepository = testRepository;
	}

}

TestService.java의 TestRepository 변수에 @Autowired를 붙여주자.

이제 빈 등록과 의존성 주입을 위한 설정이 모두 완료되었다.

main()을 실행해보면 이전과 동일한 결과가 나온다.

 

application.xml 에 일일이 설정하는 대신 어노테이션을 scanning해서 빈을 등록하고 의존성 주입하도록 변경한 것이다.

★ 어노테이션 기반의 빈 등록 및 설정은 spring 2.5부터 추가되었다.

 

JAVA 설정 파일의 사용

위에서 작성한 application.xml 과 같은 XML 파일이 아닌 java로도 설정파일을 만들 수 있다.

 

ApplicationConfig.java

@Configureation
public class ApplicationConfig {
	
	@Bean
	public TestRepository testRepository() {
		return new TestRepository();
	}

	@bean
	public TestService testService() {
		TestService testService = new TestService();
		testService.setTestRepository(testRepository());
		return testService;
	}

}

Java 설정 파일을 만들려면 @Configuration을 붙여주고 빈으로 등록할 객체를 리턴하는 메소드를 정의한다.

메소드명이 빈 id, 리턴 타입이 빈 타입, 리턴한 객체가 빈 레퍼런스가 된다.

의존성은 직접 setter를 호출해서 주입해준다.

 

TestApplication.java

public class TestApplication {

	public static void main(String[] args) {

		ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
		String[] beanDefinitionNames = context.getBeanDefinitionNames();
		System.out.println(Arrays.toString(beanDefinitionNames));

		TestService testService = (TestService) context.getBean("testService");
		System.out.println(testService.testRepository != null);

	}

}

Java로 만든 설정 파일은 AnnotationConfigApplicationContext()에 class를 넘겨서 사용할 수 잇다.

★ AnnotationConfigApplicationContext란?
어노테이션 기반의 빈 config를 사용하는 ApplicationContext 구현체이다.

기존에 붙어있던 @Service, @Repository, @Autowired를 삭제하고 실행해보자.

역시 실행 결과는 동일하다.

Java설정 파일에서 직접 setter를 호출하지 않고 @Autowired를 붙여서 의존성을 주입해주는 것도 가능하다.

 

ApplicationConfig.java

@Configuration
public class ApplicationConfig {

	@Bean
	public TestRepository testRepository() {
		return new TestRepository();
	}

	@Bean
	public TestService testService() {
		return new TestService();
	}

}

TestService.java

public class TestService {

	@Autowired
	TestRepository testRepository;

	public void setTestRepository(TestRepository testRepository) {
		this.testRepository = testRepository;
	}

}

Java 설정 파일에서 직접 setter를 호출해서 의존 관계를 엮어주지 않아도 @Autowired 어노테이션을 붙여주면 의존성 주입이 된다.

 

JAVA 설정 파일 + Component Scan

위 방법은 XML 설정 파일에서 component scan을 사용하도록 설정하는 것보다 더 번거롭다.

그래서 Java 설정 파일에서도 component scan을 사용할 수 잇다.

 

ApplicationConfig.java

@Configuration
//@ComponentScan(basePackages = "io.mong")
@ComponentScan(basePackageClasses = ApplicationConfig.class) // 더 type safe한 방법
public class ApplicationConfig {

}

Java 설정 파일 클래스에 @ComponentScan 어노테이션을 붙인다.

Scan을 시작하는 패키지를 지정하는 방법으로 basePackages와 basePackagesClasses의 두 가지 속성을 사용할 수 있는데 basePackages에는 패키지 이름을 문자열로, basePackagesClasses에는 scan을 시작할 위치의 클래스를 지정한다.

 

basePackagesClasses가 더 type safe한 방법이다.

 

이렇게 설정해주면 XML 설정 파일에서 <context:component-scan...>을 설정한 것과 동일하게 동작한다.

이렇게 Java 설정 파일에 @ComponentScan 어노테이션을 붙여서 설정하는 것이 spring boot 기반에서 사용하는 방법과 가장 가까운 방법이다.

역시 실행 결과는 동일하다.

★ 지금까지 ApplicationContext를 직접 만들었는데 Spring은 ApplicationContext를 알아서 만들어준다.
또한 Java 설정 파일로 만들었던 ApplicationConfig.java 같은 파일도 Spring boot를 사용하면 따로 생성 할 필요가 없다.

 

 

댓글(0)

Designed by JB FACTORY