Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support simplified main class application context / dependency management [SPR-9044] #13684

Closed
spring-issuemaster opened this issue Jan 21, 2012 · 4 comments

Comments

Projects
None yet
2 participants
@spring-issuemaster
Copy link
Collaborator

commented Jan 21, 2012

Bob Tiernay opened SPR-9044 and commented

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:

  • #12732 Provide Java main() for launching Spring applications

4 votes, 10 watchers

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Jan 21, 2012

Bob Tiernay commented

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.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 23, 2012

Dave Syer commented

There's a lot of nice stuff here. There's also a duplicate at #12732.

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).

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Aug 6, 2013

Phil Webb commented

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.