PropertyPlaceholderConfigurer는 프로퍼티 파일의 속성을 가지고 ${database.name}과 같은 프로퍼티 값을 바꿔주는 매우 유용한 기능을 가지고 있어서 자주 사용된다. 스프링의 기초정도만 배웠어도 DataSource를 직접 스프링에서 정의하는 할 때 DB연결정보는 프로퍼티 파일로 빼고 ${database.url}과 같은 식으로 쓰라는 것은 한번쯤 들어봤을 것이다.

context 네임스페이스를 쓰면 더욱 정의하기 편하다. 다음과 같이 적어주면 내부적으로 PropertyPlaceholderConfigurer가 만들어지고 모든 ${}로 정의된 빈의 프로퍼티 값을 프로퍼티 파일의 바꿔치기 해준다.

 <context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>

 

프로퍼티 값은 애노테이션을 쓴다면 @Value에 의해서 지정할 수 있다.

그렇다면 다음과 같은 코드도 만들어 볼 수 있지 않을까?

public class BeanSP {

    @Value("#{systemProperties['os.name']}")

    String name;

    @Value("${database.username}")

    String username;

    @Bean

    public PropertyPlaceholderConfigurer databaseProperty() {

        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();

        ppc.setLocation(new ClassPathResource("database.properties", getClass()));

        return ppc;

    }

}

name은 SpEL을 사용해서 다이나믹하게 시스템 프로퍼티 값을 가져온 것이다. SpEL이 알아서 동작하니 신경쓸 건 없고.

두번째 username은 PropertyPlaceholderConfigurer에 의해서 변경되는 전형적인 ${}을 가지고 있으니 적절한 PropertyPlaceholderConfigurer와 프로퍼티 파일만 만들어주면 DB접속이름으로 변경될 것이라고 기대한다.

보통 PropertyPlaceholderConfigurer은 XML에 정의하지만 XML없는 컨텍스트를 사용하기 위해서 @Bean을 붙여 자바코드에 의한 빈 설정 기능을 사용했다. 이제 BeanSP만 빈으로 등록해주면 @Bean이 붙은 databaseProperty() 메소드에 의해서 PropertyPlaceholderConfigurer 타입의 빈이 등록될 것이고 그러면 당연히 username의 값도 변경될 것이라고 기대할 수 있다.

 

그러나 테스트 해보면 ${database.username}은 바뀌지 않는다. 파일도 잘 만들었을 뿐더러 확인해보면PropertyPlaceholderConfigurer 타입의 빈도 정상적으로 등록되어있다. XML로 바꿔서 등록하면 당연히 잘 된다.

그렇다면 @Bean을 사용해서 정의하면 왜 안될까?

 

이를 알려면 PropertyPlaceholderConfigurer @Bean애노테이션이 붙은 클래스를 스프링이 어떻게 처리하는지에 대한 두가지 지식이 모두 필요하다.

이 두가지 기능은 모두 BeanFactoryPostProcessor(BFPP)에 의해서 처리된다. BFPP는 빈 정의가 모두 준비되었을 때 진행하는 빈 팩토리 후처리기이다. 준비된 빈 정의 자체를 어떤 식으로든 바꿔치기 할 수 있기 때문에 상당히 유용하다.

PropertyPlaceholderConfigurer는 프로퍼티 파일의 속성과 빈 정의에 나온 프로퍼티 값을 비교해서 일치하면 프로퍼티 값 정의 자체를 바꿔주는 것이다. 그래서 ${database.name}이 user1과 같은 값 설정으로 바뀌고 나중에 빈을 만들면 이 빈 정의에 따라서 바뀐 값으로 만들어지는 것이다.

@Bean에 의해서 빈이 등록되는 것은 ConfigurationClassPostProcessor(CCPP) BFPP에 의해서 진행된다. 이 BFPP는 한 술 더 떠서 아예 새로운 빈 정의를 추가해준다. BFPP는 빈 정의를 어떤 식으로든 조작할 수 있는 강력한 기능을 가지도록 정의된 것으로 스프링은 이를 이용해서 많은 기능을 확장해왔다. 그래서 이 BFPP가 동작하는 동안에 @Bean이 붙은 빈 정의를 발견하면 그 내용을 토대로 새로운 빈 정의를 추가해준다.

자.. 문제는 BFPP가 실행되는 시점이다.  순서를 잘 보자.

1. 먼저 위의 BeanSP가 빈으로 등록된다. XML이든 스캐닝이든, 직접 주입이든 암튼 컨텍스트의 빈 설정으로 등록된다. 이 때 아직 @Bean에 의해서 CCPP가 만들어지지 않았다.

2. 이미 ConfigurationClassPostProcessor는 등록되어있다. AnnotationConfigApplicationContext라면 초기화 과정에서 추가해줄 것이고, XML이라면 <context:annotation-config>에 의해서 추가되어있을 것이다.

3. 기본 빈 등록이 끝났으므로 등록된 빈 중에서 BFPP를 찾는다. 지금까지 빈으로 등록된 BFPP는 ConfigurationClassPostProcessor뿐이다.

4. 모든 BFPP를 실행한다. 따라서 CCPP가 후처리기로 동작한다. 이 때 @Bean 메소드를 발견하고 PropertyPlaceholderConfigurer 타입의 빈을 등록해준다.

5. 끝.

문제는 3과 4의 순서이다. @Bean에 의해서 등록되는 빈은 이미 3번 과정에서 BFPP를 모두 찾아서 BFPP에 대한 실행이 시작된 이후에 일어난다. 따라서 4번 과정에서 등록된 PropertyPlaceholderConfigurer은 다시 3번으로 돌아가서 컨텍스트가 실행할 BFPP의 후보로 추가될 수 없다.

따라서 PropertyPlaceholderConfigurer는 빈으로 등록되지만 BFPP로 실행되는 시점이 지난 후기 때문에 무용지물이다.

 

결론은 "BFPP 빈은 다른 BFPP(CCPP)에서 등록되게 만들면 안된다".

XML을 사용하지 않으면서 위의 문제를 풀려면 다음과 같이 아예 독립적으로 PropertyPlaceholderConfigurer를 만들어 초기부터 빈으로 바로 등록되게 하면 된다.

@Component

public class DatabasePropertyPlaceHolder extends PropertyPlaceholderConfigurer {

    public DatabasePropertyPlaceHolder() {

        this.setLocation(new ClassPathResource("database.properties", getClass()));

    }

}

비슷한 원리가 BeanPostProcessor에도 적용될 수 있다. BPP에서 빈을 등록할 일은 없겠지만 기존 프로퍼티 내용을 조작하려고 하려면 BPP의 순서를 잘 염두에 둬야 한다.

또, BFPP가 단지 시간순서의 문제라면 BFPP빈의 실행순서를 조정하는 것은 가능하다. priority나 order를 지정하면 우선적으로 실행될 BFPP를 지정할 수 있다.

AC가 빈 등록이후 초기화 하는 작업의 순서를 알고 싶다면 AbstractApplicationContext의 refresh() 메소드를 참고하면 된다. 구체적인 후처리 작업에 대해서는 BFPP와 BPP를 beanFactory에서 가져와 출력해보면 된다. 스프링 초보자가 아니라면 적어도 자신이 만든 설정에 의해서 어떤 BF, Bean 후처리기들이 동작하는지쯤은 알아야 한다.

Related posts:

  1. Inside Spring (6) 애노테이션 설정 지원 스프링 웹 테스트용 DispatcherServlet 만들기
  2. Spring 3.0 (59) 프로퍼티 파일 이용하기 – placeholder vs SpEL
  3. Spring 3.0 (60) 클래스패스 리소스를 지정할 때 주의사항과 팁
  4. 스프링 3.1 (4) Static @Bean 메소드
  5. Spring 3.0 (14) Context Support 모듈의 선택 라이브러리 분석
  6. Spring 3.0 (26) Spring Expression Language와 @Value
  7. Spring 3.0 (33) JavaConfig의 통합과 변신. 메타-빈(meta-bean) 개념의 등장.
  8. Spring 3.0 (13) Context 모듈의 선택 라이브러리 분석
  9. Spring 3.0 (15) Jdbc 모듈의 선택 라이브러리 분석
  10. Spring 3.0 EL (Spel)을 이용한 AssertThrows 확장 (1)
  11. Spring 3.0 (56) @Bean 사용의 주의사항
  12. Spring 3.0 (58) Static Class를 XML없이 빈으로 등록하기
  13. Spring 3.0 (20) Transaction 모듈의 선택 라이브러리
  14. Spring 상식퀴즈 (1) – DI 태클하기
  15. Spring 3.0 (2) R-518 스프링의 새 모듈 OXM(Object/XML Mapping)

Facebook comments:

to “Inside Spring (5) PropertyPlaceholderConfigurer를 @Bean으로 정의해서는 안되는 이유”

  1. although sites we backlink to beneath are considerably not related to ours, we really feel they may be really worth a go by means of, so have a look

  2. Your new valuable essential points imply much someone like me and really more to an workplace workers. With thanks; by everyone of us.

  3. the time to read or check out the content material or websites we ave linked to beneath the

  4. the minute but I have saved it and also included your RSS feeds, so

  5. Wonderful story, reckoned we could combine some unrelated data, nevertheless seriously worth taking a look, whoa did 1 find out about Mid East has got a lot more problerms too

  6. It’s amazing to visit this web site and reading the views of all mates on the topic of this article, while I am also eager of getting know-how.|

  7. I do not even know how I ended up here, but I thought this post was good. I do not know who you are but definitely you’re going to a famous blogger if you are not already ;) Cheers!|

  8. always a large fan of linking to bloggers that I appreciate but do not get a good deal of link really like from

  9. Looking mail to reading added. Enormous article.Really looking to the fore to interpret more. Keep writing.

  10. This very blog is without a doubt awesome as well as factual. I have discovered a lot of handy things out of this amazing blog. I ad love to go back again soon. Thanks a bunch!

  11. you are stating and the best way in which you say it.

  12. the time to study or stop by the content material or internet sites we’ve linked to below the

  13. one of our visitors a short while ago advised the following website

  14. below you will discover the link to some web pages that we consider you’ll want to visit

  15. usually posts some quite fascinating stuff like this. If youre new to this site

  16. one of our visitors not long ago proposed the following website

  17. Fine way of explaining, and fastidious article to get data about my presentation subject, which i am going to convey in university.|

  18. I blog quite often and I seriously appreciate your information. Your article has really peaked my interest. I am going to take a note of your blog and keep checking for new details about once a week. I opted in for your RSS feed as well.|

  19. I’m experiencing several small security difficulties using my latest blog, plus I’d like to locate something safer. Do a person have any suggestions?

  20. Say, you got a nice article post.Much thanks again. Awesome.

  21. Looking forward to reading more. Great blog post. Great.

  22. Looking forward to reading more. Great blog.Really looking forward to read more. Really Great.

  23. sharing in delicious. And naturally, thanks to your effort!

  24. You made some good points there. I looked on the internet for the subject and found most individuals will go along with with your blog.

  25. I value the article post.Much thanks again. Cool.

  26. always a big fan of linking to bloggers that I like but dont get a good deal of link like from

  27. Great blog you have here.. It’s difficult to find excellent writing like yours nowadays. I honestly appreciate individuals like you! Take care!!|

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha