Whiteship's Note


context:component-scan 엘리먼트는 annotation-config도 등록해줌.

Spring/Chapter 3 : 2008. 9. 22. 18:43



이클립스에서 F2를 이용해서 읽어봤습니다.

Scans the classpath for annotated components that will be auto-registered as
 Spring beans. By default, the Spring-provided @Component, @Repository,
 @Service, and @Controller stereotypes will be detected. Note: This tag implies the
 effects of the 'annotation-config' tag, activating @Required, @Autowired,
 @PostConstruct, @PreDestroy, @Resource, @PersistenceContext and
 @PersistenceUnit annotations in the component classes, which is usually desired
 for autodetected components (without external configuration). Turn off the
 'annotation-config' attribute to deactivate this default behavior, for example in order
 to use custom BeanPostProcessor definitions for handling those annotations. Note:
 You may use placeholders in package paths, but only resolved against system
 properties (analogous to resource paths). A component scan results in new bean
 definition being registered; Spring's PropertyPlaceholderConfigurer will apply to
 those bean definitions just like to regular bean definitions, but it won't apply to the
 component scan settings themselves.

Content Model : (include-filter*, exclude-filter*)

수확이 있었군, 스프링 공부할 때 살펴볼 클래스가 하나 등장했다. PropertyPlaceholderConfigurer
설정 파일 읽어서 BeanDefinition 객체로 만든다는것 까진 알고 있었는데, 어디서 누가 하는진 몰랐는데 저 녀석이 하고 있었나 봅니다. 캬오~ JavaDoc 귿이야..

top

Write a comment.


BeanLifeCycle 인터페이스를 없애보자.

Spring/Chapter 3 : 2008. 9. 22. 16:50


BeanLifeCycle에 등장하는 여러 인터페이스 들 중에서 BeanFactoryAware, ApplicationContextAware, MessageSoruceAware, ApplicationEventPublisherAware, ResourceLoaderAware 인터페이스를 사용하지 않고도 이들이 해주는 일과 똑같은 작업을 할 수 있습니다.

@Component
public class Bean {

    @Autowired
    ApplicationContext applicationContext;
   
    @Autowired
    MessageSource messageSource;
   
    @Autowired
    ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    ResourceLoader resourceLoader;
   
    @Autowired
    BeanFactory beanFactory;
   
}

이런식으로 @Autowired를 사용하시면 됩니다. 물론 저 중에서 BeanFactory를 뺀 나머지는 ApplicationContext를 사용할 때 이용할 수 있겠죠. 라이프사이클 중에 InitializingBean 인터페이스는 bean 엘리먼트의 init-method 또는 @PostConstruct를 사용하면 대체할 수 있습니다.

꼭 필요하진 않고, 있을 때만 주입하고 싶다면, @Autowired(required=false) 이렇게 설정하면 되겠죠.

다음은 위 코드의 테스트 코드입니다,.

@ContextConfiguration(locations="springContext.xml")
public class BeanTest extends AbstractJUnit4SpringContextTests{

    @Autowired
    Bean bean;
   
    @Test
    public void lifecycle() {
        assertNotNull(bean.beanFactory);
        assertNotNull(bean.applicationContext);
        assertNotNull(bean.messageSource);
        assertNotNull(bean.applicationEventPublisher);
        assertNotNull(bean.resourceLoader);
    }
   
}

테스트는 당연히 잘 돌아갑니다.

아차. 빈 설정파일은 딱 두 줄 한 줄 입니다.
    <context:component-scan base-package="org.opensprout.sandbox.lifecycle" />
   
    <context:annotation-config />

top

  1. Favicon of http://toby.epril.com BlogIcon '토비 2008.09.22 18:27 PERM. MOD/DEL REPLY

    XML 설정에 문제가 있꾼!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.09.22 22:27 신고 PERM MOD/DEL

    헉;;; 한줄로 줄일 수 있군요.

    context:component-scan 이 엘리먼트 등록하면 <context:annotation-config /> 얘도 등록한셈이 되는거죠.

    ㅎㅎ감사합니다.

Write a comment.


Spring XML 설정 파일에서 import 동작 원리

Spring/Chapter 3 : 2008. 3. 10. 01:30


잘못된 spring configuration문제로 StackOverflowException 황당한 예외 이 글을 읽다가 궁금해서 테스트를 해봤습니다.

package contextImport;

import static org.junit.Assert.*;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextTest {

    @Test
    public void testname() throws Exception {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("contextImport/applicationContext.xml");
        assertNotNull(applicationContext);
       
        A a = (A) applicationContext.getBean("bean1");
        assertEquals("whiteship2000", a.getName());
    }
}


간단합니다. A라는 객체의 속성 값을 보고 어느 파일에서 세팅된 녀석을 가져온 건지 확인하기 위한 코드 입니다.

Application Context 설정 파일은 세 개입니다.

applicationContext.xml : bean1(A.class, name=keesun), bean2(B.class)

    <import resource="applicationContext2.xml" />
    <import resource="applicationContext3.xml" />
    <bean id="bean1" class="contextImport.A">
        <property name="name" value="keesun" />
    </bean>
    <bean id="bean2" class="contextImport.B" />

applicationContext2.xml : bean1(B.class)

    <bean id="bean1" class="contextImport.B"/>

applicationContext3.xml : bean1(A.class, name=whiteship2000)

    <bean id="bean1" class="contextImport.A">
        <property name="name" value="whiteship2000" />
    </bean>

자.. 지금 bean1 이라는 id로 등록되어 있는 빈이 전부 세개 이고 그 중에서 두 개는 A 클래스 하나는 B 클래스 입니다.

결론부터 말씀드리자면, 저는 StackOverFlow를 목격하지 못했습니다. Casting Exception은 목격할 수 있지만 운좋게 피해 갈 수도 있습니다.

1. 위와 같이 설정 해 놓고 getBean("bean1")을 호출하면 applicationContext.xml에 정의되어 있는 bean1을 돌려줍니다.

놀랐습니다. 에러가 날 줄 알았는데, 에러가 안나서.. 그런데 생각해보니 참 잘 만들었다는 생각이 들었습니다.  오오~ import 한 건 무시하고 오버라이딩 했나봐~~ 근데 이건 착각이었습니다.

오버라이딩이라고 하기도 뭐한것이... import는 엄연히 자기가 가지고 있는 빈들과 동급으로 처리하는 거지 상속 구조 처럼 상위 하위와 같은 게층 구조가 아니기 때문입니다.

사실은 오버라이딩 보다 더 단순한 규칙이 적용됩니다. 이 글을 끝까지 보시면 알 수 있습니다.

2. applicationContext.xml에 있는 bean1 설정을 주석처리하거나 없애버리고 getBean("bean1")을 호출하면, applicationContext3.xml에 정의 되어 있는 bean2를 돌려줍니다.

오호.. 이거 뭐야!! 완전 똑똑하자나!! 어떻게 알았어!! 내가 bean1을 A로 캐스팅 할 줄 알고 applicationContext3.xml 에 있는 bean1을 준거야?? 그런거야?? 너 정말 그렇게 천재인거야???

아니죠. 그렇게 똑똑 할 수는... 없습니다. 불가능하죠. 빈을 만드는 시점(ApplicationContext 인데다가 싱글톤이니까 초기에 생성하겠죠)에서는 밖에서 누굴 부를지 알 수가 없습니다. 글쵸?

암튼, 그럼 어떻게 된 일이냐...

3. 2번 상황에서 import문의 위치를 바꿔서 applicationContext3.xml이 위로 가고 applicationContext2.xml이 아래로 오게 해놓고 테스트를 했습니다.

java.lang.ClassCastException: contextImport.B
    at contextImport.ApplicationContextTest.testname(ApplicationContextTest.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
    at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
    at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51)
    at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
    at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

이야!!! 역시.. 뭔가 수상하다 했어!!
 
import는 import를 한 쪽에서 다른쪽에 정의 되어 있는 모든 bean 설정을 그대로 딱 import문을 사용한 고 위치에 XML 설정을 삽입하는 겁니다.

같은 이름의 bean이 있을 때 동작하는 방식도 무지 단순합니다. 같은 타입이건 아니건 간에 무조건 맨 아래 쪽에 정의 되어 있는 bean이 짱입니다.

스택오버플로우가 어떻게 발생한건지 더 궁금해져 갑니다 ㅠ.ㅠ
Ologist님 알려주세요~ 어떻게 된거지요???



퀴즈. 그렇다면, 다른 건 동일하고 applicationContext.xml만 다음과 같이 정의하고 위의 코드를 돌리면 어떤 결과가 발생할까요?

    <bean id="bean1" class="contextImport.A">
        <property name="name" value="keesun" />
    </bean>
      
    <bean id="bean2" class="contextImport.B" />

    <import resource="applicationContext3.xml" />
    <import resource="applicationContext2.xml" />

top

  1. Favicon of http://www.ologist.co.kr BlogIcon ologist 2008.03.11 21:07 PERM. MOD/DEL REPLY

    위에서 테스트한 내용보다 조금 더 복잡한 내용이 있는데, 글로는 표현이 안되서..
    이 부분은 시간이 날때 좀더 보도록 하죠. 나중에 알게 되면 공유할게요. 지금은 너무 바뻐서...OTL

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.03.11 22:59 신고 PERM MOD/DEL

    :)

Write a comment.


3.11.2. Using filters to customize scanning

Spring/Chapter 3 : 2007. 8. 6. 12:16


bean으로 등록할 class를 스캔할 때 기본적인 방식(기본으로 사용하는 필터)은 다음과 같습니다.

base-package 이하의 package에 속해 있는 모든 클래스 중에서 @Component 또는 @Repository 애노테이션이 붙어 있으면 모두 bean으로 사용.

이 때 명시적으로 다른 필터를 사용하여 위의 기본 방식을 변경하거나 확장할 수 있습니다. 필터 사용은 매우 간단하게 <component-scan /> 태그의 하위 태그로 정의 할 수 있습니다.

필터 태그의 종류는 include-filter와 exclude-filter 두 가지 이며 각각 type과 expression을 가지고 있습니다. type은 필터의 타입을 나타내며 expression은 말그대로 표현식을 나타냅니다.

필터에서 사용할 수 있는 타입과 표현식은 다음과 같습니다.
사용자 삽입 이미지

<context:component-scan base-package="whiteship" use-default-filters="false"  />

이렇게 기본 필터의 사용을 fasle로 설정하면 @Component나 @Repository 애노테이션을 사용한 클래스 조차 bean으로 인식하지 않습니다.

    <context:component-scan base-package="whiteship" use-default-filters="false">
        <context:include-filter type="annotation" expression="whiteship.Bean"/>
    </context:component-scan>

Bean이라는 annotation을 만들고, @Bean 애노테이션이 붙은 것을 bean으로 읽도록 정의해 두었습니다. @Bean 애노테이션 생성은 간단합니다.

public @interface Bean {

}

요렇게 만들어 두면 되죠. 그리고 이제 그냥 사용하면 됩니다.

@Bean
public class MovieFinder {

}

@Bean
public class SimpleMovieLister {

    @Autowired
    private MovieFinder movieFinder;
   ....
}

매우 간단하네요.


top

Write a comment.


