Spring이 어느덧 2.0 RC2를 7월6일에 발표하였다.
개인적으로는 dev 메일링을 받아 개발진척이나 관련 프로젝트들의 진행을
꾸준히 모니터링하고 있는데, 분위기상  정식 릴리즈가 임박했음이 느껴진다.

이에 곧 나올 2.0 정식버젼에 앞서 어떤 것들이 새롭게 변모되었는지 이제는
한번쯤 봐둘 필요가 있을 듯 싶어 간단히 정리해 볼까한다.

1. IoC 컨테이너의 향상

  2.0으로 올라오며, 내부적으로 가장 많은 변화가 있었던 부분이 IoC 컨테이너
  부분이다. (단, 사용자 관점에서는 큰 변화를 느끼지 못하겠지만)
  간단히 간추려 보면,

  1.1. XML 설정파일이 쉬워지다.  

  내용인 즉, 새로운 스키마의 지원에 따른 내용을 쉽게 처리할 수 있다는 것이다.
  <util:XXX> , <jee:XXX> 와 lang, tx, aop 스키마가 추가 지원되고 이에 대한 것이
   IDE 에서의 제공되는 spring 플러그인에서 제공된다는 것이다.
   결과적으로 새로운 것 더 열심히 공부하면 더 쉽게 쓸 수 있다는 것이다. ^^
   참조 : http://static.springframework.org/spring/docs/2.0.x/reference/new-in-2.html

  1.2. XML 작성의 확장

  2.0에서는 단지 쉬어지기만 한 것이 아니라, 좀 더 확장성을 띄고 있다.
    이는 XML 스키마를 직접 작성가능하게 함으로 이를 가능케 한다.
    위에서 언급한 새롭게 등장한 스키마와 같이, 나 또는 팀에서 자주 사용하는 스키마에
    대해서 이미 스키마로 구현이 가능하다는 것이다. (말그대로 확장성을 대폭 강화하여
    spirng을 사용하는 개개인이 스키마 확장까지 가능하게 되었다.)
    참조 : http://static.springframework.org/spring/docs/2.0.x/reference/extensible-xml.html

  1.3. 새로운 bean 범위
    
  기존의 Spring은 IoC 컨네이터 레벨에서 두가지(singleton과 prototype)만 지원했었지만,
    2.0에서는 위의 두가지 이외에 request, session, global session 가 추가되었다.
    앞선 두가지는 local(!) 개발에 후자 3개는 웹기반에 적용된다.
    크게 변화가 없는 듯 하면서도 변화가 생긴 부분이라 하겠다. (기존 사용방식에는 차이가 없다.)
   참조 : http://static.springframework.org/spring/docs/2.0.x/reference/beans.html#beans-factory-scopes
 
2. AOP
 
  2.0에서는 AOP 제공이 매우 향상되었다.
   XML 설정이 쉬워졌으며, AspectJ pointcut 언어와 @AspectJ와 통합되었다.
   (이것은 AspectJ의 리더인 Adrian Colyer가 지난해 9월 IBM에서 Interface21(스프링을 만드는 회사)로
   옮기면서 이미 예견된 부분이다.)

  2.1. 쉬워진 AOP XML 설정

  2.0은 aspects 를 위한 새로운 스키마를 지원한다. AspectJ pointcut 언어와 전체적인 타입에 대한 안내
  (캐스팅이나 Object[]아규먼트와 같은 더이상의 조작은 필요없다.)의 이점을 제공한다.
  <aop:config> 엘리먼트 내에 <aop:aspect> <aop:pointcut> 등과 같은 방법으로 사용 가능하다.
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/aop.html#aop-schema

  2.2.  @AspectJ aspects의 제공

  2.0 은 @AspectJ annotations의 사용을 제공하고 이는 AspectJ와 Spring AOP간에 공유가 가능하다.

3. Middle Tier (Data Access)

  3.1. XML 내에 선언된 트랜젝션의 설정이 쉬어졌다.

  기존의 1.2.X 스타일이 계속 지원은 되지만, 2.0 스타일을 추천되며, 이 방식은 작성을 쉽게 소스량(!)을
  현저히 줄인다. 주목해야 할 부분은 AspectJ aspects library와 사용이 가능한데 이때 다양한 오브젝트와
  사용이 가능한데 하물며, Sping container에서 생성되지 않은 객체까지 사용이 가능하다는 점이다.
  (의미적으로는 이런데 자세히 봐야되겠다. 기존의 트랜젝션 관리에 있어서 많은 솔루션들이 가지고 있던
  문제가 여러 객체를 거치는 (프로세스를 가지는) 트랜젝션의 처리가 쉽지 않다는 것이였는데, 이 의미로는
  이것 또한 해결이 가능하다는 이야기이므로 정확한 확인이 필요할 듯 싶다.
  이가 가능하다면 엔터프라이즈 솔루션에 있어 상당한 기여가 있을 것 같다.)

  3.2. JPA

  Spring의 JDBC 추상 레이어 목적으로 Hibernate, JDO와 같은 것을 동일한 방법 내에서 포괄적으로
  Java Persistence API를 위해 제공한다.
  + JPA 관련 참조 : http://static.springframework.org/spring/docs/2.0.x/reference/orm.html#orm-jpa
  + Java Persistence API 참고 : http://java.sun.com/developer/technicalArticles/J2EE/jpa/index.html

  3.3. Asynchronous JMS

  개인적으로 오래 기다려온 내용이다.  
    이전의 1.2 버젼까지의 Spring은 JMS를 제공함에 있어 JmsTemplate 클래스가 기능적으로 훌륭히
  추상화하여 사용의 간편함을 제공하였다. 그러나 이것은 메시지의 비동기적인 production 와
  consumption은 지원하는 것이 아니였다.
    이번 2.0 에서는 이러한 부족한 부분을 완성하여 비동기적인 부분까지 지원이 되었다.
    참고 : http://static.springframework.org/spring/docs/2.0.x/reference/jms.html#jms-asynchronousMessageReception

  3.4. JDBC

  Spring의 JDBC 추상 프레임워크 내에 새롭게 주목해야할 크랠스가 있는데,
  첫째가 NamedParameterJdbcTemplate 로 named parameters 의 사용을 지원한다.
  둘째가 SimpleJdbcTemplate 로 기존의 core 기능에서 더욱 사용을 간편하게 만들어졌다. 단, 이는 Java 5(Tiger에서만 사용가능)

  자세한 것은 참조 사이트의 예제를 보면 바로 이해가 될 듯하다.
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html#jdbc-NamedParameterJdbcTemplate
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html#jdbc-SimpleJdbcTemplate

