Spring Framework
  1. Spring Framework
  2. SPR-9044

Support simplified main class application context / dependency management

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Minor Minor
    • Resolution: Won't Fix
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: Core
    • Labels:
    • Last commented by a User:
      false

      Description

      Problem

      One common request I see quite frequently on the internet is the ability to have spring autowire a main class:

      There is no shortage of questions / solutions to this problem which illustrates a need for a standardized approach.

      Solution

      What I am proposing is combination of features between the following existing classes:

      1. org.springframework.test.context.junit4.SpringJUnit4ClassRunner - provides functionality of the Spring TestContext Framework to standard JUnit 4.5+ tests
      2. org.springframework.test.context.ContextConfiguration - class-level metadata that is used to determine how to load and configure an ApplicationContext for test classes
      3. org.springframework.web.context.support.SpringBeanAutowiringSupport a convenient base class for self-autowiring classes that gets constructed within a Spring-based web application.

      Thus provinding first class support for console based application context management and DI.

      Features

      1. Autowiring of main class dependencies
      2. Auto-destruction of application context
      3. Ability in the future to handle command line arguments as beans

      Properties

      1. Standardization
      2. Consistency with other APIs
      3. Minimal configuration
      4. Intent revealing

      Example

      My visions is something like the following:

      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.MainSupport;
      import org.springframework.context.ContextConfiguration;
      import org.springframework.context.support.AnnotationConfigContextLoader;
      
      @ContextConfiguration(classes=AppConfig.class, loader=AnnotationConfigContextLoader.class)
      public class Main extends MainSupport {
          
          @Autowired
          private Service service;
      
          public static void main( String[] args ) {
              // MainSupport.execute
              execute(args);
          }
          
          @Main
          public void main() {
              service.run();
          }
          
      }
      

      The way this would work is as follows:

      1. JVM calls main
      2. main delegates to super class method MainSupport.execute provided by spring (analog of SpringBeanAutowiringSupport)
      3. MainSupport.execute reads the @ContextConfiguration annotation and looks for a @Main annotation (analog of @Test)
      4. MainSupport.execute creates the application context
      5. MainSupport.execute create an application Main class instance
      6. MainSupport.execute injects dependencies
      7. MainSupport.execute wraps instance in a proxy that will advise the method annotated with @Main. This proxy will first call the annotated method and then destroy the application context

        Issue Links

          Activity

          Show
          Bob Tiernay added a comment - Some additional related posts: http://tmarthal.blogspot.com/2008/02/spring-framework-sample-main-method.html http://blog.jason-stillwell.com/2011/02/spring-java-based-configuration-and.html http://forum.springsource.org/showthread.php?91562 http://stackoverflow.com/questions/2497627/what-should-the-java-main-method-be-for-a-standalone-application-for-spring-jms http://forum.springsource.org/showthread.php?48197-spring-standalone-app http://www.devdaily.com/blog/post/java/load-spring-application-context-file-java-swing-application http://www.springbyexample.org/examples/intro-to-ioc-creating-a-spring-application.html http://happygiraffe.net/blog/2008/08/16/bootstrapping-spring/ http://forum.springsource.org/showthread.php?11252-Bootstrapping-IoC-container-in-Spring-standalone-app http://stackoverflow.com/questions/171130/autostart-spring-app/8954259#8954259
          Hide
          Bob Tiernay added a comment -

          As a further simplification / enhancement, MainSupport could resemble the following:

          @ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
          public class Main extends MainSupport {
          
              @Autowired
              private Service service;
          
              @Resource
              private String[] args;
          
              @Value("#{args[0]}")
              private String value;
          
              public static void main( String[] args ) {
                  main( Main.class, args );
              }
          
              @Override
              public void main() {
                  service.run( value );
              }
          
          }
          

          In the above there are a few things to note:

          • execute in MainSupport has been renamed to main for greater clarity / consistency
          • The class literal Main.class is required for static context initialization
          • If @Main is omitted, public void main() is called (Defined in MainSupport)
          • A named bean args is created and injected by name
          • The args bean is available for @Value consumption

          Having args as a bean is powerful since it enables the ability to perform command line processing / binding in AppConfig, the main configuration of the application context. This is one area in spring where there is currently an impedance mismatch for console based applications.

          Show
          Bob Tiernay added a comment - As a further simplification / enhancement, MainSupport could resemble the following: @ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class) public class Main extends MainSupport { @Autowired private Service service; @Resource private String [] args; @Value( "#{args[0]}" ) private String value; public static void main( String [] args ) { main( Main.class, args ); } @Override public void main() { service.run( value ); } } In the above there are a few things to note: execute in MainSupport has been renamed to main for greater clarity / consistency The class literal Main.class is required for static context initialization If @Main is omitted, public void main() is called (Defined in MainSupport ) A named bean args is created and injected by name The args bean is available for @Value consumption Having args as a bean is powerful since it enables the ability to perform command line processing / binding in AppConfig , the main configuration of the application context. This is one area in spring where there is currently an impedance mismatch for console based applications.
          Hide
          Dave Syer added a comment -

          There's a lot of nice stuff here. There's also a duplicate at SPR-8077.

          I wonder if there's really any need to write a main() method at all as a Spring user though - these days it makes a lot more sense to put all app specific java code in an @Configuration, and then a generic main could just load a context (and maybe do nothing, eg if a web or other server is launched as a context bean, or maybe just evaluate an expression with the bean factory as context).

          Show
          Dave Syer added a comment - There's a lot of nice stuff here. There's also a duplicate at SPR-8077 . I wonder if there's really any need to write a main() method at all as a Spring user though - these days it makes a lot more sense to put all app specific java code in an @Configuration, and then a generic main could just load a context (and maybe do nothing, eg if a web or other server is launched as a context bean, or maybe just evaluate an expression with the bean factory as context).
          Hide
          Phil Webb added a comment -

          Rather than fix this as part of the core Spring Framework we have decided to start a new project called Spring Boot that addresses this and a number of other issues.

          The GitHub project is at https://github.com/SpringSource/spring-boot and this blog post provides a general overview.

          Show
          Phil Webb added a comment - Rather than fix this as part of the core Spring Framework we have decided to start a new project called Spring Boot that addresses this and a number of other issues. The GitHub project is at https://github.com/SpringSource/spring-boot and this blog post provides a general overview.

            People

            • Assignee:
              Phil Webb
              Reporter:
              Bob Tiernay
              Last updater:
              Phil Webb
            • Votes:
              4 Vote for this issue
              Watchers:
              10 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                36 weeks, 4 days ago