3.11. Classpath scanning for beans

Spring/Chapter 3 : 2007. 8. 2. 10:13


3.10에서 살펴봤던 @Autowired 애노테이션을 사용할 때에도 기본 bean 설정은 XML을 통해서 했었습니다. 하지만 이번에는 암묵적으로 클래스패스에서 bean을 등록하는 방법과 필터와 매칭 되는 bean을 등록하는 방법을 살표보겠습니다.

3.11.1. @Component and @Repository

@Component 와 @Repository 애노테이션 사용해서 bean 등록하는 방법

http://whiteship.tistory.com/1042

3.11.2. Using filters to customize scanning

@Component 와 @Repository 애노테이션이 붙어 있으면 무조건 bean으로 등록이 되지만, filter를 사용하여 특정 클래스들을 bean으로 사용하는 것에서 제외할 수 있습니다.

3.11.3. Naming auto-detected beans

bean이름을 설정할 수 있습니다.

3.11.4. Providing a scope for auto-detected beans

bean의 scope을 지정해 줄 수 있습니다.






top

Write a comment.


3.11.1. @Component and @Repository

Spring/Chapter 3 : 2007. 8. 2. 10:01


Spring 2.0에 새로 도입한 @Repository 애노테이션은 스테레오타입 애노테이션으로 DAO 역할을 하는 클래스를 나타냈었으며 해당 클래스에서 발생하는 DB 관련 예외를 Spring의 DAOException으로 전환해주는 일을 했습니다. 참조

Spring 2.1에는 '스테레오 타입이 붙은' 클래스를 모두 찾아서 ApplicationContext의 BeanDefinition 객체로(<bean>태그를 읽어서 이 객체 형태로 가지고 있게 되지요.) 만들어 주는 역할을 하는 새로운 스테레오타입 애노테이션인 @Component를 추가했습니다.

물론 그럴 떄 필요한 Post Processor를 등록해야 하는데 그 부분을 숨겨두고 사용하기 편하게 태그 한 줄로 등록할 수 있습니다.

AutowiredAnnotationBeanPostProcessor 와 CommonAnnotationBeanPostProcessor를 등록해주는 태그는 다음과 같습니다.

<context:component-scan base-package="org.example"/>

사용자 삽입 이미지
Spring IDE 2.0을 설치 하셨다면 Spring 설정파일 안에서 'Ctrl + 스페이스' 만으로 해당 태그를 찾을 수 있습니다.
@Repository
public class MovieFinder {

}

@Component
public class SimpleMovieLister {

   @Resource(name="myMovieFinder")
   private MovieFinder movieFinder;

   ...
}

<?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-2.0.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context-2.1.xsd">

   <context:annotation-config />
   <context:component-scan base-package="whiteship"  />

</beans>

그리고 다음과 같은 테스트 코드를 돌려서 확인해 볼 수 있습니다.

public class DITest extends AbstractDependencyInjectionSpringContextTests{

   private SimpleMovieLister lister;

   public void setLister(SimpleMovieLister lister) {
       this.lister = lister;
   }

   @Override
   protected String[] getConfigLocations() {
       return new String[]{"classpath:whiteship/applicationContext.xml"};
   }

   public void testDI() throws Exception {
       assertNotNull(lister.getMovieFinder());
   }
}

결과는 에러~
이유는? asm 라이브러리가 필요합니다.
구체적으로는 asm.jar 와 asm-commons.jar 가 필요합니다.

그리고 주의 할 것!
@Component나 @Repository 애노테이션에 별도의 bean name을 지정하지 않았다면 bean의 이름을 사용하여 DI하기 위해 사용했었던 @Resource 애노테이션은 걷어내고 @Autowired로 바꿔주어야 합니다.


top

Write a comment.


3.10.3. @PostConstruct and @PreDestroy

Spring/Chapter 3 : 2007. 7. 30. 20:26


Bean Life Cycle 콜백 중에서 InitializingBean과 DisposableBean 인터페이스를 사용하거나 XML 설정에서 bean 태그 속성 중에 init-method와 destroy-method 을 사용하여 특정 메소드를 생성자가 호출 된 후(초기화 이후)나 객체가 소멸되기 전에 실행할 메소드를 지정할 수 있었습니다.

이것에 대한 또 다른 대안이자 JSR-250 라이프사이클 애노테이션 표준을 따르는 @PostConstruct와 @PreDestroy 애노테이션이 Spring 2.1에 추가되었습니다.

public class CachingMovieLister {

    @PostConstruct
    public void populateMovieCache() {
        // populates the movie cache upon initialization...
    }
   
    @PreDestroy
    public void clearMovieCache() {
        // clears the movie cache upon destruction...
    }
   
}

사용법은 위 처럼 더욱 간편해 졌습니다.

정리하다 보니 궁금한 것이 생겼는데 애노테이션에서도 설정하고 XML에서도 설정을 하면 어떻게 될지 입니다.
그래서 예제를 만들어 돌려보았습니다.

public class SimpleMovieLister {

    public void initMethod(){
        System.out.println("initMetod");
    }

    @PostConstruct
    public void postConstuct(){
        System.out.println("postConstruct");
    }

}

    <bean name="lister" class="whiteship.SimpleMovieLister"
        init-method="initMethod" />

init-method 속성도 사용하고 @PostConstruct 애노테이션도 사용하면 다음과 같이 @PostConstruct가 먼저 적용되는 것을 확인할 수 있었습니다.

사용자 삽입 이미지


top

Write a comment.


3.10.2. @Resource

Spring/Chapter 3 : 2007. 7. 30. 20:12


@Autowired 애노테이션의 경우 타입으로 오토 와이어링을 하고 있습니다. 따라서 같은 타입이 여러개인 경우 예외가 발생합니다. 이 때 bean의 Name으로 종속성을 주입할 수 있는데 @Resource 애노테이션과 name 속성을 사용하면 됩니다.

public class SimpleMovieLister {

    @Resource(name="myMovieFinder")
    private MovieFinder movieFinder;

    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    public MovieFinder getMovieFinder() {
        return movieFinder;
    }

}

SimpleJndiBeanFactory를 명시적으로 설정해둔 경우에는 JNDI를 사용하여 해당 이름의 객체를 가져오지만 그렇치 않은 기본적인 경우에는 CommonAnnotationBeanPostProcessor를 사용하는 BeanFactory에서 가져옵니다.

'Spring > Chapter 3' 카테고리의 다른 글

Spring XML 설정 파일에서 import 동작 원리  (2) 2008.03.10
3.11.2. Using filters to customize scanning  (0) 2007.08.06
3.11. Classpath scanning for beans  (0) 2007.08.02
3.11.1. @Component and @Repository  (0) 2007.08.02
3.10.3. @PostConstruct and @PreDestroy  (0) 2007.07.30
3.10.2. @Resource  (0) 2007.07.30
3.10.1. @Autowired  (0) 2007.07.30
3.10. Annotation-based configuration  (0) 2007.07.30
Bean Life Cycle  (2) 2007.06.21
Spring에서 Bean을 언제 만들지?  (5) 2007.06.05
Spring Reference 3장 오타  (2) 2007.05.22
top

Write a comment.


3.10.1. @Autowired

Spring/Chapter 3 : 2007. 7. 30. 20:09


@Autowired 애노테이션을 붙여서 종속성을 주입할 수 있는데 XML 기반 설정파일에서의 오토 와이어링 설정 보다 더 유연하고 확장성이 좋아졌습니다.
  • 일반 적인 setter 위에 붙일 수 있습니다.
  • 메소드의 이름이 굳이 setter 형식일 필요가 없습니다.
  • 필드와 생성자에도 붙일 수 있습니다.
public class SimpleMovieLister {

   @Autowired
   private MovieFinder movieFinder;

   public void setMovieFinder(MovieFinder movieFinder) {
       this.movieFinder = movieFinder;
   }

   public MovieFinder getMovieFinder() {
       return movieFinder;
   }

}

주의 할 것은 종속성을 주입할 후보자가 아무것도 없다면 에러가 발생한다는 것입니다. 즉 @Autowired 애노테이션이 붙은 메소드, 생성자, 필드의 경우 기본으로 필수 요소로 인식합니다. 이를 원치 않을 때는 다음과 같이 설정할 수 있습니다.

@Autowired(required = false)

Spring 2.1 M1에서는 해당 속성이 없습니다. Spring 2.1 M2 부터 지원하고 있습니다.

사용자 삽입 이미지

Spring 2.1 M2에서도 지원하고 있는 속성이 딱 한 개 입니다. 타입으로 종속성 주입할 대상을 찾습니다.
top

Write a comment.


3.10. Annotation-based configuration

Spring/Chapter 3 : 2007. 7. 30. 20:06


Spring 2.0에서 필수 속성을 강제할 수 있었던 @Required 애노테이션과 같이, Spring 2.1에는 종속성을 주입할 수 있는 @Autowired 애노테이션을 비롯하여 JSP-250 표준에 따르는 @Resource, @PostConstruct, 그리고 @PreDestroy 애노테이션이 추가되었습니다. (물론 JDK 5.0 이상을 사용해야합니다.)

이러한 애노테이션이 붙은 빈들을 별도의 처리가 필요하고, 그러한 일들을 담당하는 녀석이 BeanPostProcessor였습니다. 따라서 @Autowired 애노테이션이 붙어있는 Bean의 속성을 종속성 주입할 BeanPostProcessor를 등록해야 합니다. 그리고 또 다른 애노테이션에 대한 작업을 할 BeanPostProcessor도 등록해야 하죠. 하지만 이렇게 여러 BeanPostProcessor를 등록하는 대신 간단한 태그 한 줄이면 이런 Bean들이 등록 되도록 하는 네임스페이스가 있으니 그것을 사용하면 됩니다.

<?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-2.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.1.xsd">
              
    <context:annotation-config/>
    
</beans>

저 한 줄이면 AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor 이 세개의 BeanPostProcessor를 빈으로 등록한 것과 같은 것입니다.
top

Write a comment.


Bean Life Cycle

Spring/Chapter 3 : 2007. 6. 21. 13:48


사용자 삽입 이미지

<참조>
Spring In Action 48쪽
[Spring 3] BeanFactory와 ApplicationContext 내의 Bean의 Lifecycle
Spring API :: BeanFactory
top

  1. 양완수 2008.08.22 11:08 PERM. MOD/DEL REPLY

    기선님 life cycle 포스트의 이미지를 회사 세미나 자료에 사용하려합니다. 허락해주신다면 출처를 기재한후 사용하겠습니다.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.08.22 12:41 PERM MOD/DEL

    네. 출처만 밝혀주시면 자유롭게 사용하실 수 있습니다.

Write a comment.


Spring에서 Bean을 언제 만들지?

Spring/Chapter 3 : 2007. 6. 5. 18:34


그때 그때 상황(Context, Configuration Metadata)에 따라 다릅니다.
 
0. default로 BeanFactory와[각주:1] ApplicationContext를 만들 때 모든 bean들의 객체를 만들어 두고 getBean()이라는 요청이 오면 해당 bean을 넘겨 줍니다.

1. 만약에 어떤 bean을 미리 만들어 두기 싫고 필요할 때 만들고 싶다면(lazy-initialization) lazy-init 속성을 사용할 수 있습니다.

2. bean의 scope와도 관계가 있는데요. bean을 정의할 때 별다른 설정을 하지 않으면 singleton scope을 가지게 됩니다. 이 때도 역시 bean을 미리 만들어 둘려고 합니다. singleton이 아닌 scope으로 설정하면 미리 만들어 두지 않습니다.

3. 1번과 2번으로 해당 bean을 설정해도 예상과 다르게 동작할 수 있습니다. scope이나 lazy-init 속성이 다른 여러 bean들 사이의 종속성으로 인해 그런 일이 발생합니다.

0, 1, 2를 표로 나타내면 다음과 같습니다.

bean설정 내용

Singleton(Default)

Non-Singleton

Lazy-Init=false(default)

초기에 생성

나중에 생성

Lazy-Init=true

나중에 생성

나중에 생성


테스트 코드
 public void testBeanInstantiation() throws Exception {
  System.out.println("*******************************");
  System.out.println("BeanFactory 만들기 시작!!!");
  System.out.println("*******************************");
  Resource resource = new ClassPathResource("bean/beanInstantiation-context.xml");
  BeanFactory beanFactory = new XmlBeanFactory(resource);
  assertNotNull(beanFactory);
  System.out.println("*******************************");
  System.out.println("BeanFactory 만들기 끝!!!");
  System.out.println("*******************************");
  Object bean1 = beanFactory.getBean("bean1");
  System.out.println("*******************************");
  System.out.println("bean1 만들기 끝!!!");
  System.out.println("*******************************");
  bean1 = beanFactory.getBean("bean1");
  System.out.println("*******************************");
  System.out.println("bean1 만들기 끝!!!");
  System.out.println("*******************************");
 }

예상[각주:2]했던 거랑은 달리 ApplicationContext랑 BeanFactory 차이가 없습니다.[각주:3]

테스트 할 때 사용한 파일들 입니다.


  1. 김재호님의 제보로 수정합니다. BeanFactory는 무조건 Lazy Initialization을 사용합니다. [본문으로]
  2. BeanFactory에서만 prototype일 경우 lazy-init을 무시한다. [본문으로]
  3. 그러나 테스트 해본 결과 ApplicationContext도 prototype일 경우 lazy-init을 무시합니다. [본문으로]

'Spring > Chapter 3' 카테고리의 다른 글

3.10.3. @PostConstruct and @PreDestroy  (0) 2007.07.30
3.10.2. @Resource  (0) 2007.07.30
3.10.1. @Autowired  (0) 2007.07.30
3.10. Annotation-based configuration  (0) 2007.07.30
Bean Life Cycle  (2) 2007.06.21
Spring에서 Bean을 언제 만들지?  (5) 2007.06.05
Spring Reference 3장 오타  (2) 2007.05.22
Bean Life Cycle 콜백 인터페이스 사용 예(in Spring)  (2) 2007.05.11
머리 뽀개지는 BeanPostProcessor  (0) 2007.05.09
Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
top

  1. 김재호 2007.12.13 00:31 PERM. MOD/DEL REPLY

    BeanFactory에서 lazy-init 속성은 무시 되는거 아닌가요?
    BeanFactory는 컨테이너 생성 시점에서 bean들을 생성안하고 요청했을때 만드는데
    ApplicationContext 처럼 BeanFactory도 bean을 미리 만들어 두는 방법이 있는 건가요?

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.12.13 17:08 신고 PERM MOD/DEL

    BeanFactory에서 lazy-init 속성은 무시 되는거 아닌가요?
    => bean의 scope와 의존성에 따라 다른 결과가 발생합니다.

    BeanFactory는 컨테이너 생성 시점에서 bean들을 생성안하고 요청했을때 만드는데
    => 꼭 그렇치는 않습니다. bean 설정에 따라 다릅니다.

    ApplicationContext 처럼 BeanFactory도 bean을 미리 만들어 두는 방법이 있는 건가요?
    => 아직까진 모르겠습니다.

  2. 김재호 2007.12.13 15:18 PERM. MOD/DEL REPLY

    그렇다면 제가 그동안 잘못 알고 있었군요...

    BeanFactory 를 생성 할 때 다음과 같은 bean이 선언 되어 있을 경우
    <bean id="test" class="a.Test" />
    scope는 디폴트로 singleton인데 왜 미리 생성을 안하는지 궁금하네요
    어떻게 설정해야 하는지 알려 주실 수 있으신가요?

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.12.13 17:08 신고 PERM MOD/DEL

    죄송합니다. 제가 틀렸습니다. ㅎㅎ;;
    BeanFactory는 lazy initialization만 제공합니다.
    글을 수정하겠습니다~ 감사합니다.(__)/

  3. 김재호 2007.12.13 17:38 PERM. MOD/DEL REPLY

    아닙니다.
    BeanFactory는 lazy initialization만 제공하는걸 확실히 알았으니 오히려 제가 감사합니다.

Write a comment.


Spring Reference 3장 오타

Spring/Chapter 3 : 2007. 5. 22. 15:43


3.8.1 에 다음과 같은 예제 코드가 있습니다. (2.0.5 버전)

# in 'exceptions.properties'
argument.required=The '{0}' argument is required.

여기에 잘 못된 부분이 하나 있습니다. {0}을 따옴표로 감싸면 안 됩니다. 출력 될 때 인자로 값을 받기 위한 것이 맞다면 홑 따옴표를 없애야 합니다.

좀더 아래에 있는 다음의 예제코드인

<beans>

    <!-- this MessageSource is being used in a web application -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="baseName" value="WEB-INF/test-messages"/>
    </bean>
   
    <!-- let's inject the above MessageSource into this POJO -->
    <bean id="example" class="com.foo.Example">
        <property name="messages" ref="messageSource"/>
    </bean>

</beans>

여기에도 잘 못된 부분이 하나 있습니다. beanName 이라고 하면 안되고 beanname 이렇게 소문자로 바꿔줘야 합니다. setBeanname() 메소드를 사용하기 때문이죠.

오타가 자주 등장하지만 그렇다고 코딩에 지대한 영향을 끼치지는 않습니다. 물론 대부분 에러가 발생하고 로그 메시지 보면 고칠 수 있고 정말 단순한건 이클립스에 코드만 붙여넣어 봐도 오타를 찾을 수 있습니다.ㅋㅋ


오타를 어떻게 수정해야 하는지는 위에 적어뒀습니다. 찾아보세열~


'Spring > Chapter 3' 카테고리의 다른 글

3.10.2. @Resource  (0) 2007.07.30
3.10.1. @Autowired  (0) 2007.07.30
3.10. Annotation-based configuration  (0) 2007.07.30
Bean Life Cycle  (2) 2007.06.21
Spring에서 Bean을 언제 만들지?  (5) 2007.06.05
Spring Reference 3장 오타  (2) 2007.05.22
Bean Life Cycle 콜백 인터페이스 사용 예(in Spring)  (2) 2007.05.11
머리 뽀개지는 BeanPostProcessor  (0) 2007.05.09
Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
top

  1. Favicon of http://gerions.egloos.com BlogIcon 윤걸 2007.05.22 16:59 PERM. MOD/DEL REPLY

    으음.. 기선이도 오타~ 오타가 어딨는지 찾아보아요~
    오타놀이~~~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.05.22 17:56 신고 PERM MOD/DEL

    크헉 너무 많아요. 제 블로그는 오타 투성이에요.ㅋㅋ
    맞춤법, 띄어쓰기 너무 어려워요.ㅋ

Write a comment.


Bean Life Cycle 콜백 인터페이스 사용 예(in Spring)

Spring/Chapter 3 : 2007. 5. 11. 11:54


BeanNameAware
- ServletForwardingController
- AbstractView
- PortletWrappingController
- GenericFilterBean
- JobDetailBean
- OsgiServiceProxyFactoryBean
- AbstractTest
- EhCacheFactoryBean
- FieldRetrievingFactoryBean

BeanClassLoaderAware
- 구현 방법 : this.beanClassLoader = (beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader());
- AbstractBeanFactory
- AbstractBeanDefinitionReader ::
- ConfigurableBeanFactory 인터페이스 ::
- AbstractHttpInvokerRequestExecutor
- HttpInvokerTests

BeanFactoryAware
- MethodLocatingFactoryBean
- ProxyFactoryBean
= AbstractAdvisorAutoProxyCreator
- AbstractBeanFactoryBasedTargetSourceCreator
- ScopedProxyFactoryBean
- AbstractBeanFactoryBasedTargetSource
- AutowiredAnnotationBeanPostProcessor
- ObjectFactoryCreatingFactoryBean
- ServiceLocatorFactoryBean
- DependencyInjectionAspectSupport
- 엄청난 분량

BeanPostProcessor :: before :: after
- BundleContextAwareProcessor :: 해당 bean이 bundleaware 일 때 BundleContext 세팅, 로깅, 없으면 예외처리 :: ::
- CommonsLogProviderBeanPostProcessor :: 리플렉션 사용해서 로깅 :: ::
- ServletContextAwareProcessor :: ServletContext랑 SevletConfig 세팅 :: ::
- PortletContextAwareProcessor
- AbstractAutoProxyCreator ::  :: 프록시 만들 때 사용

InitializingBean
- MustBeInitialized
- ServiceCreationFactoryBean
- CommonsLogFactoryBean :: 로깅
- FieldRetrievingFactoryBean :: 없으면 확인하고
- MethodInvokingFactoryBean ::
public void afterPropertiesSet() throws Exception {
        prepare();
        if (this.singleton) {
            this.initialized = true;
            this.singletonObject = doInvoke();
        }
    }
- PropertiesFactoryBean :: 싱글톤인지..
- ResourceFactoryBean :: resource 가 널이면 예외 발생
- 그 외에도 많아요.

ResourceLoaderAware
- ReloadableResourceBundleMessageSource :: Set the ResourceLoader to use for loading bundle properties files.
- DefaultPersistenceUnitManager
- ResourceJobSchedulingDataProcessor
- ScriptFactoryPostProcessor

ApplicationEventPublisherAware
- EventPublicationInterceptor :: invoke 호출할 때 이벤트 발생

MessageSourceAware
- Service :: 그냥 구현했네

ApplicationContextAware
- ApplicationObjectSupport :: applicationcontext 세팅하고 주는일 하는데 사용하는거 편하게 해주려고 만든 클레스
- SchedulerFactoryBean :: 스케쥴링 할 때 applicatoincontext 사용

ServletContextAware
-ServletContextAwareBean :: 기본 구현
- ServletContextAttributeExporter :: servletcontext 받아서 attributes Map을 채우네..
- ServletContextAttributeFactoryBean :: 위랑 같은데 역긴 attribute 하나만 채우네..
- ServletContextFactoryBean :: 기본 구현
- ServletContextParameterFactoryBean :: this.paramValue = servletContext.getInitParameter(this.initParamName); paramValue 세팅
- ServletContextPropertyPlaceholderConfigurer :: resolvePlaceholder 에서 사용
- WebApplicationObjectSupport :: 기본 구현
- CommonsMultipartResolver :: FileItemFactor에 Repository 위치 정보 세팅
- SimpleServletPostProcessor :: postProcessAfterInitialization 에서 사용

'Spring > Chapter 3' 카테고리의 다른 글

3.10.1. @Autowired  (0) 2007.07.30
3.10. Annotation-based configuration  (0) 2007.07.30
Bean Life Cycle  (2) 2007.06.21
Spring에서 Bean을 언제 만들지?  (5) 2007.06.05
Spring Reference 3장 오타  (2) 2007.05.22
Bean Life Cycle 콜백 인터페이스 사용 예(in Spring)  (2) 2007.05.11
머리 뽀개지는 BeanPostProcessor  (0) 2007.05.09
Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
top

  1. Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2007.05.11 12:40 PERM. MOD/DEL REPLY

    엄청 많아요 >.<

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.05.11 13:39 신고 PERM MOD/DEL

    언젠가 학교에서 Spring을 가르치게 되면
    분명히 저걸 다 외우라고 시킬꺼야.
    미리 외워둬 ㅋㅋ

Write a comment.


머리 뽀개지는 BeanPostProcessor

Spring/Chapter 3 : 2007. 5. 9. 17:20


이전 글에서 모든 Bean Life Cycle 콜백들을 구현하여 모든 콜백들이 예상대로 동작하는지 확인해봤습니다. 모든 메소드들이 제대로 동작했지만 BeanPostProcessor만 이상하게 동작하지 않았습니다.

결론부터 말씀드리면 재미없기 때문에 일단 코드를 보겠습니다.
    <bean id="test" class="net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean" init-method="customInit" />

    <bean id="test2" class="net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean" init-method="customInit" />

이 전 글에서 테스트 할 때 사용한 클레스를 다른 빈으로 하나 더 등록하고 테스트를 돌렸습니다.

setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.
setResourceLoader() 실행합니다.
setApplicationEventPublisher() 실행합니다.
setMessageSource() 실행합니다.
setApplicationContext() 실행합니다.
afterPropertiesSet() 실행합니다.
customInit() 실행합니다.
setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.
setResourceLoader() 실행합니다.
setApplicationEventPublisher() 실행합니다.
setMessageSource() 실행합니다.
setApplicationContext() 실행합니다.
postProcessBeforeInitialization() 실행합니다.
afterPropertiesSet() 실행합니다.
customInit() 실행합니다.
postProcessAfterInitialization() 실행합니다.

자 이제 수수께기가 풀리기 시작합니다. 제가 녹색으로 칠한 부분이 test 빈에서 찍힌것이고 v하늘색은 test1 빈에서 찍힌것입니다.

BeanPostProcessor의 콜백 메소드들은 자신 이후에 생성되는 빈들에 적용됩니다.

좀 더 확실하게 확인하기 위해서 이번엔 세 개로 테스트 해보겠습니다.

    <bean id="test" class="net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean" init-method="customInit" />

    <bean id="test2" class="net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean" init-method="customInit" />

    <bean id="test3" class="net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean" init-method="customInit" />

결과는 다음과 같습니다,

setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.
setResourceLoader() 실행합니다.
setApplicationEventPublisher() 실행합니다.
setMessageSource() 실행합니다.
setApplicationContext() 실행합니다.
afterPropertiesSet() 실행합니다.
customInit() 실행합니다.
setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.
setResourceLoader() 실행합니다.
setApplicationEventPublisher() 실행합니다.
setMessageSource() 실행합니다.
setApplicationContext() 실행합니다.
postProcessBeforeInitialization() 실행합니다.
afterPropertiesSet() 실행합니다.
customInit() 실행합니다.
postProcessAfterInitialization() 실행합니다.
setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.
setResourceLoader() 실행합니다.
setApplicationEventPublisher() 실행합니다.
setMessageSource() 실행합니다.
setApplicationContext() 실행합니다.
postProcessBeforeInitialization() 실행합니다.
postProcessBeforeInitialization() 실행합니다.
afterPropertiesSet() 실행합니다.
customInit() 실행합니다.
postProcessAfterInitialization() 실행합니다.
postProcessAfterInitialization() 실행합니다.

하지만 bean 생성은 보통 설정 파일에 등록되어 있는 순서이고 depends-on 속성을 사용한다 하더라고 위 처럼 여러개의 BeanPostProcessor의 실행 순서를 예측하기란 사실 불안합니다.

그래서...BeanPostProcessor가 implements하고 있는 Orderd 인터페이스를 사용하여 순서를 지정할 수 있습니다.

BeanFactoryPostProcessor와의 차이는 BeanPostProcessor는 Bean 객체에 조작을 하는 반명 BeanFactoyPostProcessor는 Bean을 만드는 설명서에 해당하는 설정파일을 조작한다는 것입니다.

'Spring > Chapter 3' 카테고리의 다른 글

3.10. Annotation-based configuration  (0) 2007.07.30
Bean Life Cycle  (2) 2007.06.21
Spring에서 Bean을 언제 만들지?  (5) 2007.06.05
Spring Reference 3장 오타  (2) 2007.05.22
Bean Life Cycle 콜백 인터페이스 사용 예(in Spring)  (2) 2007.05.11
머리 뽀개지는 BeanPostProcessor  (0) 2007.05.09
Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
top

Write a comment.


Bean Life Cycle 통째로 테스트

Spring/Chapter 3 : 2007. 5. 9. 17:02


Bean Life Cycle
BeanNameAware 테스트
BeanClassLoaderAware 테스트
BeanFactoryAware 테스트
MessageSource 사용 예
ApplicationEvent 사용 예
MessageSource 사용 예
BeanPostProcessor 사용 예

다 비슷한 테스트 들인데 하나씩 테스트 하기가 지겨워서 Bean Life Cycle에 관여하는 모든 인터페이스를 전부 구현하도록 했습니다.

/**
 *
 */
package net.agilejava.jedi.spring.beanLifeCycle;

import javax.servlet.ServletContext;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.context.ServletContextAware;

/**
 * @author keesun
 *
 */
public class BeanLifeCycleTestBean implements BeanNameAware,
    BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware,
    ApplicationEventPublisherAware, MessageSourceAware,
    ApplicationContextAware, ServletContextAware, BeanPostProcessor,
    InitializingBean{

    String beanName;

    ClassLoader classLoader;

    BeanFactory beanFactory;

    ResourceLoader resourceLoader;

    public void setBeanName(String beanName) {
        System.out.println("setBeanName() 실행합니다.");
        this.beanName = beanName;
    }

    public String getBeanName(){
        return beanName;
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader() 실행합니다.");
        this.classLoader = classLoader;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory() 실행합니다.");
        this.beanFactory = beanFactory;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

    public void setResourceLoader(ResourceLoader resourceLoader) {
        System.out.println("setResourceLoader() 실행합니다.");
        this.resourceLoader = resourceLoader;
    }

    public ResourceLoader getResourceLoader(){
        return resourceLoader;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher arg0) {
        System.out.println("setApplicationEventPublisher() 실행합니다.");
    }

    public void setMessageSource(MessageSource arg0) {
        System.out.println("setMessageSource() 실행합니다.");
    }

    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        System.out.println("setApplicationContext() 실행합니다.");
    }

    public void setServletContext(ServletContext servletContext){
        System.out.println("setServletContext() 실행합니다.");
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization() 실행합니다.");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization() 실행합니다.");
        return bean;
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet() 실행합니다.");
    }

    public void customInit(){
        System.out.println("customInit() 실행합니다.");
    }
}

테스트에서는 getBean으로 해당 bean을 가져오기만 합니다. 그러면 다음과 같은 출력을 확인할 수 있습니다.

setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.
setResourceLoader() 실행합니다.
setApplicationEventPublisher() 실행합니다.
setMessageSource() 실행합니다.
setApplicationContext() 실행합니다.
afterPropertiesSet() 실행합니다.
customInit() 실행합니다.

어라.. 뭔가 빠졌습니다. 뭐가 빠졌을까요.. 구현한 것 중에 BeanPostProcessor와 관련된 callback들이 실행되지 않았습니다.

이론~ 왜이러는거야~~ 왜 BeanPostProcessor를 왕따시키는거야!!

'Spring > Chapter 3' 카테고리의 다른 글

Bean Life Cycle  (2) 2007.06.21
Spring에서 Bean을 언제 만들지?  (5) 2007.06.05
Spring Reference 3장 오타  (2) 2007.05.22
Bean Life Cycle 콜백 인터페이스 사용 예(in Spring)  (2) 2007.05.11
머리 뽀개지는 BeanPostProcessor  (0) 2007.05.09
Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
Circular dependencies  (0) 2007.03.24
top

Write a comment.


BeanFactoryAware 테스트

Spring/Chapter 3 : 2007. 5. 9. 15:34


    @Test
    public void testBeanFactoryAware() {
        BeanFactory beanFactory = bean.getBeanFactory();
        assertNotNull(beanFactory);
    }

테스트 코드는 간단합니다. 이전 글에 사용했던 클레스에 BeanFactoryAware 인터페이스를 추가로 구현합니다.

public class BeanLifeCycleTestBean implements BeanFactoryAware, ... {

    ... 생략

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("setBeanFactory() 실행합니다.");
        this.beanFactory = beanFactory;
    }

    public BeanFactory getBeanFactory() {
        return beanFactory;
    }

}

테스트를 실행하면 테스트가 통과 하는 걸 확인 할 수 있습니다. 그리고 Output 창을 통해 확인 하면 다음과 같습니다.

setBeanName() 실행합니다.
setBeanClassLoader() 실행합니다.
setBeanFactory() 실행합니다.

BeanFactoryAware 사용 예
ObjectFactoryCreatingFactoryBean 사용 예

이 인터페이스를 구현한 클레스들..
AbstractAdvisorAutoProxyCreator, AbstractAutoProxyCreator, AbstractBeanFactoryBasedTargetSource, AbstractBeanFactoryBasedTargetSourceCreator, AbstractBeanFactoryPointcutAdvisor, AbstractFactoryBean, AbstractPoolingTargetSource, AbstractPrototypeBasedTargetSource, AnnotationAwareAspectJAutoProxyCreator, AspectJAwareAdvisorAutoProxyCreator, BeanConfigurerSupport, BeanFactoryDataSourceLookup, BeanNameAutoProxyCreator, BeanReferenceFactoryBean, CommonsPoolTargetSource, DefaultAdvisorAutoProxyCreator, DefaultBeanFactoryPointcutAdvisor, HibernateAccessor, HibernateAccessor, HibernateInterceptor, HibernateInterceptor, HibernateTemplate, HibernateTemplate, HibernateTransactionManager, HibernateTransactionManager, LazyInitTargetSource, LazyInitTargetSourceCreator, ListFactoryBean, MapFactoryBean, MBeanExporter, MethodInvokingFactoryBean, MethodInvokingJobDetailFactoryBean, MethodLocatingFactoryBean, ObjectFactoryCreatingFactoryBean, OpenSessionInViewInterceptor, OpenSessionInViewInterceptor, PersistenceAnnotationBeanPostProcessor, PersistenceExceptionTranslationInterceptor, PersistenceExceptionTranslationPostProcessor, PreferencesPlaceholderConfigurer, PropertyPathFactoryBean, PropertyPlaceholderConfigurer, PrototypeTargetSource, ProxyFactoryBean, QuickTargetSourceCreator, ScopedProxyFactoryBean, ScriptFactoryPostProcessor, ServiceLocatorFactoryBean, ServletContextPropertyPlaceholderConfigurer, SetFactoryBean, SimpleBeanFactoryAwareAspectInstanceFactory, SimpleBeanTargetSource, ThreadLocalTargetSource, TransactionProxyFactoryBean
엄청나게 많습니다.

주로 다른 Bean을 lock up 할 수 있는 factory사 필요할 때 사용합니다. 특정 객체만을 뽑아낼 factory가 필요하다면 FactoryBean을 사용하면 되는데 이때도 이 인터페이스를 사용할 수 있기 때문에 위의 구현체들의 반정도는 XXXFactoryBean 입니다.

FactroyBean을 사용하는 이유는 '만들 수 없는 것'을 FactoryBean으로 만들기 이 글에서 확인할 수 있으며 주로 객체 생성에 복잡한 설정과 로직이 필요한 경우에 사용하며 따라서 다른 프레임워크와 연동하는 객체가 필요한 경우에 자주 사용하며 위의 구현체 중에 또 절반 정도는 그러한 구현체에 해당합니다.


top

Write a comment.


BeanClassLoaderAware 테스트

Spring/Chapter 3 : 2007. 5. 9. 08:32


이전 글에서 사용한 Bean 클레스에 BeanClassLoaderAware 인터페이스를 추가로 구현합니다.
public class BeanLifeCycleTestBean implements BeanNameAware, BeanClassLoaderAware{

    String beanName;

    ClassLoader classLoader;

    public void setBeanName(String beanName) {
        System.out.println("setBeanName() 실행합니다.");
        this.beanName = beanName;
    }

    public String getBeanName(){
        return beanName;
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("setBeanClassLoader() 실행합니다.");
        this.classLoader = classLoader;
    }

    public ClassLoader getClassLoader() {
        return classLoader;
    }

간단한 로깅을 위해서 문자열을 출력해 줍니다. 빈 설정은 바뀔 것이 없으며 테스트 코드만 약간 변경합니다.
public class BeanLifeCycleTest {

    private ApplicationContext context;
    private BeanLifeCycleTestBean bean;

    @Before
    public void setUp(){
        context = new ClassPathXmlApplicationContext("net/agilejava/jedi/spring/beanLifeCycle/applicationContext.xml");
        bean = (BeanLifeCycleTestBean) context.getBean("test");
    }

    @Test
    public void testBeanNameAware() {
        assertEquals("test", bean.getBeanName());
    }

    @Test
    public void testClassLoaderAware() {
        ClassLoader classLoader = bean.getClassLoader();
        assertNotNull(classLoader);
    }

}

Spring 소스코드에서 BeanClassLoader 인터페이스를 구현한 클레스들입니다.
- AbstractBeanFactory :: configurableBeanFactory 인터페이스 구현체
- AbstractBeanDefinitionReader :: Set the ClassLoader to use for bean classes. Default is null, which suggests to not load bean classes eagerly but rather to just register bean definitions with class names, with the corresponding Classes to be resolved later (or never).
- ConfigurableBeanFactory 인터페이스 :: Set the class loader to use for loading bean classes. Default is the thread context class loader. Note that this class loader will only apply to bean definitions that do not carry a resolved bean class yet. This is the case as of Spring 2.0 by default: Bean definitions only carry bean class names, to be resolved once the factory processes the bean definition.
- AbstractHttpInvokerRequestExecutor
- HttpInvokerTests
This is mainly intended to be implemented by framework classes which have to pick up application classes by name despite themselves potentially being loaded from a shared class loader.
ClassLoader 에 대한 학습이 필요하겠군요. 얼추 보니까 loadClass("풀 패키지 이름 붙은 클레스명") 을 사용하여 Class 객체를 받아 올 수 있습니다. 그 이후에는 리플렉션으로 이어지겠군요.

ClassLoader를 테스트 하기 위해 테스트 코드를 약간 수정했습니다.
    @Test
    public void testClassLoaderAware() throws ClassNotFoundException {
        ClassLoader classLoader = bean.getClassLoader();
        assertNotNull(classLoader);
        Class clazz = classLoader.loadClass("net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean");
        assertEquals(BeanLifeCycleTestBean.class, clazz);
    }

top

Write a comment.


BeanNameAware 테스트

Spring/Chapter 3 : 2007. 5. 9. 01:45


public class BeanLifeCycleTestBean implements BeanNameAware{

    String beanName;

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public String getBeanName(){
        return beanName;
    }

}

위와 같이 BeanNameAware 클레스를 구현해 놓고 다음과 같이 간단히 Bean으로 등록합니다.

<bean id="test" class="net.agilejava.jedi.spring.beanLifeCycle.BeanLifeCycleTestBean" />

테스트 코드를 다음과 같이 작성하고 돌려보면...

public class BeanLifeCycleTest {

    private ApplicationContext context;

    @Test
    public void testBeanNameAware() {
        context = new ClassPathXmlApplicationContext("net/agilejava/jedi/spring/beanLifeCycle/applicationContext.xml");
        BeanLifeCycleTestBean bean = (BeanLifeCycleTestBean) context.getBean("test");
        assertEquals("test", bean.getBeanName());
    }

}

녹색 막대를 확인할 수 있습니다.

이 인터페이스를 구현한 Spring의 소스 코드로는 다음과 같은 것들이 있습니다.
- ServletForwardingController
- AbstractView :: Set the view's name. Helpful for traceability.
- PortletWrappingController
- GenericFilterBean :: Stores the bean name as defined in the Spring bean factory. Only relevant in case of initialization as bean, to have a name as fallback to the filter name usually provided by a FilterConfig instance.
- JobDetailBean
- OsgiServiceProxyFactoryBean :: To find a bean published as a service by the OsgiServiceExporter, simply set this property. You may specify additional filtering criteria if needed (using the filter property) but this is not required.
- AbstractTest
- EhCacheFactoryBean
- FieldRetrievingFactoryBean :: The bean name of this FieldRetrievingFactoryBean will be interpreted as "staticField" pattern, if neither "targetClass" nor "targetObject" nor "targetField" have been specified. This allows for concise bean definitions with just an id/name.

각각의 소스코드 위에 붙어있던 JavaDoc을 보면 설정 파일에서 사용하는 bean 이름을 알면 유용한 경우가 있는 듯 합니다.
- Bean을 추적하거나 찾을 때 사용
- 특정 Bean 이름으로 필터링 할 때 사용합니다.
Interface to be implemented by beans that want to be aware of their bean name in a bean factory. Note that it is not usually recommended that an object depend on its bean name, as this represents a potentially brittle dependence on external configuration, as well as a possibly unnecessary dependence on a Spring API.
Spring API에서 인용한 부분을 보면 빈 설정의 빈 이름에 빈이 종속 되도록 하는 것을 권장하지 않습니다. 이유는 빈이 외부의 설정 파일에 종속되게 되며 이것은 Spring API에 종속되는 거나 마찬가지기 때문이라고 합니다.

top

Write a comment.


3.4.3. The other scopes

Spring/Chapter 3 : 2007. 4. 29. 00:44


2.0에 새로 추가 된 Bean의 Scope들로 request, session, global session이 있습니다. 그리고 이 Scope들은 웹에서 사용하도록 만들어진 것이기 때문에 web-based applicationContext에서만 사용할 수 있습니다. 안그러면 IllegalStateException 이게 발생합니다.

web-based applicationContext 란?
WebApplicationContext 인터페이스를 구현한 클래스들로 다음과 같습니다.
AbstractRefreshablePortletApplicationContext, AbstractRefreshableWebApplicationContext, GenericWebApplicationContext, StaticPortletApplicationContext, StaticWebApplicationContext, XmlPortletApplicationContext, XmlWebApplicationContext
물론 위에서 abstract와 generic(여러 확장 포인트를 제공하기 위해 만든 클래스들)과 static(테스트 용도로 만들어둔 클래스들)을 제외 하면 사실상 XmlPortletApplicationContext, XmlWebApplicationContext 이 두 개가 남습니다.

3.4.3.1. Initial web configuration

새로 추가된 웹 어플리케이션을 위한 scope들을 사용하려면 web.xml에 리스너 or 필터를 등록해야 합니다.

Sevlet 2.4 이상의 버젼을 사용할 때는 아래 처럼 리스너를 등록합니다.
<web-app>
  ...
  <listener>
   <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
  ...
</web-app>

Servlet 2.4 미만의 버젼을 사용할 때는 아래 처럼 필터를 등록합니다.
<web-app>
  ..
  <filter>
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>requestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  ...
</web-app>

3.4.3.2. The request scope

<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>

매 요청 마다 해당 객체를 사용할 수 있으며 각각의 요청은 서로 다른 객체를 가지게 됩니다. 그리고 요청에 대한 처리가 끝나면(컨트롤러에서 해당 메소드가 종료 되면) 더 이상 사용할 수 없습니다.

3.4.3.3. The session scope

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

매 세션 마다 해당 객체를 사용할 수 있으며 각각의 세션은 서로 다른 객체를 가지게 됩니다. 그리고 세션이 닫히면(브라우저를 끄거나 타임오버가 되면) 더 이상 사용할 수 없습니다.

3.4.3.4. The global session scope

<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>

위에서 설명한 session Scope과 동일하며 단지 포틀릿 어플리케이션에서만 사용할 수 있다는 차이가 있습니다. 포틀릿 어플리케이션이 뭔지 모르기 때문에 pass..

3.4.3.5. Scoped beans as dependencies

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <!-- a HTTP Session-scoped bean exposed as a proxy -->
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
         
          <!-- this next element effects the proxying of the surrounding bean -->
          <aop:scoped-proxy/>
    </bean>
   
    <!-- a singleton-scoped bean injected with a proxy to the above bean -->
    <bean id="userService" class="com.foo.SimpleUserService">
   
        <!-- a reference to the proxied 'userPreferences' bean -->
        <property name="userPreferences" ref="userPreferences"/>

    </bean>
</beans>

위와 같이 <aop:scoped-proxy/>를 항상 request, session, globalsession 빈을 만들 때 넣어줘야 합니다.

왜?
보통은 아래 처럼 DI하는 것을 생각할 수 있습니다.
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

하지만 이때 userPreferences 빈은 scope이 session이지만 userManager의 scope이 singletone(default가 singleton이죠.)이기 때문에 문제가 발생합니다. 매 세션 마다 새로운 객체를 만들어 줘야 하지만 저 세션 객체를 사용하는 빈의 생성을 한 번 밖에 안하기 때문에 원하던 대로 동작하지 못합니다.
따라서 매 세션 마다 새로운 객체를 만들어서 줄 프록시를 만들기 위해서 <aop:scoped-proxy/>를 사용합니다.

3.4.3.5.1. Choosing the type of proxy created

<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
    <aop:scoped-proxy proxy-target-class="false"/>
</bean>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

Spring AOP는 프록시 기반이며 프록시를 만들 때 인터페이스를 기반으로 만들 거라면 JDK의 API를 사용하고 클래스 기반으로 만들 때에는 CGLib을 사용합니다.

위에서도 Spring AOP를 사용하고 있고 기본적으로 CGLib을 사용하여 프록시를 만들도록 설정되어 있습니다.

대상이 되는 객체가 어떤 인터페이스를 기반으로 만들어 졌고 JDK의 프록시 API를 사용하고 싶다면 위의 예제 코드 처럼 proxy-target-class 속성의 값에 false 를 넣어 주면 됩니다.

'Spring > Chapter 3' 카테고리의 다른 글

머리 뽀개지는 BeanPostProcessor  (0) 2007.05.09
Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
Circular dependencies  (0) 2007.03.24
연습 문제 풀다가 모르는 것 체크  (0) 2007.03.24
Java Black Belt :: Spring Basic 시험 결과  (0) 2007.03.24
setParentBeanFactory 사용하기  (0) 2007.03.23
ApplicationEvent 사용 예  (2) 2007.03.16
top

  1. Favicon of https://jjaeko.tistory.com BlogIcon 째코 2007.12.14 18:39 신고 PERM. MOD/DEL REPLY

    저는 <aop:scoped-proxy /> 사용할 때 문제가 좀 발생하더군요
    트랙백 걸었습니다.
    아무래도 저 혼자 삽질 하는거 같긴 한데... ㅋㅋ

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2007.12.14 22:27 PERM MOD/DEL

    네 살펴보겠습니다.

  2. Favicon of https://jjaeko.tistory.com BlogIcon 째코 2007.12.15 00:14 신고 PERM. MOD/DEL REPLY

    기선님 글 내용을 약간 수정했습니다. 시간 되실때 보시고 의견좀 주시면 감사하겠습니다.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2007.12.15 12:14 PERM MOD/DEL

    넵 보겠습니다.

  3. Favicon of https://jjaeko.tistory.com BlogIcon 째코 2007.12.15 18:40 신고 PERM. MOD/DEL REPLY

    덕분에 확실히 짚고 넘어가는 계기가 되었네요
    감사합니다

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2007.12.15 20:18 PERM MOD/DEL

    넵. 저도 덕분에 다시 알게 됐습니다. 감사합니다.

Write a comment.


Circular dependencies

Spring/Chapter 3 : 2007. 3. 24. 23:54


참조 : Spring Reference 3.3.1.2의 오른쪽 회색 박스

Circular dependencies[각주:1]는 간단하게 교착상태에 비유할 수 있을 것 같습니다.

Constructor Injection을 사용할 때 발생할 수 있는 문제로 예를 들어 A라는 클래스의 인자로 B 클래스 타입의 객체가 필요하고 B 객체를 만들 때 생성자의 인자로 A 타입의 객체가 필요하다면... 대체.. 어떻게 A와 B를 만들 수 있을까요??[footnote]저런 생성자들만 존재한다는 전제 조건이죠.[/footenote]

이런 경우 BeanCurrentlyInCreationException 이 발생한다고 합니다.

해결책은..Setter Injection을 사용하는거죠. 아니면 다른 객체를 인자로 받아들이는 생성자 말고 다른 생성자를 사용해서 생성하는 방법도 있지만 어차피 속성을 세팅하려면 Setter Injection을 써야겠습니다.

코드로 확인해보죠.

<bean id="employee" class="circularReference.Employee">
    <constructor-arg ref="project" />
</bean>

<bean id="project" class="circularReference.Project">
    <constructor-arg ref="employee"/>
</bean>

@Test public void name(){
        ApplicationContext context =
            new ClassPathXmlApplicationContext("circularReference/circuralContext.xml");
        assertNotNull(context.getBean("project"));
    }

BeanCurrentlyInCreationException의 상위 타입인 BeanCreationException으로 나옵니다. 에러 메시지를 좀 더 읽다보면 보입니다.
사용자 삽입 이미지

아래는 에러 메시지의 Trace입니다.

  1. 이전 글에서 모르겠다고 했던 circular reference를 다르게 IoC챕터 답게 표현한듯... [본문으로]

'Spring > Chapter 3' 카테고리의 다른 글

Bean Life Cycle 통째로 테스트  (0) 2007.05.09
BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
Circular dependencies  (0) 2007.03.24
연습 문제 풀다가 모르는 것 체크  (0) 2007.03.24
Java Black Belt :: Spring Basic 시험 결과  (0) 2007.03.24
setParentBeanFactory 사용하기  (0) 2007.03.23
ApplicationEvent 사용 예  (2) 2007.03.16
MessageSource 사용 예  (0) 2007.03.15
top

Write a comment.


연습 문제 풀다가 모르는 것 체크

Spring/Chapter 3 : 2007. 3. 24. 13:55


It is a good idea to use constructor injection instead of setter injection to evade circular reference. = FALSE
=> evade circular reference. 이게 뭐지..
Circular dependencies

The prototype-scoped beans ignore lazy-init  attribute of bean  element of the wiring configuration file only if the bean is instantiated using plain BeanFactory , not using the ApplicationContext = TRUE
=> 난 false 떙!! 흠... 이 건 알아야 하는데.. 뭐더라..
=> 레퍼런스에서는 ApplicationContext에서 Singletone 빈의 상황에서 설명을 하고 있습니다. 그런데 Prototype 빈의 경우에 BeanFactory에서는 lazy-init이 무시 되나 봅니다. 왜??...

The method used as init-method  cannot be the private one. = TRUE
=> 오.. 모르겠는데;; 답은 private 이여도 되네요..하지만 public으로 해야 Spring IDE에서 읽을 수 있다는 군요.

Enter the name of the attribute of the <ref/> element (spring-beans.dtd) which DOES NOT make XML parser to validate whether Spring bean referenced by such <ref/> element exists in the wiring configuration file. = bean
=> 이건 뭐야;;  답은 bean.. 레퍼런스 3.3.3.2인가.. 3.3.2인가. <ref bean="이름" /> 이렇게 예제가 나와있었네요.

'Spring > Chapter 3' 카테고리의 다른 글

BeanFactoryAware 테스트  (0) 2007.05.09
BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
Circular dependencies  (0) 2007.03.24
연습 문제 풀다가 모르는 것 체크  (0) 2007.03.24
Java Black Belt :: Spring Basic 시험 결과  (0) 2007.03.24
setParentBeanFactory 사용하기  (0) 2007.03.23
ApplicationEvent 사용 예  (2) 2007.03.16
MessageSource 사용 예  (0) 2007.03.15
MessageSource 인터페이스  (2) 2007.03.15
top

Write a comment.


Java Black Belt :: Spring Basic 시험 결과

Spring/Chapter 3 : 2007. 3. 24. 13:48


사용자 삽입 이미지

틀린 문제 정리..

사용자 삽입 이미지
constructor 인자 구별하는 문제였는데 틀렸네요.ㅠ.ㅠ

사용자 삽입 이미지
흠.. 그럼 싱글톤인 빈은 불려지려나..

사용자 삽입 이미지
이런 실수를.. 말장난에 속아버리다니..

사용자 삽입 이미지
흠냐.. 이벤트와 ApplicationCotext 관련 문젠데...틀렸네요.


'Spring > Chapter 3' 카테고리의 다른 글

BeanClassLoaderAware 테스트  (0) 2007.05.09
BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
Circular dependencies  (0) 2007.03.24
연습 문제 풀다가 모르는 것 체크  (0) 2007.03.24
Java Black Belt :: Spring Basic 시험 결과  (0) 2007.03.24
setParentBeanFactory 사용하기  (0) 2007.03.23
ApplicationEvent 사용 예  (2) 2007.03.16
MessageSource 사용 예  (0) 2007.03.15
MessageSource 인터페이스  (2) 2007.03.15
3.8. The ApplicationContext  (0) 2007.03.14
top

Write a comment.


setParentBeanFactory 사용하기

Spring/Chapter 3 : 2007. 3. 23. 02:33


Configuration 간에도 Parent와 Child를 사용할 수 있다는 걸 얼핏 보고 거의 사용하지 않는 다는 문구를 보고 그냥 지나갔었는데 그걸 활용 할 방법을 생각하신 선배님은 정말 엄청난 Spring 매니아 이십니다.

소스코드를 보다가 멋칫 한 건..

1. setParentBeanFactory 라는 메소드를 처음 봤기 때문이였고..
2. 혹시 getFactoryFromClassPath 이것도 이미 존재하는 메소드 인가..
3. ProxyFactoryBean이 자주 쓰이는 구나.. 공부해야겠네..

였습니다.

1. AbstractBeanFactory에 있는 구현 되어 있는 메소드로 ConfigurableBeanFactory 인터페이스에 선언되어 있습니다.

//ConfigurableBeanFactory
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;

//AbstractBeanFactory
public void setParentBeanFactory(BeanFactory parentBeanFactory) {
        if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) {
            throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory);
        }
        this.parentBeanFactory = parentBeanFactory;
    }

2. 만들어 줘야 하더군요. 훔,,근데 여기서 궁금증이 생겼습니다.

    private BeanFactory getFactoryFromClassPath(String resource) {
        return new ClassPathXmlApplicationContext(resource);
    }
왜 이건 안되고.. 아래 것은 될까요..
    private BeanFactory getFactoryFromClassPath(String resource) {
        return new XmlBeanFactory(new ClassPathResource(resource));
    }
 
3. 은.. 벌써 시간이 2시 30분인 관계로.. 내일로 미룹니다.. 어차피 오늘이지만.ㅋ.

'Spring > Chapter 3' 카테고리의 다른 글

BeanNameAware 테스트  (0) 2007.05.09
3.4.3. The other scopes  (6) 2007.04.29
Circular dependencies  (0) 2007.03.24
연습 문제 풀다가 모르는 것 체크  (0) 2007.03.24
Java Black Belt :: Spring Basic 시험 결과  (0) 2007.03.24
setParentBeanFactory 사용하기  (0) 2007.03.23
ApplicationEvent 사용 예  (2) 2007.03.16
MessageSource 사용 예  (0) 2007.03.15
MessageSource 인터페이스  (2) 2007.03.15
3.8. The ApplicationContext  (0) 2007.03.14
'만들 수 없는 것'을 FactoryBean으로 만들기  (2) 2007.03.14
top

Write a comment.


ApplicationEvent 사용 예

Spring/Chapter 3 : 2007. 3. 16. 18:53


ApplicationContext를 중개자 삼아서 Event를 발생시키거나 처리 할 수 있습니다. Event는  ApplicationEvent 클래스를 상속하여 만들 수 있으며 Event를 처리 할 클래스는 ApplicaionListener 인터페이스를 구현하면 됩니다.

Reference에 나와있는 예제는 email을 보낼 때 Black List에 있는 email 주소로는 email을 보내지 않고 BlackListEvent를 발생시키고 이 이벤트가 발생하면 담당자에게 알리도록 하는 핸들러가 작동하게 됩니다.

먼저 ApplicationEvent를 상속하여 BlackListEvent를 만들겠습니다.
import org.springframework.context.ApplicationEvent;

public class BlackListEvent extends ApplicationEvent {

    private String message;

    public BlackListEvent(Object souce, String message) {
        super(souce);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
이 때 ApplicationContext의 생성자가 주의해야 합니다. 인자가 하나인 생성자 하나밖에 없기 때문에 super()를 사용해서 명시적으로 호출해 줘야 합니다.

다음은 ApplicationListener를 구현하는  BlackListEvent를 처리할 BlackListNotifier를 만들겠습니다.
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class BlackListNotifier implements ApplicationListener {

    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof BlackListEvent)
            System.out.println("메일 보내지마~");
    }
}
구현해야 할 메소드는 onApplicationEvent 하나 입니다.

그럼 이제 위에서 만든 BlackListEvent를 특정 상황에서 발생시켜야 하는데요. ApplicationContext의 publishEvent() 메소드를 이용하면 됩니다. 그럼 이벤트를 발생 시킬 클래스에서 ApplicationContext를 알고 있어야 하니까 ApplicationContextAware 인터페이스를 구현해야겠습니다.
ApplicationContextAware 인터페이스를 구현한 EmailBean을 만듭니다.
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class EmailBean implements ApplicationContextAware {

    private List blackList;

    private ApplicationContext ctx;

    public void setBlackList(List blackList) {
        this.blackList = blackList;
    }

    public void setApplicationContext(ApplicationContext ctx) {
        this.ctx = ctx;
    }

    public void sendEmail(String address, String text) {
        if (blackList.contains(address)) {
            BlackListEvent evt = new BlackListEvent(address, text);
            ctx.publishEvent(evt);
            return;
        }
        // send email...
    }
}

이제 BlackListEvent를 실제 발생 시키고 화면에 메시지가 출력 되는지 확인해 봐야 합니다. 그럼 먼저 EmailBean을 context에 등록하고 EmailBean의 blackList에 이벤트를 발생시킬 이메일 주소를 넣어줍니다. 그리고 Event를 핸들링할 bean을 설정해 줍니다.

      <bean id="emailBean" class="event.EmailBean" >
          <property name="blackList">
              <list>
                  <value>monster@email.com</value>
              </list>
          </property>
      </bean>

    <bean id="blackListListener" class="event.BlackListNotifier" />

그리고 이벤트가 발생하는지 확인하기 위해서 monster@email.com으로 간단한 메시지를 날려봅니다. 그럼 화면에는 "메일 보내지마~"라고 출력이 될 것입니다.
        EmailBean emailBean = (EmailBean) bf.getBean("emailBean");
        emailBean.sendEmail("monster@email.com", "I'm gonna kill u");

top

  1. Favicon of http://sehaeng.tistory.com BlogIcon 쌩이~ 2008.11.17 10:12 PERM. MOD/DEL REPLY

    주말에 공부하면서 테스트해보려고 했던건데

    자료 잘읽었습니다.^^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.11.17 11:02 신고 PERM MOD/DEL

    :)

Write a comment.


MessageSource 사용 예

Spring/Chapter 3 : 2007. 3. 15. 21:47


ApplicationContext가 MessageSource 인터페이스를 구현했기 때문에 ApplicationContext를 MessageSource 처럼 사용할 수 있습니다.

greeting에 관한 메시지를 받아 오는 예제를 작성해 보겠습니다.

    @Test public void messageSource(){
        MessageSource messageSouce = bf;
        assertTrue(messageSouce.getMessage("greeting", null, "Default", null).
                equals("It's good to see you"));
    }

테스트는 실패 합니다. 이 테스트를 통과 시키기 위해서는 properties 파일[각주:1]과 간단한 xml 설정이 필요합니다.

먼저 format.properties 파일을 만듭니다.
greeting=It's good to see you

xml에는 다음 과 같이 format.properties 파일을 읽을 수 있도록 설정합니다.
    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
              <list>
                <value>format</value>
              </list>
        </property>
      </bean>

그럼 이제 테스트가 통과 하는 걸 확인 할 수 있습니다. bean의 이름은 항상 messageSource여야 합니다.

이번에는 똑같이 greeting에 관한 메시지를 받아 오지만 Locale을 이용해서 Locale.KOREA와 Locale.ENGLISH를 사용하여 i18n을 해봅니다.

테스트 코드를 다음과 같이 수정합니다.
    @Test public void messageSource(){
        MessageSource messageSouce = bf;
        assertEquals(messageSouce.getMessage("greeting", null, "Default", Locale.ENGLISH)
                ,"It's good to see you");
        assertEquals(messageSouce.getMessage("greeting", null, "Default", Locale.KOREA)
                ,"hi");
    }

properties 파일 이름을 변경하고 하나를 추가합니다.
#format_en.properties
greeting=It's good to see you
#format_ko_KR.properties
greeting=hi

xml 파일은 그대로 두고 테스트를 실행합니다. 테스트는 녹색불이 켜집니다.

format 뒤에 접미어는 Locale 클래스의 상수를 보고 거기에 따라 붙여 줘야 합니다. 그래야 ResouceBundle이 Locale에 따라 적당한 properties파일로 부터 message를 읽어옵니다.

Properties 참조 : http://blog.naver.com/swucs?Redirect=Log&logNo=40007033984
  1. 하나의 번들이라고도 할 수 있겠습니다. [본문으로]
top

Write a comment.


MessageSource 인터페이스

Spring/Chapter 3 : 2007. 3. 15. 08:55


Strategy interface for resolving messages, with support for the parameterization and internationalization of such messages.
MessageSource 인터페이스에 있는 메소드들은 다음과 같습니다.

사용자 삽입 이미지

이 인터페이스를 구현한 클래스들은 다음과 같습니다.
AbstractApplicationContext, AbstractMessageSource, AbstractRefreshableApplicationContext, AbstractRefreshablePortletApplicationContext, AbstractRefreshableWebApplicationContext, AbstractXmlApplicationContext, ClassPathXmlApplicationContext, DelegatingMessageSource, FileSystemXmlApplicationContext, GenericApplicationContext, GenericWebApplicationContext, ReloadableResourceBundleMessageSource, ResourceBundleMessageSource, StaticApplicationContext, StaticMessageSource, StaticPortletApplicationContext, StaticWebApplicationContext, XmlPortletApplicationContext, XmlWebApplicationContext
이 중에서 Reference와 MessageSource 인터페이스 API에서 언급하고 있는 클래스는 세개 입니다.

1. ResourceBundleMessageSource 클래스
JDK의 ResourceBundle 클래스MessageFormat 클래스를 기반으로 만들었으며, 번들들에 특정 이름으로 접근할 수 있는 클래스입니다.

2. ReloadableResourceBundleMessageSource 클래스
JVM 실행 도중 번들들을 다시 읽어 들이는 것이 가능합니다.

3. StaticMessageSource 클래스
MessageSource의 간단한 구현체로 기본적인 국제화를 지원하며 테스트를 위해 만들었습니다.

top

  1. Favicon of http://decoder.tistory.com BlogIcon decoder 2007.03.15 11:04 PERM. MOD/DEL REPLY

    헉! 벌써 4장이시군요. -_-;;
    정말 빠르십니다. :)

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.03.15 11:16 PERM MOD/DEL

    아직 3장이 안끝났어요.ㅋㅋ
    4장은 주말이나 다음주 초에 들어갈 수 있을듯 하네요. :)

Write a comment.


3.8. The ApplicationContext

Spring/Chapter 3 : 2007. 3. 14. 16:27


사용자 삽입 이미지

3.8.1. Internationalization using MessageSources

MessageSource 인터페이스
를 상속하고 있기 때문에 다음의 메소드들을 사용하여 Message를 받아 올 수 있습니다.

ApplicationContext가 로딩 될 때 context에 정의되어 있는 MessageSource를 자동으로 읽어 들입니다. 이때 bean의 이름은 messageSource 여야 합니다.

MessageSource 인터페이스 (2)
MessageSource 사용 예

3.8.2. Events

ApplicationEvent 클래스ApplicationListener 인터페이스를 사용해서 ApplicationContext에서 이벤트 처리를 지원합니다.

ApplicationEvent 사용 예

3.8.3. Convenient access to low-level resources

4장 Resources에서 자세히 다룰 예정이오니 pass.

3.8.4. Convenient ApplicationContext instantiation for web applications

ContextLoader를 사용해서 웹 어플리케이션에서 ApplicationContext를 선언적으로 생성할 수 있다.

일반적으로 ContexLoader를 구현한 ContextLoaderListenerContextLoaderServlet를 다음과 같이 사용합니다. Servlet 2.2 나 2.3 에서는 ContextLoderServlet을 사용해야 합니다.

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- or use the ContextLoaderServlet instead of the above listener
<servlet>
  <servlet-name>context</servlet-name>
  <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
-->

top

Write a comment.


'만들 수 없는 것'을 FactoryBean으로 만들기

Spring/Chapter 3 : 2007. 3. 14. 01:15


Using FactoryBeans to create the ‘uncreatable’ 을 번역한 글입니다.

Carlos SanchezMarc Logemann의 글에 답하기 위해 FactoryBean의 개념과 다수의 FactoryBean이 어떻게 삶을 좀 더 편하게 해주는지 자세히 말해야겠다.

Spring의 FactoryBean은 어떤 종류의 객체라도 ApplicationContext에서 사용할 수 있도록 해준다는 의미에서 간접적인 계층을 추가하는 특별한 bean이다.

Setter-injection과 constructor-injection의 예


먼저 Spring이 객체를 생성하는 ‘평범한’ 방법을 보자. bean들은 보통 default 생성자를 사용하여 만들거나(나중에 setter이용하여 속성에 값을 넣는다.) 특정 XML을 사용하여 생성자의 인자를 사용하여 만든다. 첫 번째 경우는 ‘setter-injection’이라고 부르고 나중의 것은 ‘constructor-injection’이라고 한다. 이 두 방법을 잠시 살펴보자. 다음의 테스트용 bean이 있고 아래에는 두 개의 bean 설정이 있다.
public class TestBean {
  private String name;
  private int age;

  public TestBean() {
  }

  public TestBean(String name) {
    this.name = name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setAge(int age) {
    this.age = age;
  }
}

# normalBeans1.xml
<bean id="setter" class="example.TestBean">
<property name="name" value="Alef [setter]"/>
</bean>

<bean id="constructor" class="example.TestBean">
  <constructor -arg value="Alef [constructor]"/>
</bean>

보시다시피 setter-injection과 constructor-injection을 사용하는 건 쉽다.

Setter-injection과 constructor-injection 섞어 쓰기


원한다면 setter-injection과 constructor-injection을 섞어서 사용할 수도 있다. 따라서 위와 같은 TestBean이 있을 때 다음과 같이 쓸 수 있다.

<bean id="mixed" class="example.TestBean">
  <constructor -arg value="Alef [mixed]"/>
<property name="age" value="27"/>
</bean>

위에 있는 설정은 Spring으로 하여금 먼저 ‘Alef’ 라는 인자를 받는 생성자를 사용하여 TestBean을 만들고 그 후에 age 속성에 값을 (setAge() 메소드를 호출해서)적용한다.

그럼 이제 모든 종류의 객체를 설정하고 생성할 수 있는 방법을 익혔다. 이제 일반적인 JavaBean의 생성자를 가진 객체를 만들 수도 있고 setter와 인자가 있는 생성자를 가지고 객체의 속성에 값을 지정할 수 있는 객체를 만들 수도 있다.

Factory에서 만들어지는 객체와 다른 타입의 객체들

그러나 잠깐만 멈춰봐라! 만약에 객체가 public 생성자를 가지고 있지 않은 경우는 어떤가. 위에서 봤던 방식으로는 도무지 이런 객체를 생성할 방법이 없다. 그리고 또 만약에 어떤 객체가 생성자나 Setter를 가지고는 할 수 없는 부가적인 설정이 필요하다면 역시 객체를 생성할 수 없다.

그래서 FactoryBean이 나타난 것이다!

Spring의 FactoryBean은 그들 스스로가 factory가 되어 BeanFactory에서 사용될 객체들이 구현할 인터페이스다. 만약에 어떤 bean이 FactoryBean 인터페이스를 구현했다면 그 객체는 bean이 아닌 factory로 사용된다.

FactoryBean은 매우 단순한 인터페이스로 세 개의 메소드가 있다:

•   Class getObjectType() – factory가 반환하는 객체의 타입을 알려준다.
•    Boolean isSingleton() – factory가 늘 같은 객체를 반환하는지 아니면 getObject()를 호출 할 때 마다 다른 객체를 호출하는지 알려준다.
•   Object getObject() – 객체를 (만들어) 준다.

간단한 FactoryBean의 구현을 살펴보자.

public class SimpleFactoryBean implements FactoryBean {

  public Class getObjectType() {
    return TestBean.class;
  }

  public boolean isSingleton() {
    return false;
  }

  public Object getObject() {
    return new TestBean("Alef [factory]");
  }
}

# factoryBean2.xml
<bean id="simpleFactoryBean"
  class="example.SimpleFactoryBean"/>

FactoryBean이 실제 어떻게 동작하는지 설명하기 위해서 ApplicationContext에서 bean을 가져오는 API를 사용하겠다. 먼저 ClassPathXmlApplicationContext 클래스를 사용해서 설정 파일들을 읽어 들인다.

ApplicationContext ctx = new ClassPathXmlApplicationContext(
  new String[] {
    "normalBeans1.xml",
    "normalBeans2.xml",
    "factoryBeans1.xml" });

getBean(String name) 메소드를 사용해서 ApplicationContext에서 bean을 가져 올 수 있다. 아래 코드는 예상대로 TestBean을 반환한다.

TestBean tb = (TestBean)ctx.getBean("setter");
assertEquals("Alef [setter]", tb.getName());
tb = (TestBean)ctx.getBean("constructor");
assertEquals("Alef [constructor]", tb.getName());
tb = (TestBean)ctx.getBean("mixed");
assertEquals("Alef [mixed]", tb.getName());

그러나 –이제 FactoryBean이 나올 차례다.- 아래의 코드도 SimpleFactoryBean이 아닌 TestBean을 반환한다. 이전에 정의한 getObejct()에서 반환하도록 되어 있는 객체가 넘어온 것이다.

TestBean tb = (TestBean)ctx.get("simpleFactoryBean");
assertEquals("Alef [factory]", tb.getName());

좀 더 쓸만한 상황

물론 SimpleFactoryBean을 사용해서 TestBean 객체를 가져 오는 것은 너무 단순한 예제이기 때문에 쓸모 없어 보인다. 하지만 어떤 경우에는 오직 FactoryBean만이 극심한 혼란을 없앨 수 있는 방법이 된다. 이제부터 그런 상황들을 살펴보자.

‘희한한’ 곳에서 객체 얻어 오기

DataSources 같은 객체를JNDI에서 가져온다고 생각해보자. DataSource가 JNDI에 설정이 되어 있길 원하기 때문에 그냥 ‘new’를 사용할 수 있다. 따라서 새로운 InitialContext를 만들고 lookup()메소드를 사용해서 JNDI 트리로부터 명시적으로 가져와야 한다. 우린 여전히 DataSource가 Spring의 설정 파일을 통해 DI되길 원하기 때문에 간접적인 계층이 필요하다. FactoryBean이 그 해답을 제공한다. 아래의 FactoryBean을 보자. org.springframework.jndi.JndiObjectFactoryBean을 단순하게 만든 버전이라고 생각하면 된다.

public class JndiObjectFactoryBean implements FactoryBean {

  private String jndiName;

  public void setJndiName(String jndiName) {
    this.jndiName = jndiName;
  }

  public Object getObject() {
    // let's not worry about exceptions
    // and closing the context for now
    Context ctx = new InitialContext();
    return ctx.lookup(jndiName);
  }
}

아래의 XML 몇 조각을 사용하면 DataSource를 묶을 수 있고 다른 bean들이 다시 resort하거나 lookup할 필요 없이 참조할 수 있다. 다시 말하자면 DataSource를 DI할 수 있다! 이 예제는 FactoryBean을 설정해 두었기 때문에 JNDI 위치를 하드코딩 할 필요가 없다. 여기서 DataSource를 설정한 것이 아니라 FactoryBean을 설정했다는 것을 기억하라.

# jndiFactory.xml
<bean class="example.MyDao">
<property name="dataSource ref="myDataSource"/>
</bean>

<bean id="myDataSource" class="example.JndiObjectFactoryBean">
<property name="jndiName"
    value="java:comp/env/jdbc/MyDataSource"/>
</bean>

JavaBeans spec에 맞지 않는 객체

Property 객체를 생각해 보자. Spring에서는 속성들을 <props /> 태그를 사용해서 설정할 수 있다. TestBean 클래스에 Property 객체와 setter를 추가한다면 다음처럼 묶을 수 있다.

<bean class="example.TestBean">
  <!-- results in a call to setPropertiesSetter(props) -->
<property name="propertiesSetter">
<props>
      myName=Alef
      yourName=reader
    </props>
  </property>
</bean>

쉽게 이런 방법을 생각할 수 있다. 하지만 한 가지 단점이 있는데 만약 저기 있는 Property가 하나의 bean이 아닌 다른 여러 곳에서 필요하다면 어떨까. 일반적인 bean 처럼 <ref bean=”xxx”/> 할 수는 없다. In other words, the Properties object passed to the TestBean isn’t a first-class citizen in our Spring application context. 또한 <props /> 엘리먼트를 루트 레벨로 올릴 수도 없다. 또 다시 FactoryBean이 해답이 된다. 아래의 PropertiesFactoryBean(이것도 Spring에 있는 것을 단순하게 만든 버전이다.) 코드를 보자.

public class PropertiesFactoryBean implements FactoryBean {

  private Properties props;

  public void setProperties(Properties props) {
    this.props = props;
  }

  public Object getObject() {
    Properties p = new Properties(props);
    return p;
  }
}

이제 최상위 레벨의 Property 객체를 정의할 수 있게 됐고 다른 Bean들에도 DI할 수 있다.

<bean class="example.TestBean">
  <!-- results in a call to setPropertiesSetter(props) -->
<property name="propertiesSetter" ref="properties/>
</bean>
<bean id="properties" class="example.PropertiesFactoryBean">
<property name="properties">
<props>
      myName=Alef
      yourName=reader
    </props>
  </property>
</bean>

Spring이 제공하는 FactoryBean 에 대한 짧은 리뷰

살펴본 대로, FactoryBean은 일반적인 Spring DI container의 특성으로는 생성하기 힘든 객체를 DI할 때 매우 유용한 중간 계층을 제공한다. FactoryBean는 새로운 InitialContext 객체를 생성하거나 Property를 읽어 들이는 등의 너저분한 코드 작성을 없애준다. Spring을 이미 우리가 살펴본 PropertiesFactoryBean과 JndiObjectFactoryBean같은 유용한 FactoryBean들을 제공하고 있다. 아래에 조그만 설명화 함께 있는 리스트 들이 Spring이 제공하는 다른 FactoryBean들이다.

•    JndiObjectFactoryBean - retrieves JNDI objects from a JNDI context
•    ListFactoryBean - creates List instances (as first-class citizens in a Spring context) where you have the option to specify the type of List you want to use
•    MapFactoryBean - same as the ListFactoryBean but this one creates Maps
•    SetFactoryBean - idem
•    TimerFactoryBean - creates java.util.Timer objects and takes care of all the necessary configuration
•    ServletContextAttributeFactoryBean - retrieves attributes from a ServletContext (works in web-app contexts only
•    WebSphereTransactionManagerFactoryBean - retrieves the WebSphere transaction manager (uses WebSphere proprietary APIs)
•    WebLogicServerTransactionManagerFactoryBean - retrieves the WebLogic transaction manager
•    And many more

ps : 끄트머리는 귀찮아서 번역 안했습니다.;;;
top

  1. 이종민 2007.03.14 12:27 PERM. MOD/DEL REPLY

    좋은 번역 잘 보고 갑니다. ^^*

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.03.14 12:42 PERM MOD/DEL

    넵~ 감사합니다. :)

Write a comment.


BeanFactoryPostProcessor 사용 예

Spring/Chapter 3 : 2007. 3. 13. 16:20


BeanFactoryPostProcessor 인터페이스에는 메소드가 하나 있습니다.

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

이 인터페이스를 구현한 클래스들 입니다.
CustomEditorConfigurer, CustomScopeConfigurer, PreferencesPlaceholderConfigurer, PropertyOverrideConfigurer, PropertyPlaceholderConfigurer, PropertyResourceConfigurer, ServletContextPropertyPlaceholderConfigurer
언제 사용 하면 좋을지는.. 공부를 더 해봐야겠네요.

일단은 Java Developement with Spring 책에 있는 예제[각주:1]를 사용해 보겠습니다.
public class KeesunFactoryPostProcessor implements BeanFactoryPostProcessor {

    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
        System.out.println("The factory contains the followig beans:");
        String[] beanNames = factory.getBeanDefinitionNames();
        for (int i = 0; i < beanNames.length; ++i)
            System.out.println(beanNames[i]);
    }
   
}

설정 파일에 간단하게 bean을 등록 했습니다.[각주:2]
<bean class="beanConfiguration.KeesunFactoryPostProcessor" />

그리고 여태까지 모아둔 테스트 들을 그냥 실행해 봤습니다.[각주:3]

The factory contains the followig beans:
member
혜인
keesun
keesun2
keesun3
keesun4
email
keesun5
email2
keesun6
keesun7
email3
keesun8
keesun9
keesun10
keesun11
keesun12
ticket
keesun13
keesun14
keesun15
beanConfiguration.KeesunPostProcessor
beanConfiguration.KeesunFactoryPostProcessor
콘솔창에 여태까지 Spring Reference 3장에 관한 예제를 만들면서 사용한 bean들의 name이 쭉 찍힌 것을 확인할 수 있습니다.

  1. bean factory가 가지고 있는 모든 bean을 출력하는 BeanFactoryPostProcessor [본문으로]
  2. AppicationContext 를 사용하고 있기 때문에 이렇게만 하면 됩니다. BeanFactory를 사용할 때는 아래 처럼 소스 코드에서 등록을 해줘야 합니다.
    XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("ch03/sample8/beans.xml"));
    AllBeansLister lister = new AllBeansLister();
    lister.postProcessBeanFactory(factory); [본문으로]
  3. 이번에는 따로 test 메소드를 만들지 않고 그냥 콘솔 창에서 테스트 합니다. [본문으로]
top

Write a comment.