'ITWeb/개발일반'에 해당되는 글 489건

  1. 2012.03.05 [펌] 1장 스프링 시큐리티란?
  2. 2012.03.05 Spring Security 따라하기.
  3. 2012.02.29 Groovy, Gradle plugin
  4. 2012.02.21 Spring Annotation 참고 글.
  5. 2012.02.20 Spring Security PDF
  6. 2012.02.20 maven integration for eclipse jdk warning - eclipse 실행 시
  7. 2012.02.20 eclipse checkstyle 적용하기.
  8. 2012.02.14 삼성애드허브 모바일 웹 광고 붙혀 보기.
  9. 2012.02.14 내 블로그에 애드센스 적용하기
  10. 2012.02.14 문서제목 작성구조 정의

[펌] 1장 스프링 시큐리티란?

ITWeb/개발일반 2012. 3. 5. 17:36

원본글 :  http://springmvc.egloos.com/504862 


드디어 대망의 스프링 시큐리티입니다! 이것이 정녕 막판 보스는 아니지만 현재까지의 개발환경에서 스프링 시큐리티만 어느 정도 가닥이 잡힌다면 웹서비스 제작에 필요한 대부분의 요소는 자리를 잡게 되는 셈입니다. 게다가 스프링 시큐리티는 매우 지능적이며 대부분 간단한 선언만으로 작동하므로 대량의 코드를 손쉽게 절약해줍니다.

그러므로 스프링 시큐리티를 이용하는 것만으로도 고철자물쇠에서 최첨단 10 중 보안장치를 설치하는 것과 동일한 효과를 얻을 수 있겠다 말하겠습니다.
스프링 시큐리티는 강력하면서도 쉽습니다. 게다가 단 몇십줄의 코드만으로도 대형 웹서비스사와 비슷한 수준의 보안을 유지할 수 있다는 장점이 있습니다. 물론 진짜로 비슷한 수준을 유지하려면 적정 수준의 튜닝이 필요하겠지만 그 튜닝의 기반으로 삼기에 스프링 시큐리티는 정말 최상 중 최상의 선택입니다.

한가지 단점은 아직 한국에서 스프링 시큐리티에 대한 활용이 미비한 상태인데다 제대로된 포럼글이나 최신버전에 맞는 설명이 많지 않다는 것입니다. (덕분에 저도 문서를 작성하기 위해 필요한 정보를 찾느라 정말 애먹었습니다. 영어 모르는게 정말 서럽더군요.) 스프링 시큐리티가 ACEGI란 이름으로 시작해, 세상에 나온지 벌써 10년 가까이 됬음에도 아직까지 큰 관심이 없다는 것은 한국이 아직도 웹서비스의 발전이 미미하거나 보안에 대해 크게 간과하면서 많은 관심이 두고있지 않다는 사실일지도 모릅니다.

앞으로 이 포스트는 최소 3부 이상의 기나긴 마라톤 포스트가 될 예정이며 단순히 스프링 시큐리티를 활용하는데 그치지 않고 보안의 기본상식이나 개념에 대해 알아가는 시간이 되도록 할 예정입니다. 

그리고 이건 개인적인 이야기지만 시중에 나온 스프링 시큐리티3란 서적이 있긴 있는데 한글을 읽으면서도 외계어 읽는 듯한 기분을 느끼길 좋아하신다면 구매하셔도 상관은 없습니다… 그런 이유가 아니시라면 개인적으로 구매는 권장하지 않습니다. (현재까지 프로그래밍 서적에서 비추하는 책은 iBATIS 인 액션과 더불어 바로 이 책입니다. iBATIS 인 액션은 개발진이 직접 쓴 책이지만 솔직히 책이 필요없을 정도로 라이브러리가 너무 쉽습니다...;;)


보안이란?
위의 두 단어는 스프링 시큐리티 뿐만이 아니라 일반 보안에서도 핵심 축입니다. 개인적으로 너무나 중요하다 생각되어 하단 한글명에 욕심을 부려보았습니다. 게다가 많은 사람들이 Authentication과 Authorization의 이름이 비슷해 "명사형, 동사형 정도의 차이겠지"라며 착각하실 때가 종종 있는데 두 단어의 뜻은 전혀 다릅니다. 그러므로 글을 읽으시면서 비슷한 단어니까 비슷한 뜻이겠지… 라고 넘어가서는 절대 안됩니다.  한글 발음으로는 아우덴티케이션, 아우토리제이션입니다.

먼저 인증의 종류부터 알아봅시다. 인증에는 여러가지 종류가 있지만 보통 3가지로 분류하곤 합니다.

크리덴셜(Credential:자격) 기반 인증 : 우리가 웹에서 사용하는 대부분의인증 방식은 크리덴션 기반의 인증 방식입니다. 즉 권한을 부여받는데 1차례의 인증과정이 필요하며 대개 사용자명과 비밀번호를 입력받아 입력한 비밀번호가 저장된 비밀번호와 일치하는지 확인합니다. 일반적으로 스프링 시큐리티에서는 아이디를 프린시플(principle)비밀번호를 크리덴셜(credential)이라고 부르기도 합니다.
이중 인증(Two-factor authentication) : 한번에 2가지 방식으로 인증을 받는 것을 말합니다. 예를 들어 금융, 은행 웹어플리케이션을 이용해 온라인 거래를 하실 때에는 로그인과 보안 인증서, 2가지 방법으로 인증을 받곤 합니다. 별 것 아닌 것 같지만 Authentication이 하나 추가됨으로서 프로그래밍 적으로 변화해야 할 부분은 상당히 광범위해집니다.
물리적인 인증 : 이 부분은 웹의 영역을 벗어난 것이지만 가장 효과적인 보안 수단 중에 하나입니다. 예를 들어 컴퓨터를 킬 때 지문을 인식받는다거나 키를 삽입해야 하는 것들 말입니다. 

앞으로 우리가 스프링 시큐리티를 이용해 구현해나갈 인증(Authentication)은 눈치채셨겠지만 바로 크리덴셜(Credential) 인증입니다. 그리고 한가지 말씀드리고 싶은 것은 보안용어에 대해 잘 모르신다면 여기서 나오는 영어 단어들을 유심히 살펴보고 한번씩 써보는 것이 좋습니다.

왜냐하면 이런 용어들이 앞으로 스프링 시큐리티의 클래스, 또는 메서드 명으로 나오게 되며 보안용어에 익숙치 않은 독자는 앞으로 문서를 읽어 나가면서 굉장히 혼란스러울 수도 있기 때문입니다. 그러므로 이런 문제를 미리 방지하기 위해서라도 사전적 의미만으로 표현할 수 없는 보안용어의 참 의미를 미리 숙지할 수 있도록 주의깊게 읽으셔야 합니다.

이제 인증(Authentication)의 종류에 대해 어느 정도 이해가 되셨면 다음은 권한부여(Authorization) 차례입니다. 권한부여에는 크게 2가지로 나뉠 수 있습니다.

부여된 권한(Granted Autority) : 적절한 절차로 사용자가 인증되었다면 권한을 부여(Granted Authority)해야 할 것입니다. 회원가입 등을 통해 반영구적인 권한이 부여됬다면 우리는 이 회원에게 부여된 권한을 어딘가에 저장해야 하구요. 만약 해당 사용자가 로그인을 했는데 메인 페이지로 넘어갈 수 없다면 권한부여에 문제가 있다는 것이겠죠.
리소스의 권한(Intercept) : 사용자의 권한만 있다고 보안이 제대로 동작할리는 없습니다. 보안이란 본래 권한이 없는 자들이 원천적으로 리소스에 접근할 수 없도록 막아내는 것이기 때문입니다. 그런 의미에서 적절한 권한을 가진자만 해당 자원에 접근할 수 있도록 자원의 외부요청을 원천적으로 가로채는 것(Intercept)이 웹보안, 그 중 권한부여(Authorization)의 핵심 원칙이라 할 수 있겠습니다.

위의 보안 용어들은 중요한 개념이라고도 할 수 있지만 한편으로는 골치아픈 해결과제라고도 할 수 있습니다. 즉 우리가 위와 같은 주요 개념들에 입각해 구현해야 할 보안을 생각해본다면 일단 우선적으로 "어떤 방식으로 권한을 부여할까?""해당 리소스에 어떻게 권한수준을 부여하지?""인증받은 사람은 어떻게 인증받았다는 정보를 지속적으로 유지할 수 있을까?"와 같은 골치아픈 과제들이 산더미같이 존재할 수 있을 것입니다. 게다가 문제들을 해결하는 것도 힘든 일이지만 일을 더욱 더욱 어렵게 만드는 것은 보안이 아무리 잘해도 티 안나고 한번만 실수해도 독박은 다 뒤집어쓰는 전업주부 방식의 프로그래밍 분야이라는 것입니다.

그러므로 위와 같은 문제들의 올바른 해결을 위해서라도 스프링 시큐리티의 손을 한번 더 들어주고 싶어집니다. 스프링 시큐리티는쉽고 편리하다는 장점도 있지만 이런 보안 개념이 없는 자가 보안이 필요한 쇼핑몰이나 주요 웹사이트를 설계했다고 가정했을 때 발생할 막대한 피해들을 방어할 수 있는 최선의 선택입니다. 스프링 시큐리티는 이런 과제들을 거의 10년 가까이 연구하며 발전해온 뛰어난 보안 프레임워크라는 점을 볼 때 우리에게 스프링 시큐리티는 선택이 아니라 필수라고도 할 수 있습니다.

이제 보안의 핵심용어와 스프링 시큐리티의 중요성에 대해 어느 정도 설명했으니 스프링 시큐리티에 대해 좀 더 깊이 들어가 발생하는 문제에 어떤 해결방식을 선택했는지 차근차근 집어나가보려고 합니다.

리소스의 권한(Intercept)

리소스의 권한이 영어로 Intercept가 아니라는 것쯤은 저도 스타크래프트를 조금 해봤으므로 알고 있습니다. 그럼에도 Intercept라는 말을 리소스 권한 옆에 당당히 붙여놓는 것은 보안에서 리소스에 접근권한을 설정하는 것이 바로 Intercept 방식으로 작동하고 있기 때문입니다. 아무리 서버 성능이 좋고 직원이 많더라도 우리가 가지고 있는 모든 리소스에 일일이 권한을 설정할 수는 없는 노릇입니다.대신에 우리가 @MVC에서 보았듯 DispatcherServlet처럼 멋지게 클라이언트의 요청을 가로챌 수만 있다면 간단히 문제를 해결할 수 있을 것입니다.

개인적으로 @MVC의 개발에 간접적으로나마 스프링 시큐리티가 많은 공헌을 하지 않았을까 생각하는데 그 이유는 스프링 시큐리티가 이미 ACEGI 때부터 Filter를 이용해 클라이언트의 요청을 가로채는 하는 방식을 굉장히 오래 전부터 개발해놨었기 때문입니다. (Spring Security는 스프링 커뮤니티에 합류하기 전까지 Acegi라는 이름의 프레임워크였습니다. 이름이 Acegi인 이유는 13579순서대로 알파벳을 정렬했다고 하는군요.) 그렇기 때문에 스프링 시큐리티는 @MVC의 DispatcherServlet이나 AOP를 이용해 프록시를 생성하지 않고 아주 오래 전부터 사용해온 고유의 DelegatingFilterProxy 클래스를 사용합니다. 물론 DelegatingFilterProxy를 이용하면서도 AOP 포인트컷의 활용 또한 가능합니다.

먼저 기존의 제작된 프로젝트에 다음과 같이 web.xml에 DelegatingFilterProxy를 등록해 봅시다.
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/-</url-pattern>
</filter-mapping>

여기서 주의할 점은 <filter-name>의 값이 반드시 springSecurityFilterChain이어야 한다는 점입니다. 왜 꼭 이름을 springSecurityFilterChain으로 지어야 하냐면 DelegatingFilterProxy 클래스는 setTargetBeanName(String)이라는 메서드를 갖고 있는데 이 메서드는 실제 요청을 처리할 필터를 주입받습니다. 만약 이 메서드를 통해 구현할 필터빈을 주입받지 못한다면 DelegatingFilterProxy 클래스는 기본값으로 <filter-name>의 값과 동일한 빈이 스프링 컨텍스트에 존재하는지를 검색하게 됩니다.

그러나 곧 알게 되겠지만 DelegatingFilterProxy 클래스가 springSecurityFilterChain이란 빈이 필요하다고 직접 빈을 만들어줄 필요는 없습니다. 왜냐하면 springSecurityFilterChain은 스프링 시큐리티의 inner bean이기 때문에 자동으로 생성되기 때문이죠.


이런 관점에서 본다면 DelegatingFilterProxy는 굳이 스프링 시큐리티 에서만 사용할 게 아니라 다른 목적의 필터 체인으로도 충분히 사용될 수 있는 확장성이 존재합니다. 아마 스프링 제작진들도 이 클래스가 스프링 시큐리티에서 탄생했지만 역할의 중요성을 인식해 시큐리티 내부 패키지에 위치시키지 않고 org.springframework.web.filter에 등록시킨 것 같습니다.

아마 이쯤되면 어떤 예리한 독자 분이 "DispatcherServlet이 이미 모든 요청을 가로채는데 또 DelegatingFilterChain이 가로채면 우선순위는 어떻게 결정되나요?" 라는 질문을 던지실 수도 있겠군요. 정답만 이야기하자면 필터가 우선순위가 됩니다. web.xml을 보면 알다시피 DispatcherServlet은 서블릿으로 등록되있고 DelegatingFilterChain은 필터로 등록되어 있습니다. 만약 이런 상황에 서로 겹치는 URL이 요청으로 들어온다면 필터는 프록시 패턴처럼 서블릿을 샌드위치 해버립니다. 이런 점에서 본다면 우리는 왜 DelegatingFilterChain이 필터로 만들어졌으며 DispatcherServlet이 왜 서블릿으로 만들어졌는지 이해할 수도 있겠죠.

이제 필터를 이용해 모든 URL이 DelegatingFilterProxy를 통과하도록 설정했다면 컨텍스트를 설정할 차례입니다. 보안에 대해서 따로 관리해줄 컨텍스트 파일을 만드는 것이 좋으므로 security-context.xml이란 파일을 새로 만들도록 합시다. 그리고 완성된 빈은 web.xml에 등록하는 것도 잊지 말구요. 여기까지 완료하시면 스프링 시큐리티를 사용하기 위한 기본 세팅은 마무리 됩니다.

어떠셨나요? 글을 읽으시면서 어느 정도 보안에 대해 감이 오시나요? 만약 아무리 읽어도 감이 오지 않는다면 스스로 의문을 만들고 그 답을 찾아보도록 노력해보세요. 개인적으로 스프링 시큐리티 API문서를 찾아보시길 권장합니다 ^^; 그럼 글이 길어지는 관계로 이번 장에선 보안의 기본원리와 스프링 시큐리티의 기본 세팅까지 다루고 다음 장부터 본격적으로 security-context.xml을 이용한 보안설정을 다루도록 하겠습니다. 여기까지 읽어주셔서 감사하구요. 좋은 하루 되세요 :D


:

Spring Security 따라하기.

ITWeb/개발일반 2012. 3. 5. 11:43
[원본링크]

[원본글]

THURSDAY, MARCH 17, 2011

Running Spring Security's Tutorial Sample in Spring Tool Suite

Note
Note: Vote on these JIRA's if you would like STS to be able to import Spring Security without use of the command line. 
Introduction

This blog will teach you how to run the sample applications/tests for Spring Security 3.1.x in STS. It is assumed that you have already installedSTS. Since STS is a flavor of Eclipse, the process for doing this in Eclipse is similar.

The main goal is to demonstrate how to setup a workspace with STS. In later posts I will describe how to run the other sample applications within STS. Once you can run Spring Security in an IDE, I will describe how to contribute back to Spring Security.

Screencast

If you want to see this in action, you can view the screen cast too.

STS Setup

Spring Security uses git to manage the source code. There are quite a few different git clients to choose from, but in this blog I will demonstrate how to obtain the source using EGit.

Some of the tests are written in Groovy. If you want to run the tests, you will need to install the Groovy Eclipse plugin.

To install the plugins:
  • Open up STS to a new workspace
  • You should see an option to Open Dashboard
  • At the bottom of the Dashboard View select the Extensions tab
  • In the Find box type in EGit and select the check box next to it
  • In the Find box type in Groovy Eclipse and select the check box next to it
  • Click the Install button in the lower right
  • Follow the instructions on any dialogs that pop up
  • After everything is installed, restart STS
Checking Out the Source Code
  • Once STS starts back up navigate to File->Import->Git->Projects from Git
  • Click the Clone... button
  • Fill out the URI with git://github.com/SpringSource/spring-security.git
  • Click the Next button to view the branches for this repository
  • Ensure that all the branches are selected
  • Click the Next button again to clone all the branches
  • Accept all the defaults and click the Finish button
  • The repository will be cloned and the local location will be displayed next to it
  • Remember the path to the repository as the Destination Directory
Generating the Eclipse Configuration Files
  • Open up a command prompt and navigate to the Destination Directory from the previous step
  • When using EGit, I have to add the execution bit the gradle wrapper. Since this does not happen when I use git from the command line, I suspect it is an EGit bug. To change the permissions in a Linux environment execute chmod +x gradlew from the command line.
  • Linux/Mac users run ./gradlew eclipse
  • Windows users run .\gradlew.bat eclipse
  • Gradle will automatically be downloaded, installed, download the required dependencies, and then the Eclipse configuration will be generated
Importing the Projects
  • Navigate back to Eclipse and click the Next button
  • Ensure Import Existing Projects is selected
  • Click the Next button
  • Click Select All
  • Click the Finish button
  • The project will be imported and there should be no errors.
Running the Code

At this point you should be able to run all of the unit tests by right clicking the project and navigating to Run As -> JUnit Tests. Of course that is not all that fun, so instead we will run the tutorial sample on tc Server. To run the tutorial follow these steps:
  • Right click spring-security-samples-tutorial and select Run As -> Run on Server
  • Select Finish
  • When prompted if you want to enable Spring Insight click No
  • The application will be opened up in Spring Tool Suite
  • When prompted to login, you can use the users defined in spring-security-samples-tutorial/src/main/webapp/WEB-INF/applicationContext-security.xml (i.e. rod / koala)

What Next?

You can read about Running Spring Security's CAS and PreAuth Samples in STS


[위와 같이 했을 경우 발생 하는 문제]

SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener

java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener

at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1678)

at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1523)

at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:415)

at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:397)

at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:118)

at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4660)

at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)

at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)

at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

at java.util.concurrent.FutureTask.run(FutureTask.java:138)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:619)

08.11.2011 15:23:30 org.apache.catalina.core.StandardContext listenerStart

SEVERE: Error configuring application listener of class org.springframework.security.web.session.HttpSessionEventPublisher

java.lang.ClassNotFoundException: org.springframework.security.web.session.HttpSessionEventPublisher

at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1678)

at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1523)

at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:415)

at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:397)

at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:118)

at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4660)

at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5226)

at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5221)

at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

at java.util.concurrent.FutureTask.run(FutureTask.java:138)

at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

at java.lang.Thread.run(Thread.java:619)

- 이와 같은 에러는 classpath 상에 spring-web 관련 jar 파일이 없어서 발생을 합니다.
- classpath 를 살펴 보니 정상적으로 path 등록이 되어 있으나 에러가 발생 할 경우.
- 아래 경로에 spring-web 관련 jar 파일들을 복사해서 넣어 주시면 됩니다.

[Spring Security Samples tutorial 의 lib Path확인]

D:\Development\Workspace_SpringSource\.metadata\.plugins\org.eclipse.wst.server.core\
tmp0\wtpwebapps\spring-security-samples-tutorial\WEB-INF\lib

- workspace
D:\Development\Workspace_SpringSource\  

- 해당 경로에 실제 spring web 관련 jar 파일이 존재 하지 않아 위와 같은 에러가 발생을 하였습니다.
- 아래 파일들을 복사후 tomcat start 시 정상 동작 합니다.

[jar 파일 복사]


- 어떤 파일을 복사 해야 할지 잘 모를경우, 그냥 spring mvc 프로젝트 하나 생성 하셔서 빌드 하신 후 해당 lib 경로에 들어 있는 파일들을 몽땅 복사해서 넣으시면 됩니다.
:

Groovy, Gradle plugin

ITWeb/개발일반 2012. 2. 29. 10:43

To enjoy editing your build.gradle files and running tasks using Eclipse IDE do the following:



http://groovy.codehaus.org/Eclipse+Plugin
 

For Eclipse 4.2 (Snapshot builds only):

http://dist.codehaus.org/groovy/distributions/greclipse/snapshot/e4.2/ 

For Eclipse 3.7:

http://dist.springsource.org/release/GRECLIPSE/e3.7/

For Eclipse 3.6:

http://dist.springsource.org/release/GRECLIPSE/e3.6/

For Eclipse 3.5:

http://dist.springsource.org/release/GRECLIPSE/e3.5/

For Eclipse 3.4.2 (development build only and not really recommended except for the poor souls who are stuck using Eclipse 3.4):

http://ci.repository.codehaus.org/greclipse/snapshot/e34/


:

Spring Annotation 참고 글.

ITWeb/개발일반 2012. 2. 21. 10:44
내가 이해 하고 있는게 맞는지 확인하기 위해서 관련 글들을 찾아 보던 중..
쉽게 정리된 글이 있어 올려 봅니다.

기초가 중요 하다는건.. 언제봐도 진리 인듯 합니다. ^^;



스프링 2.5가 드디어 릴리즈 되었네요.
좀 천천히 관심 둘 여유있을 줄 알았는데... 플젝 투입되어 있어서 정신이 없습니다.

19일, 인포큐에 스프링 2.5의 새로운  부분에 대한 글이 올라왔었습니다.
 
http://www.infoq.com/articles/spring-2.5-part-1

그냥 이런게 올라왔었구나... 나중에 읽어야지.. 하고 미뤄두었었는데 릴리즈도 된 마당에 대충이라도 읽어봤습니다.

2.0에서 XML 스키마 지원으로 스프링을 즐겁게 쓰도록 만들어 주었었는데... 이번에는 더욱 단순하고 강력한 스프링이 되었다고 하네요. 2.0은 2.5로 가기 위한 맛보기...ㅎㅎ

개인적으로 어노테이션을 통한 설정이 생각 만큼 생산성을 높여줄지에 대해서는 의문이지만 XML를 끔찍하게 여기는 사람들이 많기 때문에 매우 환영할만 하다고 생각합니다.

이왕 글을 쓴거 위 글의 내용을 약간 요약해보겠습니다. infoq에 기고된 글의 저작권이 어찌되는지 모르지만 요약 정도는 상관 없겠죠?

이 글은 총 3회에 나눠서 쓰여질 기고문의 첫번째에 해당합니다. 주로 어노테이션과 관련된 부분에 대해서 설명하고있구요.두번째 글은 Web Tier 쪽을, 마지막 글은 통합과 테스팅에 관련된 기술을 논하려고 한답니다. 아마도 두번째는SpringMVC를 마지막은 JUnit 4 지원과 OSGi가 될 듯 하네요.

JSR-250 어노테이션 지원

스프링 2.5에 새로 지원하는 어노테이션은 다음과 같다고 합니다.
  • @Resource
  • @PostConstruct
  • @PreDestroy
@Resource