4. Web

  4.1. Spring MVC를 위한 form fag 라이브러리

  2.0 에서는 많은 개발자들의 요구에 의해 대부분의 JSP tag 라이브러리와 사용이 가능하게 하여,
  개발자의 만족도를 높였다고 확신하고 있다. struts에 있어서도 form tag의 사용에 따른 추가적인 개발
  요소가 만만치 않았던 것을 고려할때
  이에 대한 추가에 따른 개발에 도움이 될지 어떨지는 좀 더 확인 필요할 듯 싶다.
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/mvc.html
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/spring-form.tld.html

  4.2. Sping MVC 내에 분별력 있는 표준설정

  convention-over-configuration 를 통해 models, views, 와 controllers 의 기본 영역에서 주소를
  제공하여, naming convention의 표준화를 통해 XML 설정에 따른 소스 량을 줄이고, 내용을 명확하고
  쉽게 처리할 수 있도록 한다.
  기존의 무분별한 프로젝트마다의 naming conventions 을 설정한다거나 개개인마다의 방식을 만들어
  가는 것에서 큰 도움이 될 듯하다.
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/mvc.html#mvc-coc

  4.3. Portlet framework  

  웹기반에 있어서의 Portlet (JSR-168 Portlet)을 지원한다.
  이는 특별한 설명이 필요 없을 듯 싶다.
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/portlet.html

5. 그밖에

  5.1. Dynamic language 지원

  자바 이외에도 현재 JRuby, Groovy 와 BeanShell 가 포함되어 지원된다.
  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/dynamic-language.html

  5.2. JMX

  Spring에서 지원하던 JMS의 변경은 발전적이상의 획기적인 것으로 ...
  + Controlling the registration behavior : MBean 등록에 있어서 3가지을 제공한다.
      - REGISTRATION_FAIL_ON_EXISTING : MBean 인스턴스가 등록되어 있으면 InstanceAlreadyExistsException 을 통한 등록거부(디폴트),
      - REGISTRATION_IGNORE_EXISTING : MBean 인스턴스가 등록되어 있으면 아무런 에러없이 등록거부(멀티 어플리케이션 환경에 유용)
      - REGISTRATION_REPLACE_EXISTING : MBean 인스턴스가 등록되어 있으면, 이를 등록해지하고 새롭운 MBean으로 등록처리(기존MBean 대처시 유용)
  + Notifications : NotificationListeners을 통한 MBeans의 변경을 모니터링 가능하다.

참조 : http://static.springframework.org/spring/docs/2.0.x/reference/jmx.html#jmx-exporting-registration-behavior
참조 : http://static.springframework.org/spring/docs/2.0.x/reference/jmx.html#jmx-notifications

  5.3. Task scheduling (작업 스케쥴링)

  드럭 리가 심여를 기울여 Tiger에 포함시킨 java.util.concurrent.* 패치지에는 기존의 thread 의
  기능을 강화하고 확장시킨 Executors 라는 인터페이스가 있다. 이는 위의 내용에서 이야기 하다시피
    Java5 에서부터 구현이되어 사용이 가능하다.
  이에 2.0 에서는 Java 1.3, 1.4 에서도 Executors와 같은 기능(thread pools)을 가능케 하고자 이와
  동일한 기능의 (하지만 세부적인 구현을 더 추상화 시킨) TaskExecutor 를 제공한다.
  이에 대한 것은 아래를 참조하면 된다.
  (얼마전 리스너를 여러개 띄운 상태에서의 스케쥴링을 해야하는 프로그램을 작성한 적이 있었다.
     Spring에서 Quartz Scheduler를 사용하여, 처리하려 하였지만 데드락의 징후(!)가 보여 충분한 테스트
     도 채하기도 전에(기간이  촉박했던 것이였기에) thread 로 대처하여 어찌어찌 작성을 했었다.
     돌이켜 기억해보면 이때 이 기능을 사용했으면  여러가지 도움이 되었을텐데라는 생각이 든다.)  
  그 이외에도 scheduling 관련해서 문서상으로도 많은 보강이 있어 보인다. (특히 Pooling 관련)

  참조 : http://static.springframework.org/spring/docs/2.0.x/reference/scheduling.html#taskexecutor  

  5.4. Java 5 (Tiger) 지원
  제목과 같이 Java 5 (Tiger)을 지원하는 기능들이 추가 되었다.

  - Using AspectJ to dependency inject domain objects with Spring :
     http://static.springframework.org/spring/docs/2.0.x/reference/aop.html#aop-atconfigurable
    - @AspectJ support :
     http://static.springframework.org/spring/docs/2.0.x/reference/aop.html#aop-ataspectj
    - Using @Transactional with AspectJ :
     http://static.springframework.org/spring/docs/2.0.x/reference/transaction.html#transaction-declarative-aspectj
  - @Required :
     http://static.springframework.org/spring/docs/2.0.x/reference/metadata.html#metadata-annotations-required
  - SimpleJdbcTemplate :
     http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html#jdbc-SimpleJdbcTemplate

6. 샘플 업데이트
  전반적인 소스의 업데이트와 showcases 라는 폴더가 새롭게 생겼다.

7. 문서의 향상
  2.0 에 맞춰 새롭게 레퍼런스 문서가 작성되었다.  

Posted by 아름프로
어설픈 해석보다는 원문 그대로를 적어본다.
ActiveMQ 사용에 있어서의 JmsTemplate 사용에 대한 좋은 내용이다.
  • Never use a regular ConnectionFactory unless you are totally sure it does all the pooling you need
  • If using in an EJB ensure you use the EJB containers ConnectionFactory; otherwise consider using Jencks to create it for you
  • If not using in an EJB then use Jencks to create the ConnectionFactory
  • If you are only publishing messages and you are not in an EJB and you are using ActiveMQ then you can use the PooledConnectionFactory
  • Ifyou are consuming messages its probably simpler & more efficient& less likely to loose messages to avoid using the receive() methodand use
    Message Driven POJOs instead - unless you absolutely must pull messages on demand from inside an EJB.
원문 : 위치
Posted by 아름프로
JmsTemplate은 설계가 되어질 때, EJB 컨테이너를 사용하는  EJB상에서 사용한다는 것을 전제로 설계가
되어졌다고 한다. 다시 말해, J2EE Cotainer 환경에서 JMS pooling을 이  J2EE Cotainer가 처리해준다는
것이 전제 되어있다는 것이다.

이로 인해 JMS pooling 처리를 하지 않고, JmsTemplate 을 사용할 시에 인스턴스 생성상에서 어느정도에
이르르면 에러가 발생하게 된다. (ActiveMQ의 경우, 65535 MessageProducer instances 생성시)

결과적으로 Spring JmsTemplate 은 WAS 기반을 갖추어야만 사용에 문제가 발생하지 않는다는 것이다.
해결책으로는 각 MQ벤더별 Connection에서의 풀링여부를 체크하여 사용하는 방법과
앞선 글에서 소개된 Jencks (pooling  메커니즘으로 처리됨) 를 사용하는 방법이 있다.


Posted by 아름프로

JavaEE 5, Spring 2 and AspectJ 5: dependecy injection magics


After the Filippo disillusion about Java EE 5 dependecy injection I decided to study the problem of integrating dependecy injection capabilities provided by Java EE 5 and those provided by the Spring framework.


The challange is the following: let's assume that a Stateless EJB, let's say "TestEJB", needs the injection of two POJOs, let's say "TestBean1" and "TestBean2", using two different policies: using JNDI (via @Resource annotation) or without JNDI.


The test EJB and the two test beans implements the following interface:



@Local @Remote
public interface Test {
        public abstract String doTest();
}


The two beans just print out a message and return it; let's show TestBean1 (TestBean2 is similar)



public class TestBean1 implements Test {
        public String doTest() {
                String message = "=>TestBean1";
                System.out.println(message);
                return message;
        }
}


Now let's assume that the TestEJB needs to be injected of instances of TestBean1 and TestBean2 in order to print out and return a message partially composed by TestBean1 and TestBean2:



@Stateless
public class TestEJB implements Test {
        public String doTest() {
                String message = "=>TestEJB";
                System.out.println(message);
                return message + "(" + testBean1.doTest() + "," + testBean2.doTest()

+")";
        }
        
        @Resource(name="beans/TestBean1")
        private Test testBean1;
        
        private Test testBean2;

        public void setTestBean2(Test testBean2) {
                this.testBean2 = testBean2;
        }
}


In order to allow the injection of TestBean1 into TestEJB I found the following solution: let's assume that TestBean1 is defined in the Spring application context as follows:



        <bean id="TestBean1" class="test.TestBean1" />


Now let's populate the JNDI with entries that allow the instantiation of test beans using Spring. I used the following class:



public class SpringBeanFactory implements ObjectFactory {
        private static ApplicationContext appContext;

        private static final String BIND_NAME_PREFIX = "beans/";

        public static void populateJNDI(ApplicationContext appCtx) {
                appContext = appCtx;
                try {
                        Context ctx = new InitialContext();
                        String beansDef[] = appCtx.getBeanDefinitionNames();
                        for (int i = 0; i < beansDef.length; i++) {
                                Class beanClass = appCtx.getType(beansDef[i]);
                                String bindName = BIND_NAME_PREFIX + beansDef[i];
                                Reference reference = new Reference(beanClass.getName(),

new StringRefAddr(bindName,beansDef[i]),
                                                SpringBeanFactory.class.getName(), null);
                                ctx.rebind(bindName, reference);
                        }
                } catch (Exception e) {
                        throw new RuntimeException("Unable to populate JNDI from

application context", e);
                }
        }

        public Object getObjectInstance(Object reference, Name name, Context nameCtx,

Hashtable environment)
                        throws Exception {
                String beanName = (String) ((Reference) reference).get(0).getContent();
                return appContext.getBean(beanName, Object.class);
        }
}


The method "populateJNDI" needs to be invoked with the Spring ApplicationContext instance, for example in the "init" method of a Servlet:



public class TestServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;

        public TestServlet() {
                super();
        }

        @Override
        public void doGet(HttpServletRequest req, HttpServletResponse res) throws

ServletException, IOException {
                StringBuffer buf = new StringBuffer();
                buf.append("<html>");
                buf.append("<body>");
                buf.append("Hello from Servlet");
                buf.append("<br/>");
                buf.append("Hello from chain: ");
                buf.append(testEJB.doTest());
                buf.append("</body>");
                buf.append("</html>");


                res.getOutputStream().write(buf.toString().getBytes());
        }
        
        public void init(ServletConfig config) throws ServletException {
                super.init(config);
                ApplicationContext c =

WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
                SpringBeanFactory.populateJNDI(c);
        }

        @EJB
        protected Test testEJB;
}


That's all, the TestBean1 is avaiable for injection to EJBs using the @Resource(name="beans/TestBean1") annotation.


Now the second problem: I want to inject TestBean2 into TestEJB without registering the the bean into JNDI.


The solution uses Spring 2 integration with AspectJ. Let's assume that in the Spring application context is defined the following:



        <aop:spring-configured/>
        
        <bean id="TestEJB" class="test.TestEJB" lazy-init="false">
                <property name="testBean2">
                        <bean name="TestBean2" class="test.TestBean2"/>
                </property>
        </bean>


Now let's add a Spring2 @Configurable annotation to TestEJB:



@Stateless
@Configurable("TestEJB")
public class TestEJB implements Test {
        ...
}


That's all, by compiling the TestEJB with AspectJ using the "spring-aspects.jar" aspect library provided by Spring2, the TestBean2 will be injected into TestEJB.

( Jan 27 2006, 06:01:20 PM CET ) Permalink Comments [1]


Trackback URL: http://jroller.com/trackback/malbari/Weblog/javaee_5_spring_2_and
Posted by 아름프로





Get a better handle on Struts actions, with Spring


Three ways to integrate Struts applications with Spring















Document options


























Set printer orientation to landscape mode

Print this page

Email this page

E-mail this page

Document options requiring JavaScript are not displayed


Discuss


Sample code






Rate this page











Help us improve this content



Level: Intermediate


George Franciscus (george.franciscus@nexcel.ca), Principal, Nexcel


11 Oct 2005


Struts Recipes co-author George Franciscus is back with another great Struts integration recipe -- this time for importing Struts applications into the Spring framework. Follow along as George shows you how to revamp Struts actions so they can be managed just like Spring beans. The result is a boosted web framework that easily reaps the benefits of Spring AOP.

The Inversion of Control (IOC) design pattern has been generating buzz for long enough now that you've surely heard of it. If you've used the Spring framework in any capacity, then you've seen its principles in action. In this article, you'll learn about the power of the IOC pattern first-hand as I use its principles to inject a Struts application into the Spring framework.


The advantages of integrating a Struts application into the Spring framework are manifold. First off, Spring was explicitly designed to resolve some of the real-world problems of JEE, such as complexity, poor performance, testability, and much more. Second, the Spring framework includes an AOP implementation that lets you apply aspect-oriented techniques to normal object-oriented code. Third, some might say that the Spring framework just handles Struts better than Struts handles itself. But that's a matter of opinion, so follow along as I demonstrate three approaches to integrating Struts applications into the Spring framework, and then decide for yourself.


The approaches I demonstrate are all relatively simple to execute but they offer distinctly different advantages. So that you can fully understand each approach, I've created a separate working example for each one. See the Download section for the complete example source code. See Resources to download Struts MVC and the Spring framework.


What's so great about Spring?


Spring creator Rod Johnson took a critical eye to Java™ Enterprise software development and suggested that many enterprise issues could be resolved by the strategic use of the IOC pattern, also known as dependency injection. When Rod and a dedicated team of open-source developers put his theories into practice, the result was the Spring framework. In a nutshell, Spring is a lightweight container that makes it easy to wire objects together using an external XML configuration file. Each object can receive a reference to a dependent object by exposing a JavaBean property, leaving you with the simple task of "wiring them up" in an XML configuration file.










IOC and Spring

IOC is a design pattern that externalizes application logic so that it can be injected into client code rather than written into it. Combining IOC with the use of programming to interfaces, as the Spring framework does, yields an architecture that reduces the client's dependency on implementation-specific logic. See Resources for more on IOC and Spring.


Dependency injection is a powerful feature, but the Spring framework offers much more. Spring supports pluggable transaction managers to give you a broader range of choices for transaction handling. It integrates leading persistence frameworks while also offering a consistent exception hierarchy. Spring also provides a simple mechanism for applying aspect-oriented code against normal, object-oriented code.


Spring AOP lets you use interceptors to intercept application logic at one or more execution points. Interceptors are widely used for for logging because consolidating an application's logging logic in interceptors results in a more readable, functional code base. As you'll soon see, Spring AOP ships with its own interceptors for addressing cross-cutting concerns and also lets you write your own.
















Back to top



Integrating Struts and Spring


Like Struts, Spring can also function as an MVC implementation. Both frameworks have their merits and drawbacks, although most would agree that Struts is still king when it comes to MVC. Many development teams have learned to rely on Struts as the foundation for building quality software under strict deadlines. With so much momentum behind Struts, even development teams that would like to integrate features of the Spring framework don't want to switch to Spring MVC. The good news is that you don't have to. The Spring architecture allows you to connect Struts as your Web framework to Spring-based business and persistence layers. The end result is that you can have your cake and eat it too!


In the recipes that follow, you'll learn three ways to integrate Struts MVC into the Spring framework. I'll expose the cons of each recipe as well as its comparative advantages. Once you've seen all three in action, I'll show you an exciting application of the approach I like best.
















Back to top



Three little recipes


Each of the following integration techniques (or recipes) has its merits, as well as its own particular quirks. I'm partial to only one of them, but knowing them all will deepen your understanding of both Struts and Spring. It will also provide you with a broad range of options for dealing with various scenarios. The recipes are as follows:



  • Use Spring's ActionSupport class to integrate Struts
  • Override the Struts RequestProcessor with Spring's DelegatingRequestProcessor
  • Delegate Struts Action management to the Spring framework

Loading the application context


No matter which technique you use, you will need to use the Spring ContextLoaderPlugin to load the Spring application context for the Struts ActionServlet. Simply add the plug-in to your struts-config.xml file as you would any other plug-in, as shown here:






<plug-in className=
"org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property=
"contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>


As previously mentioned, you'll find the complete source for the three fully functional example applications in the Download section. Each example presents a different approach to combining Struts and Spring for a book-search application. You can follow the basics of the examples here, but download the applications to see all the nitty-gritty details!
















Back to top



Recipe 1. Use Spring's ActionSupport


Creating a Spring context manually is the most intuitive way to integrate Struts with Spring. To make it even easier, Spring offers a little help. The org.springframework.web.struts.ActionSupport class provides a getWebApplicationContext() method to easily obtain a Spring context. All you need to do is extend your action from Spring's ActionSupport instead of the Struts Action class, as shown in Listing 1:


Listing 1. Using ActionSupport to integrate Struts






package ca.nexcel.books.actions;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;
import org.springframework.context.ApplicationContext;
import org.springframework.web.struts.ActionSupport;

import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;

public class SearchSubmit extends ActionSupport { |(1)


public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {

DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");

//the old fashion way
//BookService bookService = new BookServiceImpl();

ApplicationContext ctx =
getWebApplicationContext(); |(2)
BookService bookService =
(BookService) ctx.getBean("bookService"); |(3)

Book book = bookService.read(isbn.trim());

if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError
("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}

request.setAttribute("book", book);
return mapping.findForward("success");
}
}


Let's quickly consider what's happening here. At (1), I create an Action by extending from the Spring ActionSupport class rather than the Struts Action class. At (2), I use the getWebApplicationContext() method to obtain an ApplicationContext. To obtain the business service, I use the context obtained at (2) to look up a Spring bean at (3).


This technique is simple and easy to understand. Unfortunately, it couples the Struts action to the Spring framework. If you ever decide to replace Spring, you would have to rewrite the code. Moreover, because the Struts action isn't under Spring's control, it can't reap the benefits of Spring AOP. This technique may be useful when using multiple independent Spring contexts, but for the most part it's not as desirable a solution as the other two choices.
















Back to top



Recipe 2. Override the RequestProcessor


Decoupling Spring from the Struts action is a much smarter design choice. One way to do this is to override the Struts RequestProcessor processor with the org.springframework.web.struts.DelegatingRequestProcessor class, as shown in Listing 2:


Listing 2. Integration via Spring's DelegatingRequestProcessor






<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>

</form-beans>

<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>

<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="ca.nexcel.books.actions.SearchSubmit"
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>

</action-mappings>

<message-resources parameter="ApplicationResources"/>

<controller processorClass="org.springframework.web.struts.
DelegatingRequestProcessor"/> |(1)

<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>


<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="csntextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>

</struts-config>


Here, I've used the <controller> tag to override the default Struts RequestProcessor with the DelegatingRequestProcessor. My next step is to register the action in my Spring config file, as shown in Listing 3:


Listing 3. Registering an action in the Spring config file






<?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="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>

<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit"> |(1)
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>
</beans>


Note that at (1), I've registered a bean using the name attribute to match the struts-config action mapping name. The SearchSubmit action exposes a JavaBean property, allowing Spring to populate the property at run time, as shown in Listing 4:


Listing 4. A Struts action with a JavaBean property






package ca.nexcel.books.actions;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

import ca.nexcel.books.beans.Book;
import ca.nexcel.books.business.BookService;

public class SearchSubmit extends Action {

private BookService bookService;
public BookService getBookService() {
return bookService;
}

public void setBookService(BookService bookService) { | (1)
this.bookService = bookService;
}

public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {

DynaActionForm searchForm = (DynaActionForm) form;
String isbn = (String) searchForm.get("isbn");

Book book = getBookService().read(isbn.trim()); |(2)

if (null == book) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure") ;
}

request.setAttribute("book", book);
return mapping.findForward("success");
}

}


In Listing 4, you can see how to build the Struts action. At (1), I create a JavaBean property. This property is automatically populated by the DelegatingRequestProcessor. This design protects the Struts action from knowing it's being managed by Spring while giving you all the benefits of Spring's action management framework. Because your Struts actions are oblivious to the existence of Spring, you can swap out Spring for some other inversion of control container without refactoring your Struts code.


While the DelegatingRequestProcessor approach is definitely better than the first one, it does have some problems. If you were using a different RequestProcessor, then you would need to integrate the Spring DelegatingRequestProcessor manually. The added code would become a maintenance hassle and would also reduce your application's flexibility going forward. Moreover, there has been some talk of replacing the Struts RequestProcessor with a chain of command. Such a change would negatively impact the longevity of this solution.
















Back to top



Recipe 3. Delegate action management to Spring


A much better solution is to delegate Struts action management to the Spring framework. You can do this by registering a proxy in the struts-config action mapping. The proxy is responsible for looking up the Struts action in the Spring context. Because the action is under Spring's control, it populates the action's JavaBean properties and leaves the door open to applying features such as Spring's AOP interceptors.


In Listing 5, the Action class is the same as it was in Listing 4. However, the struts-config is a little different:


Listing 5. The delegation method of Spring integration






<?xml version="1.0" encoding="ISO-8859-1" ?>

<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

<struts-config>
<form-beans>
<form-bean name="searchForm"
type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="isbn" type="java.lang.String"/>
</form-bean>

</form-beans>

<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="welcome" path="/welcome.do"/>
<forward name="searchEntry" path="/searchEntry.do"/>
<forward name="searchSubmit" path="/searchSubmit.do"/>
</global-forwards>

<action-mappings>
<action path="/welcome" forward="/WEB-INF/pages/welcome.htm"/>
<action path="/searchEntry" forward="/WEB-INF/pages/search.jsp"/>
<action path="/searchSubmit"
type="org.springframework.web.struts.DelegatingActionProxy" |(1)
input="/searchEntry.do"
validate="true"
name="searchForm">
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>

</action-mappings>

<message-resources parameter="ApplicationResources"/>


<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>


<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation" value="/WEB-INF/beans.xml"/>
</plug-in>


</struts-config>


Listing 5 is a typical struts-config.xml file, except for one small difference. Instead of declaring the action's class name, it registers the name of Spring's proxy class, as shown at (1). The DelegatingActionProxy class uses the action mapping name to look up the action in the Spring context. This is the context that was declared with ContextLoaderPlugIn.


Registering a Struts action as a Spring bean is very straightforward, as shown in Listing 6. I simply create a bean using the name of the action mapping using the <bean> tag's name attribute (in this case, "/searchSubmit"). The action's JavaBean properties are populated like any Spring bean:


Listing 6. Register a Struts action in the Spring context






<?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="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>

<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>

</beans>
















Back to top



The benefits of action delegation


The action-delegation solution is the best of the three. The Struts action has no knowledge of Spring and could be used in non-Spring applications without changing a single line of code. It's not at the mercy of a change to the RequestProcessor, and it can take advantage of Spring's AOP features.


The benefits of action delegation don't stop there, either. Once you have your Struts action under Spring's control, you can leverage Spring to give them more pizzazz. For example, without Spring, all Struts actions must be threadsafe. If you set the <bean> tag's singleton attribute to "false," however, your application will have a newly minted action object on every request. You might not need this feature, but it's nice to know you have it in your back pocket. You can also take advantage of Spring's lifecycle methods. For example, the <bean> tag's init-method attribute is used to run a method when the Struts action is instantiated. Similarly, the destroy-method attribute executes a method just before the bean is removed from the container. These methods are a great way to manage expensive objects in much the same way as the Servlet lifecycle does.
















Back to top



Intercepting Struts


As previously mentioned, one of the chief advantages of combining Struts and Spring, and doing it by delegating Struts actions to the Spring framework, is that you can apply Spring's AOP interceptors to your Struts actions. By applying Spring interceptors to Struts actions, you can tackle cross-cutting concerns with minimal effort.


Spring offers a few built-in interceptors, but I'll show you how to create your own and apply it to a Struts action. To use an interceptor, you need to do three things:



  1. Create the interceptor.
  2. Register it.
  3. Declare where it will intersect the code.

This is pretty simple stuff but also very powerful. For example, in Listing 7, I create a logging interceptor for a Struts action. This interceptor prints out a statement before every method call:


Listing 7. A simple logging interceptor






package ca.nexcel.books.interceptors;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class LoggingInterceptor implements MethodBeforeAdvice {

public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("logging before!");
}
}


This interceptor is very simple. The before() method is executed before every method in its intersection. In this case, it prints out a statement, but it could do anything you like. The next step is to register the interceptor in the Spring configuration file, shown in Listing 8:


Listing 8. Registering the interceptor in the Spring config file






<?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="bookService" class="ca.nexcel.books.business.BookServiceImpl"/>

<bean name="/searchSubmit"
class="ca.nexcel.books.actions.SearchSubmit">
<property name="bookService">
<ref bean="bookService"/>
</property>
</bean>

<!-- Interceptors -->
<bean name="logger"
class="ca.nexcel.books.interceptors.LoggingInterceptor"/> |(1)

<!-- AutoProxies -->
<bean name="loggingAutoProxy"
class="org.springframework.aop.framework.autoproxy.
BeanNameAutoProxyCreator"> |(2)
<property name="beanNames">
<value>/searchSubmit</valuesgt; |(3)
</property>
<property name="interceptorNames">
<list>
<value>logger</value> |(4)
</list>
</property>
</bean>

</beans>


As you've probably noticed, Listing 8 extends the application shown in Listing 6 to include an interceptor. Details are as follows:



  • At (1), I register the interceptor.
  • At (2), I create a bean name autoproxy describing how the interceptor is applied. There are other ways to define intersections, but this approach is common and easy to do.
  • At (3), I register the Struts action as the bean that will be intercepted. If you wanted to intersect other Struts actions, then you could simply create additional <value> tags under "beanNames."
  • At (4), when the interception occurs, I execute the name of the interceptor bean created at (1). All the interceptors listed here are applied against the "beanNames."

That's it! As this example shows, putting your Struts actions under control of the Spring framework opens up a whole new set of options for handling your Struts applications. In the case of this example, action delegation makes it easy to utilize Spring interceptors for better logging in Struts applications.
















Back to top



In conclusion


In this article, you learned three recipes for integrating Struts actions into the Spring framework. Using Spring's ActionSupport to integrate Struts (as I did in the first recipe) is quick and easy but couples your Struts actions to the Spring framework. If you ever needed to port the application to a different framework you would need to rewrite the code. The second solution of delegating the RequestProcessor cleverly decouples your code, but it doesn't necessarily scale well and may not last long if the Struts RequestProcessor is revised to a chain of command. The third approach is the best of the three: delegating Struts actions to the Spring framework results in decoupled code that lets you utilize Spring's features (such as logging interceptors) in your Struts applications.


Each of the three Struts-Spring integration recipes is realized as a complete working application. See the Download section to study them in detail.

















Back to top



Downloads























Description Name Size  Download method
ActionSupport sample code j-sr2-actionsupport.zip 5 MB FTP
RequestProcessor sample code j-sr2-requestprocessor.zip 5 MB FTP
Delegate sample code j-sr2-delegate.zip 5 MB FTP










Information about download methods Get Adobe® Reader®















Back to top



Resources

Learn


Get products and technologies


Discuss
















Back to top



About the author










George Franciscus is a Java Enterprise consultant and Struts authority. He is a coauthor of Manning's Struts Recipes and Struts in Action. George offers technical and management consulting services through nexcel.ca.


Posted by 아름프로
EHCache, JCS and OSCache

http://ehcache.sourceforge.net/
http://jakarta.apache.org/jcs/
http://www.opensymphony.com/oscache/

좀 더 자세한 내용은 ...
https://springmodules.dev.java.net/
Posted by 아름프로
MDBs must be run within an EJB container. Depending on the architecture of your app, this may be an excessive requirement, especially if you aren't use any other EJBs and do not require the features of a full-blown EJB container. Message-driven POJOs, on the other hand, can run anywhere, even (as shown here) in a simple main() method. The only requirement is an ActiveMQ message queue.


MDBs require that you implement the lifecycle methods of javax.ejb.MessageDrivenBean. Often these lifecycle methods aren't needed and are left as empty implementations. This isn't a real problem, except that it's simply unnecessary.


Although it may not be apparent from the simple HelloBean example, message-driven POJOs can take full advantage of the dependency injection and AOP support offered by Spring (including Spring's support for declarative transactions and Acegi's support for declarative security). In short, you can do anything with the POJO that you can do with any other bean in a Spring context.


The XML used to declare a message-driven POJO is slightly more verbose then for an MDB. You should, however, keep in mind that you'll only need to declare one JCAContainer bean, regardless of how many message-driven POJOs your application has.
Posted by 아름프로
POJO Application Frameworks: Spring Vs. EJB 3.0

이 결과가 어떻게 날지.. ~~ 미리 고민들 해보시죠..

개인적인 생각으로는 EJB의 사상과 Annotation 가지고는
Spring의 DI 사상과 AOP 등등++++ 에게 안될꺼 같다는...
Posted by 아름프로
POJO 로 MDB (Message Driven Bean)에서의 javax.ejb.MessageDrivenBean 를
구현하지 않아도 된다.
단, MessageListener 구현해야만 한다.

그 외에는 구현 내용은 비슷하고..
설정에 대한 부분은 링크를 참조하기 바란다.

WAS나 MOM에 종속되지 않는 솔루션 개발 가능하다...
Posted by 아름프로

Java Boutique

2005. 7. 5. 00:13
제목과 같습니다. ^^
짧게 요약 잘되어 있네요.
Posted by 아름프로
Persistence와 POJO: 오브젝트 및 관계형 모델의 통합
Persistence and POJOs: Bridging the Object and Relational Worlds

~~ ^^ 좋은 내용이네요..
그냥 링크만 합니다.
Posted by 아름프로

Spring Web Flow

2005. 5. 17. 13:01


alt="Spring Web Flow">





May 2005



Discuss this Article






Introduction


Have you found as your web application gets more complex, understanding and managing the page flow – the orchestration that drives your application use cases – gets harder and harder? Are you tired of being forced into very particular ways of doing things that dont give you much reuse? Do you feel youre spending too much time developing your own approaches to generic problems like session state management?


Enter Spring Web Flow.


What is Spring Web Flow?


Spring Web Flow (SWF) is an emerging module of The Spring Framework. The module is part of Springs web application development stack, which includes Spring MVC.


Spring Web Flow aims to be the best solution for the management of web application page flow. It is a powerful controller for use when your applications demand complex controlled navigations, such as wizards, to guide the user through a series of steps within a larger application transaction.


An example of such a controlled navigation is illustrated as a UML State Diagram below:



Figure 1 - An Example Flight Booking Flow


Astute readers will recognize this as a typical flight booking flow – the kind you participate every time you book an airline reservation on-line.


Why Does Spring Web Flow Exist?


In traditional web applications, page flows like the one above are not explicit—they are not first class citizens. Take a webapp built on Struts, for example. To implement a page flow in Struts, most developers build on what the framework provides them: actions and views. In this case, a single action is associated with a specific request URL. When a request comes in at that URL, the action is executed. During execution, the action performs some processing and then selects an appropriate result view for display. Its that simple.


So to implement a multi-step page flow in Struts, individual actions are chained together through the various views. Action URLs to process different events like back or submit are hard-coded into each view. Some form of ad-hoc session storage is used to manage flow state. Redirect after post is used to prevent duplicate submissions, etc.


Although this is a simple and functional approach, it has a major disadvantage: the overall page flow of the web application is not clear from looking at the action definitions in the struts-config.xml file. You cant see the forest – the flow – from the trees – the many action and view definitions. Flexibility also suffers since actions and views cannot be easily reused. Finally, you simply have to do too much work—it should be easier!


Spring MVC offers a slightly higher level of functionality: form controllers that implement a predefined page flow. Two such controllers are provided out of the box: SimpleFormController and AbstractWizardFormController. However, these are still specific examples of a more general page flow concept.


Tapestry and JSF use an event-driven approach at the page level, rather than the request level, where each page and its backing controller logic are kept together. However, neither provides first-class support for a logical page flow with a well-defined lifecycle that spans several pages and potentially different paths. As youll see, the lifecycle of such a page flow is longer than a single request, but shorter than a session.


This is where Spring Web Flow comes in, allowing you to represent the page flow of a web application in a clear and simple way, and reuse it anywhere, including environments like Struts, Spring MVC, Tapestry, JSF, and even Portlets.


Advantages


As you will see, Spring Web Flow offers several advantages:



  • The page flow in a web application is clearly visible by looking at the corresponding web flow definition (in an XML file or Java class).

  • Web flows are designed to be self contained. This allows you to see a part of your application as a module you can reuse in multiple situations.

  • Web flows capture any reasonable page flow in a web application always using the same consistent technique. You're not forced into using specialized controllers for very particular situations.

  • Finally, a web flow is a first-class citizen with a well-defined contract for use. It has a clear, observable lifecycle that is managed for you automatically. Simply put, the system manages the complexity for you and as a result is very easy to use.


How does Spring Web Flow Work?


For now it suffices to say that a web flow is composed of a set of states. A state is a point in the flow where something happens; for instance, displaying a view or executing an action. Each state has one or more transitions that are used to move to another state.


A transition is triggered by an event .


The Book Flight Sample Web Flow


To demonstrate what a web flow definition looks like, the following piece of XML captures the flight booking process illustrated in the UML state diagram above:




"http://www.springframework.org/dtd/spring-webflow.dtd">


























then="enterPassengerInformation" else="displayReservationVerification"/>




































Figure 2 – A XML-based Flight Booking Flow definition


As you can see, just from scanning the XML definition, the logical flow driving the booking process is clearly discernable, even if you dont yet know about Spring Web Flow implementation details.


And if you look a bit closer, youll see two subflows that spawn child processes of the booking flow. The first subflow guides the user through entering his passenger information. The second has the user make his seat assignments. The ability to nest flows that act as mini application modules is one of the most powerful capabilities of Spring Web Flow.


You could show the definition above to a business analyst and shed probably get it. Better yet, you could engineer a visual diagram from this definition and present that to a business analyst for review. Tools to do exactly this are already appearing.


The Book Flight Flow Explained


The next part of this article breaks down the key parts of the above Book flight definition, and provides supporting dialog that illustrates how Spring Web Flow works.


The Flow Definition

Starting with line 1 of the XML-based flow definition:




...


The webflow element defines the flow, specifying its id and start-state. The id is simply a unique identifier. The start state is the first state to transition to when a new flow session is activated at runtime.


So for this business case, when a new bookflight session is activated, it transitions to the obtainTripInfo state.


The Obtain Trip Info Action State

Moving on to the obtainTripInfo state definition.









Recall that when states are entered, behavior happens. As youll see, there are different state types that execute different behaviors. An action state, like obtainTripInfoabove, executes an action when entered. That action returns the logical result of its execution, and that result is mapped to a state transition. Its that simple.


So for this business case, obtainTripInfo, when entered, executes the bindAndValidate method on the Action implementation with the bookingActions identifier. This method binds form input from the browser to a Trip domain object and validates it. If that process is successful, the suggestItineraries state is entered. If an error occurs, the tryAgain state is entered.


The Booking Action

When using Spring Web Flow with Spring IoC, the bean attribute of the action element refers to the name of an Action implementation exported in the Spring Application Context. Here, the bookingActions bean definition looks like this:



web-context.xml

class="org.springframework.samples.bookflight.BookingActions">



This allows our action implementation to be managed by Spring and configured via dependency injection.


The Suggest Itineraries Action State

Now take a look at the next action state that, given a bound and validated Trip object as input, returns a collection of suggested itineraries:








The actual implementation code required to make this happen is straightforward:



public class BookingActions extends FormAction {
...
public Event suggestItineraries(RequestContext context) {
Trip trip = (Trip)context.getRequestScope().getAttribute("trip");
Collection itineraries = bookingAgent.suggestItineraries(trip);
context.getRequestScope().setAttribute("itineraries", itineraries);
return success();
}
}

When the suggestItineraries state is entered, the suggestItineraries method is invoked. The other action states work in exactly the same way: entering the state invokes a method on the target action bean.


The Display Suggested Itineraries View State

Once a collection of suggested itineraries is returned, the next step has the user review them so she may select the best one. This is accomplished by the following state definition:








As you can see, displaySuggestedItineraries is a view state—a state type we have not yet discussed. A view state, when entered, causes the executing flow to pause, and returns control back to the client with instruction to render the configured view. Later, after some user think-time, the client signals an event describing what action the user took. That resumes the flow, and the event that occurred is mapped to a state transition, which takes the user to the next step in the flow. Again, its that simple.


So for this business case, when the displaySuggestedItineraries state is entered the suggestedIteneraries view is rendered and control returns to the browser. The user then decides which itinerary she wants and clicks the select button. That signals the select event, passing in the id of the selected itinerary as an event parameter.


The user may also choose to startOver, at which time the flow transitions to the cancel state.


Note it is the responsibility of the client environment the flow is hosted in to map the requested view name, like suggestedItineraries, to a renderable view template, like /WEB-INF/jsp/suggestedIternaries.jsp. For example, in Spring MVC, the FlowController does this using the familiar ModelAndView and ViewResolver constructs. In Struts, the FlowAction does this using the familiar ActionForward.


Client Side State

At this point you might ask:


since the executing flow is paused when a ViewState is entered, and control is returned to the browser, how is the same flow picked up and resumed on subsequent events?


The answer is the client tracks the unique idof the executing flow, and provides it as input when the next event is signaled. This is typically done using a hidden form field.


For example, in a jsp:



">

The Is Passenger Info Required? Decision State

After the user selects the Itinerary she wants, the flow has to make a contextual decision about where to go next.


Specifically, if the user has not logged in, or she has logged in but wishes to confirm her passenger information – like the credit card she will use – the flow should allow her to enter that information. On the other hand, if she has already logged in and wishes to go straight to the booking page, the flow should skip this optional step.


Basically, a dynamic decision has to be made that takes into account the users information and preferences.


The decision state is perfect for this. See the definition below:





then="enterPassengerInformation" else="displayReservationVerification"/>


The Enter Passenger Information SubFlow State

The process of managing passenger information is logically independent of the booking process. It is one part within that process, yes, but it certainly makes sense a user would want to edit her information outside of the booking context.


Subflow states facilitate this. When a subflow state is entered, a child flow is spawned. The parent flow is suspended until the child flow ends. This lets you view your application as a set of self-contained modules – flows – that you can easily embed in multiple situations in a consistent manner.


Take a look at the enterPassengerInformation subflow state:










The flow attribute is the id of the flow to spawn when this state is entered. The attribute-mapper element maps attributes to and from the subflow. Input mappings map attributes down to the subflow. Output mappings map attributes back up to the parent flow when the subflow ends. As you can see, expressions (in this case OGNL) are also supported.


So for this business case, when the enterPassengerInformation state is entered, the passenger flow is spawned. The passengerId attribute is passed down to the flow as input. From there, the subflow does whatever it wants. Its a black box as far the parent flow is concerned. When the subflow ends, the parent flow resumes, responding to the ending result to determine where to go next—in this case, to reservation verification.


The Display Confirmation End State

There is one last core state type that has yet to be discussed: the end state. When an end state is entered, the active flow session terminates. Upon termination, all resources associated with the flow are cleaned up for you automatically.


Below is the displayConfirmation end state that displays confirmation after an itinerary is successfully booked:




When this state is entered, the bookflight flow ends and the reservationConfirmation view displays.  Because the bookflight flow was acting as the root flow, and not a subflow, it and any allocated resources are automatically cleaned up.


Note: had the ending flow been acting as a subflow, the entered end state is treated as a subflow result the resuming parent flow can respond to.  More specifically, the entered end state ID is used as grounds for a state transition in the resuming parent flow's subflow state.  You can see this in action by taking a look at the "enterPassengerInformation" subflow state definition.  Note how it responds to the "finish" result of the subflow, which corresponds to a "finish" end state within the passenger flow.


Flow Deployment


So far youve learned what Spring Web Flow is all about, and youve seen an example of a realistic flow definition. What you havent seen yet is how to deploy that flow definition for execution in a particular environment, like Spring MVC in a servlet environment.


Doing this is a cinch. Heres all you have to do with Spring MVC:













This automatically exports the bookingFlow at the /booking.htm URL for use in a servlet environment.


Advanced Topics


The following section introduces some of the more advanced features of Spring Web Flow.


Flow Execution Listeners


The FlowExecutionListener construct is an observer that allows you to listen and respond to the lifecycle of an executing flow. You can use this feature to do anything from state precondition and post condition checks, to auditing and security.


Flow Execution Storage Strategies


The mechanism by which the state of an executing flow is saved and restored is fully pluggable. HttpSession-based storage is the default, and SWF provides two other storage strategies out of the box: one using server-side continuation-based session storage, another using full client-side serialization. Defining your own custom storage, for example to store flow state in a Database, is trivial.


When Is Spring Web Flow Right For You?


It should be noted that Spring Web Flow is not a one-size-fits-all solution. As youve seen, its a stateful system that automates the management of page flows that drive business processes. It should not be used when simpler, stateless solutions are more appropriate. For example, it should not be used where sites require free navigations, where the user is free to click around anywhere they please. Spring Web Flow is designed to power controlled navigations, where the user is guided through a process with a clear business goal and lifecycle.


To further make the use case more concrete, here are some examples of good flows, where the SWF system would be appropriate:



  • Book a flight

  • Pay your taxes

  • Apply for a loan


Here are some examples where Spring Web Flow would not be appropriate:



  • Index pages

  • Welcome pages

  • Menus

  • Simple form flows (one page)


Spring Web Flow is meant to be used as a compliment to traditional controllers within any web environment, such as Spring MVC, Struts, Tapestry, Web Work, JSF, or Portlets. A single site should combine use of simple controllers with web flows where appropriate.


Road Map


Spring Web Flow 1.0 final will be released with Spring 1.3, scheduled right before JavaOne in June. Between now and then, expect regular, stable-for-development-use preview releases. The offering is already quite mature in terms of feature set and sample applications.


As the development team pushes closer to a final release, here are some of the most important features we will be working on:


Integration


As a standalone library, Spring Web Flow is a strong fit for integration with other frameworks. Out of the box Spring MVC, Struts, and Portlet MVC integration is already provided. JSF and Tapestry integration are expected by the final release.


Flow Management


With Spring 1.2, exporting beans in an MBeanServer for management and monitoring is easy. A strongly typed FlowExecutionMBean management interface already exists, and we plan to extend that so global statistics on all flows executing on the server can be centrally monitored through a JMX console.


Pluggability


Every construct in the system will be made pluggable for easy extension and customization, even from the xml definition. This includes States and Transitions, among other concepts.


Compensating Transactions


Supporting features and sample applications demonstrating use of compensating transactions to rollback previously committed work during execution of a flow is of high interest to us.


Conclusion


Spring Web Flow is a powerful solution for managing controlled navigations that drive business processes. And its fun to work with. If you havent tried it already, what are you waiting for?


References


Spring Web Flow is covered in the Core Spring training course offered by Interface21 - http://www.springframework.com/training


The Spring Framework, http://www.springframework.org


The Spring Web Flow Wiki, http://opensource.atlassian.com/confluence/spring/display/WEBFLOW/Home


The kdonald blog, http://www.jroller.com/page/kdonald


Struts, http://struts.apache.org


Java Server Faces, http://java.sun.com/j2ee/javaserverfaces/


Tapestry, http://jakarta.apache.org/tapestry


WebWork, http://www.opensymphony.com/webwork/


JMX, http://java.sun.com/jmx


JavaOne, http://java.sun.com/javaone/



Biographies


Keith Donald is an Interface21 principal and a core Spring Framework project member. An experienced developer and mentor, Keith has built applications for customers spanning a diverse set of industries including banking, network management, information assurance, education, and retail. He specializes in translating business requirements into technical solutions. Keith is the founder of the Spring Rich Client Project and co-lead of Spring Web Flow with Erwin Vervaet. Lately you can find him leading Spring Training courses across the US and abroad, and as a guest speaker on Spring with the NoFluffJustStuff (NFJS) tour.


Erwin Vervaet is a software engineer with a keen interest in applying modern IT concepts and tools. He has been using the Java language since 1996, and has a master's degree in computer science from the Katholieke Universiteit Leuven in Belgium. He has been involved in IT research, e-commerce projects, open source initiatives, and industrial software systems. Erwin currently works as an independent consultant.





PRINTER FRIENDLY VERSION



Posted by 아름프로

BLOG main image

카테고리

분류 전체보기 (539)
이야기방 (19)
토론/정보/사설 (16)
IBM Rational (9)
U-IT (0)
SOA/WS/ebXML (110)
개발방법론/모델링 (122)
J2SE (34)
J2EE (60)
DataBase (39)
Open Projects (30)
WebWork (0)
Hibernate (4)
xdoclet (0)
jfree (0)
iBATIS (1)
Mule (1)
ServiceMix (0)
ActiveMQ (1)
Drools (2)
JBoss (1)
XML관련 (8)
Spring (12)
BP/표준화 (50)
Apache Projects (15)
Web/보안/OS (22)
Tools (7)
AJAX/WEB2.0 (1)
Linux/Unix (1)
영어 (0)
비공개방 (0)

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

달력

«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

글 보관함

Total :
Today : Yesterday :