반응형
Spring - Java Based Configuration
(원문 위치 : http://www.tutorialspoint.com/spring/spring_java_based_configuration.htm )
지금까지 XML설정파일을 사용하여 어떻게 Spring bean을 설정하는지 알아보았다. 만약 XML 설정으로 충분하다면, 어떤것을 사용하더라도 동일한 결과이기 때문에 Java기반 설정으로 처리하는 방법이 필요없을 수 있다.(하지만, 국내에서 순수하게 처음부터 프로젝트를 올려가지 않는 이상, 기구축된 시스템 기반으로 혹은 기존 시스템을 참고하여 개발하는 경우가 상당할 것이다. 따라서 보고 어떻게 돌아가는지는 파악할 수 있도록 해 놓아야 한다고 생각한다.)
Java 기반 설정옵션은 XML없이 대부분의 spring설정을 가능하게 한다. 몇가지 java기반 annotation을 아래에 설명한다.
@Configuration & @Bean Annotations:
@Configuration를 가진class를 선언(annotating - 주석이란 의미지만 선언한다고 해야 더 의미가 맞을것 같아 그리하였음.)은 그 class가 bean의 정의(definition) source로써 Spring IoC conatainer에 의해 사용됨을 나타낸다. @Bean annotation은 @Bean으로 선언된 함수가 Spring application context에서 bean으로써 등록(register)되어질 객체를 반환할 것이라는 걸 Spring에게 알려준다. 가장 간단한 @Configuration class는 아래와 같을 것이다.
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class HelloWorldConfig { @Bean public HelloWorld helloWorld(){ return new HelloWorld(); } }
위 코드는 아래 XML설정과 동일하다.
<beans> <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" /> </beans>
@Bean으로 선언된 함수는 bean ID로써 동작하고 이것이 실제 bean을 성성하고 반환한다. 설정 class는 하나 이상의 @Bean을 선언할 수 있다. 설정 class가 정의되어진 이후부터 아래처럼 AnntationConfigApplicationContext를 사용하여 Spring container에 bean을 load하고 제공 할 수 있다.
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class); HelloWorld helloWorld = ctx.getBean(HelloWorld.class); helloWorld.setMessage("Hello World!"); helloWorld.getMessage(); }
아래처럼 다양한 설정 class를 load할 수도 있다.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class, OtherConfig.class); ctx.register(AdditionalConfig.class); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
Example:
[003] HelloWorld Example 강좌를 참조하여 프로젝트를 생성한다.
(--> 원문에서의 예제는 Maven을 사용하지 않고 직접 lib를 import하는 형식으로 진행되어 CGLIB.jar, ASM.jar를 추가적으로 import해야 하는 것으로 나오지만, Maven - Eclipse mars에서 테스트해보니 별도의 작업없이 잘 동작되었다. 단, 샘플예제에서는 annotation lib를 *로 import하고 있으나, 구체적으로 무엇인지를 물어보는 팝업이 나타나 우클릭 -> source -> orgainze imports를 이용하여 구체적으로 변경후 실행 하였다. )
HelloWorldConfig.java:
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class HelloWorldConfig { @Bean public HelloWorld helloWorld(){ return new HelloWorld(); } }
Here is the content of HelloWorld.java:
package com.tutorialspoint; public class HelloWorld { private String message; public void setMessage(String message){ this.message = message; } public void getMessage(){ System.out.println("Your Message : " + message); } }
MainApp.java:
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.*; public class MainApp { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(HelloWorldConfig.class); HelloWorld helloWorld = ctx.getBean(HelloWorld.class); helloWorld.setMessage("Hello World!"); helloWorld.getMessage(); } }
실행 결과는 아래와 같다.
Your Message : Hello World!
Injecting Bean Dependencies:
@Bean이 다른 bean과 의존관계가 있을때, 그 의존관계를 표현하는 것은 아래와 같이 다른 bean을 호출하는 bean함수를 갖는 것만큰 간단하다.
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class AppConfig { @Bean public Foo foo() { return new Foo(bar()); } @Bean public Bar bar() { return new Bar(); } }
위 예제는 foo bean이 생성자 삽입(constructor injection)을 통해 bar의 참조를 받는다.
Example:
[003] HelloWorld Example 강좌를 참조하여 프로젝트를 생성한다.
(이건 Maven환경에서 아직 돌려보지는 않았지만, 당연히 동작할거라 생각한다. - 물론 원문에서 기술된 기준으로는 잘 돌아간다. 이 예제 또한 annotation lib를 구체적으로 해야 할 듯 싶다.)
TextEditorConfig.java: 생성자(textEditor)내부에서 spellChecker() 호출을 통해 의존관계가 삽입되었다.
package com.tutorialspoint; import org.springframework.context.annotation.*; @Configuration public class TextEditorConfig { @Bean public TextEditor textEditor(){ return new TextEditor( spellChecker() ); } @Bean public SpellChecker spellChecker(){ return new SpellChecker( ); } }
TextEditor.java:
package com.tutorialspoint; public class TextEditor { private SpellChecker spellChecker; public TextEditor(SpellChecker spellChecker){ System.out.println("Inside TextEditor constructor." ); this.spellChecker = spellChecker; } public void spellCheck(){ spellChecker.checkSpelling(); } }
SpellChecker.java:
package com.tutorialspoint; public class SpellChecker { public SpellChecker(){ System.out.println("Inside SpellChecker constructor." ); } public void checkSpelling(){ System.out.println("Inside checkSpelling." ); } }
MainApp.java:
package com.tutorialspoint; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.*; public class MainApp { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(TextEditorConfig.class); TextEditor te = ctx.getBean(TextEditor.class); te.spellCheck(); } }
실행 결과는 아래와 같다.
Inside SpellChecker constructor. Inside TextEditor constructor. Inside checkSpelling.
The @Import Annotation:
@Import annotation은 다른 설정 clas로부터 @Bean을 load할 수 있도록 한다. 아래 ConfingA class를 보자
@Configuration public class ConfigA { @Bean public A a() { return new A(); } }
아래처럼 다른 Bean 선언에서 위 Bean 선언을 import할 수 있다.
@Configuration @Import(ConfigA.class) public class ConfigB { @Bean public B a() { return new A(); } }
이제는 context를 인스턴스화(instantiating)할 때 ConfigA.class와 ConfigB.class 모두를 명시하는 것이 아니라, 아래처럼 단지 사용되어지는 ConfigB만 필요하다.
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class); // now both beans A and B will be available... A a = ctx.getBean(A.class); B b = ctx.getBean(B.class); }
(--> 둘다 context를 통해 load한 후 사용한 것이 아니라 ConfigB.class만 로드해도 ConfigA.class가 자동으로 로드되어진다는 소리..)
Lifecycle Callbacks:
@Bean annotation은 임의의 초기화(initialization)와 소멸(destruction) callback 함수를 지원한다.(XML 기반에서 bean 요소의 init-method/destroy-method 속설처럼.)
public class Foo { public void init() { // initialization logic } public void cleanup() { // destruction logic } } @Configuration public class AppConfig { @Bean(initMethod = "init", destroyMethod = "cleanup" ) public Foo foo() { return new Foo(); } }
Specifying Bean Scope:
bean의 기본(default) scope는 'singleton'이지만, @Scope annotation으로 변경할 수 있다.
@Configuration public class AppConfig { @Bean @Scope("prototype") public Foo foo() { return new Foo(); } }
반응형