DI를 위해서 사용합니다. 
빈 컨테이너 안의 빈들 중에서 지정된 이름의 빈을 찾아서 DI를 해줍니다. 아래 예에서라면 스프링은 관라하는 빈들 중 이름이 dataSource인 놈을 가지고 setDataSource()를 호출하는거죠.
@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
직접 맴버 변수에 지정할 수도 있는데 이렇게 하면 setter 없이도 DI가 된다네요. 요거 맘에 듭니다. 

@Resource
private DataSource dataSource; // inject the bean named 'dataSource' 

위의 예에서 처럼 이름을 지정하지 않으면 변수 이름이 자동으로 사용되네요. 아래처럼 setter 메소드에 이름 없이 지정 할 수도 있다고 합니다.
private DataSource dataSource;
@Resource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
이름으로 빈을 찾았는데 없으면 타입으로 찾아서 인젝션 해준답니다. 원하지 않으면 이 기능을 끌 수도 있습니다.

Lifecycle 어노테이션 @PostConstruct와 @PreDestory

기존에 빈 생성시 빈을 초기화하고 소멸시 정리하는 작업을 하려면 InitializingBean과 DesposableBean 인터페이스를 상속하거나 빈설정시 명시적으로 초기화 메소드와 정리 메소드를 지정해 주었어야 합니다.
인터페이스를 사용하면 자동화 되어 좋기는 하지만 스프링 디펜던시가 생기고 - 솔직히 이 빈을 다른 곳에서 쓸 일이 얼마나 있겠냐만 늘 결벽증 때문에 사용안하게 된다죠 - 그래서 설정을 주로 사용하곤 했습니다.

사용은 간단합니다. 초기화 메소드와 정리 메소드 위에 각 어노테이션을 표기만 하면 되는거죠.

public class FilePoller {

@PostConstruct
public void startPolling() {
...
}
...

@PreDestroy
public void stopPolling() {
...
}
...

늘 XML 설정 할 때 마다 빼먹을까봐 신경 썼었는데 좋네요.

정밀한 오토와이어링

2.5 이전에도 여러가지 오토와이어링 방법을 제공했습니다. 컨스트럭터, 셋터의 타입, 셋터의 이름, 자동인식.... 하지만 전체적으로어떤 것을 선택할지 설정 할 수는 있어도 어떤 경우에는 타입으로 찾고 어떤 경우에는 이름으로 찾을지 정밀하게 제어 할 수는 없었습니다.

위에서 말한 것 처럼 2.5에서는 @Resource 어노테이션으로 메소드별 필드별로 이름 기반의오토와이어링을 지정 할 수 있게 되었습니다. 하지만 이건 제약이 있어 스프링 2.5에서는 @Autowired 어노테이션을추가했다고 합니다. 이건 비표준인거죠. 스프링 디펜던시가 생깁니다.

@Autowired 어노테이션은 컨스트럭터, 메소드, 필드에 사용하며 타입으로 오토와이어링 하도록 지정하는 기능을 가지고 있습니다. 그런데 메소드가 꼭 셋터일 필요는 없습니다. 심시어 패러미터가 여러개인 경우도 상관 없답니다. 오호...
@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

기본적으로 이 어노테이션으로 표시된 항목은 필수인 것으로 처리되지만 required 옵션을 false로 하면 빈을 못 찾아도 그냥 넘어갑니다. 예를 들어 다음에서 빈을 못찾으면 그냥 하드코딩한 DefaultStrategy가 사용되는거죠.

@Autowired(required=false)
private SomeStrategy strategy = new DefaultStrategy(); 

이렇게 타입으로 빈을 찾는데 해당 타입의 빈이 하나 이상일 경우 스프링은 오토와이어링이 실패한 것으로 처리합니다. 이 문제를 해결하기 위한 몇가지 방법이 있습니다. 우선 빈 설정에서 primary 속성을 사용하는 방법이 있다.

<bean id="dataSource" primary="true" ... /> 

이번 2.5에는 보다 정밀한 제어가 가능한데 @Qualifier 어노테이션을 사용하면 빈 이름을 지정할 수 있다. 타입이 아닌 이름으로 찾게 됩니다.

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource; 

이 어노테이션을 별도로 만든 이유는 다음 처럼 사용할 수 있게 하려는 것이라네요. 머리도 좋아요. 이 어노테이션은 컨스트럭터 매개변수, 필드, 메소드 매개변수 어디에도 쓸 수 있답니다.

@Autowired
public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o) { ... } 

이 뿐 아니라 커스텀 어노테이션을 사용한 인젝션에도 사용될 수 있다는데요. 요건 읽기 귀찮아서 일단 PASS...

스프링 컴포넌트 자동 인식

스프링 2.0부터 스테레오 타입 개념의 어노테이션이 도입되었습니다. @Repository는 데이타 억세스 코드라는 표시를 하는 어노테이션으로 사용된 것이죠.
2.5에는 일반적인 3-Tier 아키택쳐에서의 역활을 표기하기 위해 @Service와 @Controller라는 어노테이션을 추가했습니다. 이와 함께 제너릭 어노테이션인 @Component도 추가...

이들 어노테이션들은 객체에 역할을 부여해서 AOP나 후처리기가 뭔가 추가적인 작업을 하도록 해줍니다.

이 어노테이션들로 사용할 수 있는 새 기능 중 하나가 컴포넌트 자동 인식 기능... 오토와이어링을 쓰더라도 기본적인 빈 설정을 해주었어야 했지만 이 컴포넌트 자동 탐색 기능을 쓰면 이 기본적인 빈 설정 조차 필요없게 됩니다.

2.5의 PetClinic 샘플을 보면 하부구조에 해당하는 컴포넌트들은 XML에 설정이 되어 있지만 Web Tier 컨트롤러들은 자동 인식 기능을 사용하도록 되어 있다는군요. 저도 처음 이 기능을 들었을 때에 Web Tier에 적용하면 좋겠다고 생각되더군요. XML의 명시적이고 중앙집중적인 특징도 무시는 못하죠. 개발할 때에는 편의상 오토와이어링을 쓰더라도 운영환경에서는 XML이 역시... 혹시 새로 생긴 자동 탐색 기능과 오토와이어링 기능으로 구성된 빈 컨테이너의 내용을 XML로 생성해주는 방법이 있다면 좀 알려주세요.

<context:component-scan base-package="org.springframework.samples.petclinic.web"/> 

이렇게 지정된 패키지 안의 클래스들을 탐색해서 스테레오타입이 지정된 클래스들을 찾아냅니다. 예를 들면 이런 Spring MVC 컨트롤러...

@Controller

public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
... 

탐색 규칙을 커스터마이제이션 할 수도 있습니다. 다음과 같이 하면 스테레오 타입을 찾는 기본 룰은 사용하지 않고 Stub로 시작하는 클래스들과 Mock 어노테이션이 되어 있는 클래스들을 스프링 객체로 인식하게 할 수 있습니다.

<context:component-scan base-package="example" use-default-filters="false">
<context:include-filter type="aspectj" expression="example..Stub*"/>
<context:include-filter type="annotation" expression="example.Mock"/>
</context:component-scan> 

기본 탐색 규칙을 조정 할 수도 있습니다. 아래 예는 탐색시 @Repository 어노테이션을 제외시킵니다.

<context:component-scan base-package="example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan> 

 물론 커스텀 어노테이션을 탐색에 사용하게 할 수도 있습니다. @Generic 제넥릭 어노테이션으로 다음과 같이 커스텀 어노테이션에 @Generic 어노테이션을 사용하면

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
String value() default "";


이 어노테이션이 지정된 객체들은 모두 스프링 객체로 인식이 됩니다.

@BackgroundTask
public class FilePoller {

@PostConstruct
public void startPolling() {
...
}

@PreDestroy
public void stopPolling() {
...
}
...


이렇게 자동 인식된 빈들은 클래스 이름으로 등록이 됩니다. 위의 예에 나오는 FilePoller 클래스는 filePoller라는 이름으로 스프링에 등록되는거죠. 만약 다른 이름을 원하면 이렇게 합니다.

@Service("petClinic")
public class SimpleJdbcClinic {
...


기본적으로 스프링은 빈을 싱글톤으로 관리하지만 다른 스코프를 써야 할 경우도 있습니다. 이 경우는 요렇게...

@Component
@Scope("session")
public class ShoppingCart {
...


전 지금 진행중인 프로젝트에 2.5를 적용할 예정입니다. 원래 아발론으로 만들어진 서버 프로그램인데 스프링으로 바꾸고 있거든요. 

프로그래밍이 즐거워지네요. ㅎㅎ

아! 아시겠지만 제가 잘못 이해해서 생긴 오류에 대해서는 책임 안집니다. ;;; 



Introduction

Since its inception the Spring Framework has consistently focused on the goal of simplifying enterprise application development while providing powerful, non-invasive solutions to complex problems. With the release of Spring 2.0 just over a year ago, these themes advanced to a new level. XML Schema support and custom namespaces reduce the amount of XML-based configuration. Developers using Java 5 or greater are able to take advantage of Spring libraries that exploit new language features such as generics and annotations. The close integration with AspectJ's expression language enables the non-invasive addition of behavior across well-defined groupings of Spring-managed objects.

The newly released Spring 2.5 continues this trend by offering further simplifications and powerful new features especially for those who are using Java 5 or greater. These features include annotation-driven dependency injection, auto-detection of Spring components on the classpath using annotations rather than XML for metadata, annotation support for lifecycle methods, a new web controller model for mapping requests to annotated methods, support for Junit 4 in the test framework, new additions to the Spring XML namespaces, and more.

This article is the first of a three-part series exploring these new features. The current article will focus on simplified configuration and new annotation-based functionality in the core of the Spring application context. The second article will cover new features available in the web-tier, and the final article will highlight additional features available for integration and testing. Most of the examples depicted within this article series are based upon the Spring PetClinic sample application. That sample has recently been refactored to serve as a showcase of the latest Spring functionality and is included within the Spring 2.5 distribution available at the Spring Framework Download page. View the 'readme.txt' file within the 'samples/petclinic' directory for instructions on building and deploying the PetClinic application. Experimenting with the showcased features in the PetClinic application is probably the best way to master the new techniques discussed here.

Spring support for JSR-250 annotations

The 'Common Annotations for the Java Platform' were introduced with Java EE version 5 and are also included out-of-the-box beginning with Java SE version 6. In May 2006, BEA Systems announced their collaboration with Interface21 on a project called Pitchfork that provided a Spring-based implementation of the Java EE 5 programming model including support for JSR-250 annotations and EJB 3 annotations (JSR-220) for injection, interception, and transactions. As of version 2.5, the Spring Framework core now provides support for the following JSR-250 annotations:

  • @Resource
  • @PostConstruct
  • @PreDestroy

With Spring these annotations are supported in any environment - with or without an Application Server - and even for integration testing. Enabling this support is just a matter of registering a single Spring post-processor:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/> 

The @Resource Annotation

The @Resource annotation enables dependency injection of a "named resource". Within a Java EE application, that typically translates to an object bound to the JNDI context. Spring does support this usage of @Resource for resolving objects through JNDI lookups, but by default the Spring-managed object whose "bean name" matches the name provided to the @Resource annotation will be injected. In the following example, Spring would pass a reference to the Spring-managed object with a bean name of "dataSource" to the annotated setter method.

@Resource(name="dataSource")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

It is also possible to annotate a field directly with @Resource. By not exposing a setter method, the code is more concise and also provides the additional benefit of enforcing immutability. As demonstrated below, the @Resource annotation does not even require an explicit String value. When none is provided, the name of the field will be used as a default.

@Resource
private DataSource dataSource; // inject the bean named 'dataSource'

When applied to a setter method, the default name would be derived from the corresponding property. In other words, a method named'setDataSource' would also resolve to the property named 'dataSource'.

private DataSource dataSource;
@Resource
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

When using @Resource without an explicitly provided name, if no Spring-managed object is found for the default name, the injection mechanism will fallback to a type-match. If there is exactly one Spring-managed object matching the dependency's type, then it will be injected. This feature can be disabled by setting the 'fallbackToDefaultTypeMatch' property of the CommonAnnotationBeanPostProcessor to 'false' (it is 'true' by default).

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="fallbackToDefaultTypeMatch" value="false"/>
</bean>

As mentioned above, Spring does provide support for JNDI-lookups when resolving dependencies that are annotated with @Resource. To force direct JNDI lookups for all dependencies annotated with @Resource, set the 'alwaysUseJndiLookup' flag of theCommonAnnotationBeanPostProcessor to 'true' (it is 'false' by default).

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="true"/>
</bean>

Alternatively, to enable lookup based upon global JNDI names specified as 'resource-ref-mappings', provide the 'mappedName' attribute within the@Resource annotation. Even when the target object is actually a JNDI resource, it is the recommended practice to still reference a Spring-managed object thereby providing a level of indirection and hence a lesser degree of coupling. With the namespace additions available since Spring 2.0, a bean definition that delegates to Spring for handling the JNDI lookup is trivial and concise:

<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic"/> 

The advantage of this approach is that the level of indirection provides for greater deployment flexibility. For example, a standalone system test environment should not require a JNDI registry. In such a case, the following alternate bean definition could be provided within the system test configuration:

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>

As an aside, in the example above the actual JDBC connection properties are resolved from a properties file where the keys match the provided ${placeholder} tokens. This is accomplished by registering a Spring BeanFactoryPostProcessor implementation calledPropertyPlaceholderConfigurer. This is a commonly used technique for externalizing those properties - often environment-specific ones - that may need to change more frequently than the rest of the configuration.

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>

With the addition of the 'context' namespace in Spring 2.5, a more concise alternative for the property placeholder configuration is available:

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

Lifecycle Annotations: @PostConstruct and @PreDestroy

The @PostConstruct and @PreDestroy annotations can be used to trigger Spring initialization and destruction callbacks respectively. This feature extends but does not replace the two options for providing such callbacks in Spring versions prior to 2.5. The first option is to implement one or both of Spring's InitializingBean and DisposableBean interfaces. Each of those interfaces requires a single callback method implementation (afterPropertiesSet() and destroy() respectively). The interface-based approach takes advantage of Spring's ability to automatically recognize any Spring managed object implementing those interfaces and therefore requires no additional configuration. On the other hand, a key goal of Spring is to be as non-invasive as possible. Therefore instead of implementing Spring-specific interfaces, many Spring users have taken advantage of the second option which is to provide their own initialization and destruction methods. While less invasive, the drawback of that approach is that it requires explicit declaration of 'init-method' and/or 'destroy-method' attributes on the 'bean' element. That explicit configuration is sometimes necessary, such as when the callbacks need to be invoked on code that is outside of the developer's control. The PetClinic application demonstrates this scenario. When it is run with its JDBC configuration, a third party DataSource is used, and a 'destroy-method' is declared explicitly. Also notice that the standalone connection-pooling DataSource is yet another deployment option for the 'dataSource' and does not require any code changes.

<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>

With Spring 2.5, if an object requires invocation of a callback method upon initialization, that method can be annotated with the @PostConstructannotation. For example, imagine a background task that needs to start polling a file directory upon startup.

public class FilePoller {

@PostConstruct
public void startPolling() {
...
}
...
}

Similarly, a method annotated with @PreDestroy on a Spring-managed object will be invoked when the application context hosting that object is closed.

public class FilePoller {

@PreDestroy
public void stopPolling() {
...
}
...
}

With the addition of support for the JSR-250 annotations, Spring 2.5 now combines the advantages of its two previous lifecycle method alternatives. Adding @PostConstruct and @PreDestroy as method-level annotations is sufficient for triggering the callbacks within a Spring managed context. In other words, no additional XML-based configuration is necessary. At the same time, the annotations are part of the Java language itself (and even included within Java SE as of version 6) and thus require no Spring-specific imports. The annotations have the added benefit of indicating semantics that should be understood within other environments, and over time Java developers can likely expect to see these annotations used more frequently within third-party libraries. Finally, one interesting consequence of the annotation-based lifecycle callbacks is that more than one method may carry either annotation, and all annotated methods will be invoked

To enable all of the behavior as described above for the @Resource@PostConstruct, and @PreDestroy annotations, provide a single bean definition for Spring's CommonAnnotationBeanPostProcessor as shown previously. An even more concise option is possible with the new 'context' namespace in 2.5:

<context:annotation-config/> 

Including that single element will not only register a CommonAnnotationBeanPostProcessor, but it will also enable the autowiring behavior as described in the section that follows. The CommonAnnotationBeanPostProcessor even provides support for @WebServiceRef and @EJBannotations. These will be covered in the third article of this series along with other new Spring 2.5 features for enterprise integration.

Fine-Grained Autowiring with Annotations

Documentation covering Spring's support for autowiring has often been accompanied with caveats due to the coarse granularity of the autowiring mechanism. Prior to Spring 2.5, autowiring could be configured for a number of different approaches: constructor, setters by type, setters by name, or autodetect (where Spring chooses to autowire either a constructor or setters by type). These various options do offer a large degree of flexibility, but none of them offer very fine-grained control. In other words, prior to Spring 2.5, it has not been possible to autowire a specific subset of an object's setter methods or to autowire some of its properties by type and others by name. As a result, many Spring users have recognized the benefits of autowiring for prototyping and testing, but when it comes to maintaining and supporting systems in production, most agree that the added verbosity of explicit configuration is well worth the clarification it affords.

However, Spring 2.5 dramatically changes the landscape. As described above, the autowiring choices have now been extended with support for the JSR-250 @Resource annotation to enable autowiring of named resources on a per-method or per-field basis. However, the @Resource annotation alone does have some limitations. Spring 2.5 therefore introduces an @Autowired annotation to further increase the level of control. To enable the behavior described in this section, register a single bean definition:

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> 

Alternatively, the 'context' namespace provides a more concise alternative as shown previously. This will enable both post-processors discussed in this article (AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor) as well as the annotation-based post-processors that were introduced in Spring 2.0: RequiredAnnotationBeanPostProcessor and PersistenceAnnotationBeanPostProcessor.

<context:annotation-config/> 

With the @Autowired annotation, it is possible to inject dependencies that match by type. This behavior is enabled for fields, constructors, and methods. In fact, autowired methods do not have to be 'setter' methods and can even accept multiple parameters. The following is perfectly acceptable:

@Autowired
public void setup(DataSource dataSource, AnotherObject o) { ... }

By default, dependencies marked with the @Autowired annotation are treated as required. However, it is also possible to declare any of them as optional by setting the 'required' attribute to 'false'. In the following example, DefaultStrategy will be used if no Spring-managed object of typeSomeStrategy is found within the context.

@Autowired(required=false)
private SomeStrategy strategy = new DefaultStrategy();

Autowiring by type can obviously result in ambiguities when the Spring context contains more than one object of the expected type. By default, the autowiring mechanism will fail if there is not exactly one bean for a required dependency. Likewise for any optional properties, it will fail if more than one candidate is available (if optional and zero candidates are available, then it will simply skip the property). There are a number of configuration options for avoiding these conflicts.

When there is one primary instance of a given type within the context, the bean definition for that type should contain the 'primary' attribute. This approach works well when other instances may be available in the context, yet those non-primary instances are always explicitly configured.

<bean id="dataSource" primary="true" ... /> 

When more control is needed, any autowired field, constructor argument, or method parameter may be further annotated with a @Qualifierannotation. The qualifier may contain a String value in which case Spring will attempt to match by name.

@Autowired
@Qualifier("primaryDataSource")
private DataSource dataSource;

The main reason that @Qualifier exists as a separate annotation is so that it can be applied at the level of a constructor argument or method parameter while the @Autowired annotation is available on the constructor or method itself.

@Autowired
public void setup(@Qualifier("primaryDataSource") DataSource dataSource, AnotherObject o) { ... }

The fact that @Qualifier is a separate annotation provides even more benefits with regard to customization. User-defined annotations may also play the role of qualifier in the autowiring process. The simplest way to accomplish this is to annotate the custom annotation with @Qualifier itself as a meta-annotation.

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface VetSpecialty { ... }

Custom annotations may optionally include a value for matching by name but more commonly would be used as "marker" annotations or define a value that provides some further meaning to the qualifier process. For example, the excerpt below depicts a field that should be autowired with a qualified candidate among those that match by type.

@Autowired
@VetSpecialty("dentistry")
private Clinic dentistryClinic;

When using XML configuration for the target of this dependency resolution, 'qualifier' sub-elements may be added to the bean definition. In the next section on component-scanning, a non-XML alternative will be presented.

<bean id="dentistryClinic" class="samples.DentistryClinic">
<qualifier type="example.VetSpecialty" value="dentistry"/>
</bean>

To avoid any dependency on the @Qualifier annotation whatsoever, provide a CustomAutowireConfigurer bean definition within the Spring context and register any custom annotation types directly:

<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>example.VetSpecialty</value>
</set>
</property>
</bean>

Now that the custom qualifier has been explicitly declared, the @Qualifier meta-annotation is no longer required.

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface VetSpecialty { ... }

On a related note, it is even possible to replace the @Autowired annotation itself when configuring theAutowiredAnnotationBeanPostProcessor.

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="autowiredAnnotationType" value="example.Injected"/>
</bean>

In a majority of cases, the ability to define custom "marker" annotations combined with the options of matching by name or other semantic value should be sufficient for achieving fine-grained control of the autowiring process. However, Spring also provides support for any number of arbitrary attributes on qualifier annotations. For example, the following is a hypothetical example of a very fine-grained qualifier.

@SpecializedClinic(species="dog", breed="poodle")
private Clinic poodleClinic;

The custom qualifier implementation would define those attributes.

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface SpecializedClinic {

String species();

String breed();

}

The custom qualifier's attributes can then match against 'attribute' sub-elements of the 'qualifier' annotation within the XML of a bean definition. These elements are used to provide key/value pairs.

<bean id="poodleClinic" class="example.PoodleClinic">
<qualifier type="example.SpecializedClinic">
<attribute key="species" value="dog"/>
<attribute key="breed" value="poodle"/>
</qualifier>
</bean>

All of the autowiring demonstrated so far has been for single instances, but collections are supported as well. Any time it's necessary to get all Spring-managed objects of a certain type within the context, simply add the @Autowired annotation to a strongly-typed Collection.

@Autowired
private List<Clinic> allClinics;

One final feature that is worth pointing out in this section is the use of autowiring in place of Spring's "Aware" interfaces. Prior to Spring 2.5, if an object requires a reference to the Spring context's ResourceLoader, it can implement ResourceLoaderAware thereby allowing Spring to provide this dependency via the setResourceLoader(ResourceLoader resourceLoader) method. This same technique applies for obtaining a reference to the Spring-managed MessageSource and even the ApplicationContext itself. For Spring 2.5 users, this behavior is now fully supported through autowiring (note that the inclusion of these Spring-specific dependencies should always be carefully considered and typically only used within "infrastructure" code that is clearly separated from business logic).

@Autowired
private MessageSource messageSource;

@Autowired
private ResourceLoader resourceLoader;

@Autowired
private ApplicationContext applicationContext;

Auto-Detection of Spring Components

Beginning with version 2.0, Spring introduced the concept of "stereotype" annotations with the @Repository annotation serving as a marker for data access code. Spring 2.5 adds two new annotations - @Service and @Controller - to complete the role designations for a common three-tier architecture (data access objects, services, and web controllers). Spring 2.5 also introduces the generic @Component annotation which the other stereotypes logically extend. By clearly indicating application roles, these stereotypes facilitate the use of Spring AOP and post-processors for providing additional behavior to the annotated objects based on those roles. For example, Spring 2.0 introduced thePersistenceExceptionTranslationPostProcessor to automatically enable data access exception translation for any object carrying the@Repository annotation.

These same annotations can also be used in conjunction with another new feature of Spring 2.5: auto-detection of components on the classpath. Although XML has traditionally been the most popular format for Spring metadata, it is not the only option. In fact, the Spring container's internal metadata representation is pure Java, and when XML is used to define Spring-managed objects, those definitions are parsed and converted to Java objects prior to the instantiation process. One significant new capability of Spring 2.5 is the support for reading that metadata from source-level annotations. The autowiring mechanisms described thus far make use of annotation metadata for injecting dependencies but still require registration of at least a minimal "bean definition" in order to provide the implementation class of each Spring-managed object. The component scanning functionality can remove the need for even that minimal bean definition in XML.

As seen above, Spring's annotation-driven autowiring can significantly reduce the amount of XML without sacrificing fine-grained control. The component detection mechanism takes this even further. It is not necessary to completely supplant configuration in XML, rather the component scanning can operate alongside XML metadata to simplify the overall configuration. This possibility of combining XML and annotation-driven techniques can lead to a well-balanced approach as demonstrated by the 2.5 version of the PetClinic sample application. There, the infrastructural components (data source, transaction manager, etc) are defined in XML along with externalized properties as described above. The data access tier objects are also defined partially in XML, but their configuration also takes advantage of the @Autowired annotations to simplify the injection of dependencies. Finally, the web tier "controllers" are not explicitly defined in XML at all. Instead the following configuration is used to trigger the auto-detection of all web controllers:

<context:component-scan base-package="org.springframework.samples.petclinic.web"/> 

Notice that the 'base-package' attribute is provided. The default matching rules for component-scanning will recursively detect any of Spring's stereotype annotations on classes within that package (multiple packages can be provided in a comma-separated list). Therefore, the various controller implementations for the PetClinic sample application are all annotated with @Controller (one of Spring's built-in stereotypes). Here is an example:

@Controller
public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
...

Auto-detected components are registered with the Spring container just as if they had been defined in XML. As depicted above, those objects can in turn make use of annotation-driven autowiring.

The component scanner's matching rules can also be customized with filters for including or excluding components based on type, annotation, AspectJ expression, or regular expressions for name patterns. The default stereotypes can also be disabled. For example, a test configuration may ignore the default stereotypes and instead auto-detect any class whose name starts with Stub or which includes the @Mock annotation:

<context:component-scan base-package="example" use-default-filters="false">
<context:include-filter type="aspectj" expression="example..Stub*"/>
<context:include-filter type="annotation" expression="example.Mock"/>
</context:component-scan>

Type matching restrictions can be controlled with exclusion filters as well. For example, to rely on the default filters except for the @Repositoryannotation, then add an exclude-filter.

<context:component-scan base-package="example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>

Clearly it is possible to extend the component scanning in a number of ways to register your own custom types. The stereotype annotations are the simplest option, so the notion of stereotype is therefore extensible itself. As mentioned earlier, @Component is the generic stereotype indicator that the @Repository@Service, and @Controller annotations "logically" extend. It just so happens that @Component can be provided as a meta-annotation (i.e. an annotation declared on another annotation), and any custom annotation that has the @Component meta-annotation will be automatically detected by the default matching rules of the scanner. An example will hopefully reveal that this is much simpler than it sounds.

Recall the hypothetical background task that was described in the section above covering the @PostConstruct and @PreDestroy lifecycle annotations. Perhaps an application has a number of such background tasks, and those task instances would typically require XML bean definitions in order to be registered with the Spring context and have their lifecycle methods invoked at the right time. With component scanning, there is no longer a need for those explicit XML bean definitions. If the background tasks all implement the same interface or follow a naming convention, theninclude-filters could be used. However, an even simpler approach is to create an annotation for these task objects and provide the @Componentmeta-annotation.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface BackgroundTask {
String value() default "";
}

Then provide the custom stereotype annotation in any background task's class definitions.

@BackgroundTask
public class FilePoller {

@PostConstruct
public void startPolling() {
...
}

@PreDestroy
public void stopPolling() {
...
}
...
}

The generic @Component annotation could just as easily have been provided instead, but the custom annotation technique provides an opportunity for using meaningful, domain-specific names. These domain-specific annotations then provide further opportunities such as using an AspectJ pointcut expression to identify all background tasks for the purpose of adding advice that monitors the activity of those tasks.

By default, when a component is detected, Spring will automatically generate a "bean name" using the non-qualified class name. In the previous example, the generated bean name would be "filePoller". However, for any class that is annotated with one of Spring's stereotype annotations (@Component@Repository@Service, or @Controlleror any other annotation that is annotated with @Component as a meta-annotation (such as @BackgroundTask in the above example), the 'value' attribute can be explicitly specified for the stereotype annotation, and the instance will then be registered within the context with that value as its "bean name". In the following example the name would be "petClinic" instead of the default generated name of "simpleJdbcClinic".

@Service("petClinic")
public class SimpleJdbcClinic {
...
}

Likewise, the bean name generated for the following revised version of the FilePoller would be "poller" instead of "filePoller".

@BackgroundTask("poller")
public class FilePoller {
...
}

While all Spring-managed objects are treated as singleton instances by default, it is sometimes necessary to specify an alternate "scope" for an object. For example, in the web-tier a Spring-managed object may be bound to 'request' or 'session' scope. As of version 2.0, Spring's scope mechanism is even extensible so that custom scopes can be registered with the application context. Within an XML configuration, it's simply a matter of including the 'scope' attribute and the name of the scope.

<bean id="shoppingCart" class="example.ShoppingCart" scope="session">
...
</bean>

With Spring 2.5, the same can be accomplished for a scanned component by providing the @Scope annotation.

@Component
@Scope("session")
public class ShoppingCart {
...
}

One final topic to address here is the simplification of qualifier annotations when using component-scanning. In the previous section, the following object was used as an example of autowiring with a custom qualifier annotation:

@VetSpecialty("dentistry")
private Clinic dentistryClinic;

That same example then featured use of a 'qualifier' element within the XML on the intended target bean definition for that dependency. When using component-scanning, the XML metadata is not necessary. Instead, the custom qualifier may be included as a type-level annotation in the target class definition. An alternative example with a scanned @Repository instance as the dependency would thus appear as follows:

@Repository
@VetSpecialty("dentistry")
public class DentistryClinic implements Clinic {
...
}

Finally, for the previous example that featured custom qualifier annotations with attributes, the non-XML equivalent for that dependency's target would be:

@Repository
@SpecializedClinic(species="dog", breed="poodle")
public class PoodleClinic implements Clinic {
...
}

Conclusion

Spring 2.5 offers significant new functionality in a number of areas. The primary focus of this article has been on simplifying configuration by harnessing the power of Java annotations. Spring supports 'Common Annotations' as defined in JSR-250 while providing additional annotations for even more fine-grained control of the autowiring process. Spring 2.5 also extends the 'stereotype' annotations that began with Spring 2.0's@Repository, and all of these stereotypes can be used in conjunction with the new component-scanning functionality. XML-based configuration is still fully supported, and Spring 2.5 introduces a new 'context' namespace that offers more concise syntax for common configuration scenarios. In fact, the support for seamlessly combining XML and annotation-based configuration enables a well-balanced overall approach. Complex configuration of infrastructure can be defined in modular XML files while the progressively higher layers of an application stack can benefit from more annotation-based techniques - all within the same Spring 2.5 application context.

Stay tuned for the next article in this series, which will cover powerful new annotation-based functionality in the Spring web tier.



:

Spring Security PDF

ITWeb/개발일반 2012. 2. 20. 22:47
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity.pdf

집에서 다운로드 받아 놓다보니..
걍.. 파일 까지 올려 봅니다.

:

maven integration for eclipse jdk warning - eclipse 실행 시

ITWeb/개발일반 2012. 2. 20. 17:06
구글링 하면 많이 나와 있습니다.
해결 방법이요.. ㅋ

직관적이죠.. -vm 옵션에 JDK  경로 설정을 하라는.. 
다만, 아래와 같이 설정 하시면 설정이 제대로 되지 않습니다.

[안좋은 예]

-vm C:\Program Files\Java\jdk1.6.0_29\bin\



[좋은 예] 

-vm
C:\Program Files\Java\jdk1.6.0_29\bin\


차이를 아시겠죠... ^^;
상세 내용을 보면 위에 내용도 잘 된건 아닙니다.
명시적으로 javaw.exe 를 작성해 주시는게 좋습니다.
설정에 대한 자세한 내용은 아래 링크 참고 하시면 됩니다.
http://wiki.eclipse.org/Eclipse.ini 

Remember that the exact values will differ slightly depending on operating system and Eclipse package.

-vm value: Windows Example

This is how the -vm argument might look on Windows (your exact path to javaw.exe could be different, of course):

-vm
C:\Java\JDK\1.6\bin\javaw.exe

-vm value: Linux Example

This is how the -vm argument might look on Linux (your exact path to javacould be different, of course):

 -vm
/opt/sun-jdk-1.6.0.02/bin/java

-vm value: Mac OS X Example

On a Mac OS X system, you can find eclipse.ini by right-clicking (or Ctrl+click) on the Eclipse executable in Finder, choose Show Package Contents, and then locate eclipse.ini in the MacOS folder under Contents.

To specify Java 6 for OS X:

 -vm
/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/bin/java
 
:

eclipse checkstyle 적용하기.

ITWeb/개발일반 2012. 2. 20. 16:54

checkstyle 플러그인은 아래 사이트 참고 하셔서 eclipse 에 등록 하시면 됩니다.
http://eclipse-cs.sourceforge.net/downloads.html 

  1. Within Eclipse go to Help->Software Updates->Find and Install
  2. Choose Search for new features to install and press Next
  3. Create a New Remote Site...
  4. Input a name to your liking (for instance Checkstyle Plug-in) and input the following URL: http://eclipse-cs.sf.net/update/
  5. Click your way through the following pages to install the plug-in.
  6. Restart Eclipse


이렇게 등록하고 나면
Windows -> Preferences -> Checkstyle 메뉴가 보이실 겁니다.

기본 Sun 에서 제공하는 checkstyle 이 있는데요..
수정 하시거나 개인적으로 사용하시는 checkstyle 파일이 있으시면 등록 하셔서 사용하시면 됩니다. 
:

삼성애드허브 모바일 웹 광고 붙혀 보기.

ITWeb/개발일반 2012. 2. 14. 18:44
tistory 의 경우 모바일 웹 스킨을 수정 할 수 있는 권한이 없다 보니 그냥 일반 웹 블로그에 적용해 봅니다. ^^*

일단, 삼성애드허브 사이트에서 회원 가입 부터 합니다.
http://www.samsungadhub.com  

좀 불편한건 Global 정책에 따른 영문 사이트다 보니 한국 사용자가 사용하기에는 접근성이 떨어질 수 밖에 없습니다. ^^;;

회원가입 Flow 와 Inventory 생성 Flow 에 대한 튜토리얼이나 영상 같은게 있으면 참 좋겠다는 생각 입니다.
사실 있기는 합니다.
http://www.samsungadhub.com/pr/support/guide/guideline/main.do <-- 요기

하지만 요즘 사용자들은 텍스트로 쭈욱 펼쳐 놓은걸 하나 하나 읽어 줄 만큼 인내심이 없다고 생각 하기 때문에 영상 또는 화면 캡쳐에 따른 flow 가 있으면 역시나 참 좋겠다는 의견 입니다.

암튼 회원 가입도 하고 인벤토리도 생성을 했으면 이제 사이트에 삽입을 해봅시다.
구글애드센스 적용 하는 거랑 별 차이 없습니다.

아래 발급 받은 코드를 그냥 넣고 싶은 곳에 삽입만 하면 광고가 나오게 됩니다.
- 빨간 부분의 불필요한 주석 코드는 삭제를 해주시면 좋을 것 같습니다.
- 또한 textarea 영역에 focus 가 들어 가면 해당 코드에 대해서 selected 가 되면 더 좋겠구요
.

제 블로그에서는 그냥 제일 하단에 코드 삽입을 했구요.
아직 Ad Network 에 activation 이 안된 상태라 그냥 테스트 AD 만 나오고 있군요. ㅎㅎ
앞으로도 대박 건승 하시길 바랍니다. :)

<script type="text/javascript">

