쾌속 웹서비스 개발 Spring & XFire
- 김영희(CDO본부 검색서비스 개발팀), 2006년 10월
- 웹서비스 개발시 시행착오와 중복 개발, 코드의 버전 관리등 여러 가지 번거로운 문제들을 피해서 가볍게 웹서비스를 개발해 본다.
- c/s 메시징에서 메시지의 정의와 처리는 매우 번거로운 일이다. 이번기회에 웹서비스로 변경하는 길잡이가 되길 바란다.
샘플 프로젝트 소개 #
- 맨 아래 첨부된 프로젝트는 원격 금리를 계산해주는 웹서비스 샘플로 웹서비스 템플릿으로 사용할 수 있다.
- 압축을 푼 디렉토리를 bank라는 context root로 등록한다.
<Context docBase="E:\\Work\\Java\\PrivateBank"
privileged="true" antiResourceLocking="false" antiJARLocking="false">
<!-- Link to the user database we will get roles from -->
<ResourceLink name="users" global="UserDatabase"
type="org.apache.catalina.UserDatabase"/>
</Context>
- 서블릿 컨테이너를 기동시키고 http://localhost:8080/bank/SimpleBankService?wsdl 주소를 호출하면 아래와 같은 xml이 나온다.
<?xml version="1.0" encoding="UTF-8" ?> - <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:tns="http://bank.spring.study.search.daum.net" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://bank.spring.study.search.daum.net"> - <wsdl:types> - <xsd:schema targetNamespace="http://bank.spring.study.search.daum.net" elementFormDefault="qualified" attributeFormDefault="qualified"> - <xsd:complexType name="Account"> ....
제공되는 서비스 #
- 아래 서비스들을 net.daum.search.study.spring.bank.test의 PrivateBankMainTest와 MyRemoteBankTest를 통해서 간단히 테스트 할 수 있다.
- 아래 메서드에서 deposit, draw에서 Account를 돌려줄 필요는 없지만 객체를 리턴 받는법을 보이고자 객체로 리턴한다.
public abstract Account deposit(Account account, long money);
public abstract Account draw(Account account, long money);
public abstract long calculateInterestAfter(Account account, int day);
프로젝트 구성 #
- PrivateBank
- src
- WEB-INF
- lib
- conf : Spring beans를 위해 임시로 몇개 xml을 넣어둠
- classes
- privateBankContext.xml : app context
- bank-servlet.xml : spring에서 xfire를 이용해 service를 export하는 설정을 담음
- web.xml : spring의 dispatch servlet을 설정
Spring/XFire 시작하기 #
Spring #
- 스프링을 사용하면 Layered Architecture를 쉽게 구성할 수 있다.
- IoC를 통해서 객체간 의존성을 줄이며 재사용을 도와준다.
- 좋은 은행은 10%의 좋은 단리로 이자가 붙는다.
- 나쁜 은행은 2%의 바보 단리로 이자를 준다.
- 수퍼 은행은 상상을 초월한 이자를 준다.
- SimpleInterest라는 객체에 이율이라는 조건을 달리해서 좋은 은행과 나쁜 은행을 생성하는걸 볼 수 있다.
- 복리라는 이율을 가지고 있지만 적용한 은행은 아직 없다.
아래는 Spring에서 주로 작성하는 applicationContext.xml로 privateBankContext.xml로 명명했다.
privateBankContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="goodSimpleInterest" class="net.daum.search.study.spring.bank.SimpleInterest" singleton="false">
<property name="interestPercent"><value>10</value></property>
</bean>
<bean id="baboSimpleInterest" class="net.daum.search.study.spring.bank.SimpleInterest" singleton="false">
<property name="interestPercent"><value>2</value></property>
</bean>
<bean id="superPowerInterest" class="net.daum.search.study.spring.bank.PowerInterest" singleton="false">
<property name="interestPercent"><value>10</value></property>
</bean>
<bean id="compoundInterest" class="net.daum.search.study.spring.bank.CompoundInterest" singleton="false">
<property name="interestPercent"><value>10</value></property>
</bean>
<bean id="goodBank" class="net.daum.search.study.spring.bank.PrivateBank" singleton="false">
<property name="interest"><ref bean="goodSimpleInterest"/></property>
</bean>
<bean id="badBank" class="net.daum.search.study.spring.bank.PrivateBank" singleton="false">
<property name="interest"><ref bean="baboSimpleInterest"/></property>
</bean>
<bean id="superBank" class="net.daum.search.study.spring.bank.PrivateBank" singleton="false">
<property name="interest"><ref bean="superPowerInterest"/></property>
</bean>
</beans>
Spring/XFire #
- Spring에서 작성한 객체들을 재사용 하고 싶은데 마땅한 툴들을 찾지 못하던중 XFire를 발견했다.
- Axis나 다른 프레임웍보다 궁합이 잘맞고 Stax기반으로 Axis에 비해 5배나 빠르다.
- 더욱이 Axis와 같은 툴을 통해서 코드를 자동 생성하게 되면 프로젝트의 버전 관리가 어렵기 때문에 Axis는 마지막까지 선택할 수 없었다.
- (그러나 Axis 2.0은 그럴 필요가 없다.)
- 다음은 XFire를 통해서 서비스를 export 해주는 Spring 설정이다.
- ServiceBean : 서비스 구현체
- ServiceClass : 오픈할 서비스의 인터페이스
- ServiceFactory : 서비스 팩토로 - 여기서는 XmlBeans를 이용한다.
bank-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- Declare a parent bean with all properties common to both services -->
<bean name="/SimpleBankService" class="org.codehaus.xfire.spring.remoting.XFireExporter" singleton="true">
<property name="serviceBean"><ref bean="goodBank"/></property>
<property name="serviceClass"><value>net.daum.search.study.spring.bank.Bank</value></property>
<property name="serviceFactory"><ref bean="xfire.xmlbeansServiceFactory"/></property>
</bean>
</beans>
다음은 service Factory로 xmlBeans를 사용하기 위한 web.xml설정이다. context-param에 spring의 설정과 XFire설정을 아래와 같이 추가하면된다.
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/privateBankContext.xml
classpath:org/codehaus/xfire/spring/xfire.xml
classpath:org/codehaus/xfire/spring/xfireXmlBeans.xml
classpath:org/codehaus/xfire/spring/customEditors.xml
</param-value>
</context-param>
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>bank</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>bank</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
결론 #
- 기존에 Spring으로 개발한 Beans를 XFire를 통해 바로 서비스로 export 할 수 있다.
- 프로젝트 전반에 걸쳐 중복 개발 최소화(서비스와 서비스간 공통 모듈을 copy&paste가 아닌 bean ref를 통해 재사용)
- Stax기반으로 성능 극대화
- 스파게티 코드 생성에서 해방
![[http]](/wiki/imgs/http.png)