    /**

     * Default Configuration

     *

     * @attribute   id          inventory id

     * @attribute   width       inventory width (px)

     * @attribute   height      inventory height (px)

     * @attribute   allow       CORS allow origin (http://SITE_DOMAIN), Publisher Site Domain

     * @attribute   bgColor     background color (RGB)

     * @attribute   fontColor   font color (RGB)

     * @attribute   fontSize    font size (px)

     * @attribute   fontFmaily  font style

     * @attribute   fontAlign   font alignment

     * @attribute   gateway     API I/F Domain

    */

    var samsungAdhubConf  = {

        id : '2100000763_001',

        width : 728,

        height : 90,

        site : 'http://jjeong.tistory.com',

        bgColor : '000000',

        fontColor : 'FFFFFF',

        fontSize : 12, 

        fontFamily : '', 

        fontAlign : 'center', 

        gateway : 'http://ad.samsungadhub.com'

    }

</script> 

<script type='text/javascript' src='http://ad.samsungadhub.com/api/web/1.0/adhub.js'></script>

 
:

내 블로그에 애드센스 적용하기

ITWeb/개발일반 2012. 2. 14. 11:57

jjeong.tistory.com 에 광고 붙히기
구글 계정 생성해서 애드센스 가입 하고 광고 코드 생성해서 삽입 하시면 됩니다.
빨간 부분이 구글에서 생성해 주는 코드고 나머지는 블로그 레이아웃에 맞게 삽입 하기 위해 사용한 허접 HTML임돠.

<!-- 구글애드센스시작 -->

<table border="0" width="100%">

<tr><td align="center">

<div id="google_adsense_area" style="width:728px; height:90px;">

<script type="text/javascript"><!--

google_ad_client = "ca-pub-6494816765698161";

/* HeaderAd */

google_ad_slot = "9895326307";

google_ad_width = 728;

google_ad_height = 90;

//-->

</script>

<script type="text/javascript"

src="http://pagead2.googlesyndication.com/pagead/show_ads.js">

</script>

</div>

</td></tr></table>

<!-- 구글애드센스끝 -->


광고플랫폼 만든다고 내 계정으로 테스트 겁나 하다 부정클릭 적발로 계정 삭제되서 다시 만들고 적용했습니다.
그 동안 정상적으로 모았던 내 수익급은 누가 돌려 주는거냐!!!! 
:

문서제목 작성구조 정의

ITWeb/개발일반 2012. 2. 14. 11:07
문서 Name Rule에 대한 자체 규약정의
지금까지 문서를 만들다 보니.. 아래와 같은 형식이 그나마 관리 하기가 쉬웠던것 같아 나중에 또 고민 안하려고 로그를 남겨 봅니다.

{YYYYMMDD}_{1차소속부서명}_{문서제목}_{버전}

- 문자열 사이 사이에 공백이 없어야 함. (문자/숫자/특수문자(.-_) 사용가능)
- 버전의 시작은 v0.1 로 시작, 정식 릴리즈 시 v1.0 으로 올림.
    . 소수는 초기 작성 및 수정 발생 시 숫자를 올림.
    . 정수는 릴리즈 시 또는 대규모 변경 시 숫자를 올림.

YYYYMMDD : 년월일(20120214)
1차소속부서명 : 광고플랫폼개발팀
문서제목 : 모바일웹광고개발전략및계획 
버전 : v0.1 


[Example]

20120214_광고플랫폼개발팀_모바일웹광고개발전략및계획_v0.1


 
: