[bs-92] Add simple main wrapper for SpringApplication

* Added Spring class
* Used in demo project in README
* Also fixed cycle in spring-bootstrap jar

[Fixes #49121565]
This commit is contained in:
Dave Syer 2013-05-02 15:33:35 +01:00
parent 0a730beb2a
commit 504d96eb51
14 changed files with 200 additions and 57 deletions

View File

@ -195,9 +195,9 @@
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0.2</version>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@ -12,6 +12,7 @@
<properties>
<main.basedir>${project.basedir}/..</main.basedir>
<spring.bootstrap.version>0.0.1-SNAPSHOT</spring.bootstrap.version>
<start-class>org.springframework.bootstrap.main.Spring</start-class>
</properties>
<modules>
<module>spring-bootstrap-application</module>

View File

@ -55,7 +55,6 @@ If you are using Maven create a really simple `pom.xml` with 2 dependencies:
</parent>
<properties>
<spring.bootstrap.version>0.0.1-SNAPSHOT</spring.bootstrap.version>
<start-class>org.springframework.bootstrap.SpringApplication</start-class>
</properties>
<dependencies>
<dependency>
@ -139,11 +138,14 @@ endpoint. An endpoint can be implemented as a Spring MVC
You can launch that straight away using the Spring Bootstrap CLI
(without the `@EnableAutoConfiguration` and even without the import
statements that your IDE will add if you are using one), or you can
use the main method to launch it from your project jar. Just change
the `start-class` in the `pom` above to the fully qualified name of
your `SampleController`, e.g.
use the main method to launch it from your project jar. Just add a
`start-class` in the properties section of the `pom` above pointing to
the fully qualified name of your `SampleController`, e.g.
<start-class>com.mycompany.sample.SampleController</start-class>
<properties>
<spring.bootstrap.version>0.0.1-SNAPSHOT</spring.bootstrap.version>
<start-class>com.mycompany.sample.SampleController</start-class>
</properties>
and re-package:

View File

@ -16,6 +16,7 @@
package org.springframework.bootstrap.autoconfigure.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
import org.springframework.bootstrap.service.audit.AuditEventRepository;
import org.springframework.bootstrap.service.audit.InMemoryAuditEventRepository;
@ -47,11 +48,13 @@ public class AuditConfiguration {
}
@Bean
@ConditionalOnClass(name = "org.springframework.security.authentication.event.AbstractAuthenticationEvent")
public AuthenticationAuditListener authenticationAuditListener() throws Exception {
return new AuthenticationAuditListener();
}
@Bean
@ConditionalOnClass(name = "org.springframework.security.access.event.AbstractAuthorizationEvent")
public AuthorizationAuditListener authorizationAuditListener() throws Exception {
return new AuthorizationAuditListener();
}

View File

@ -27,8 +27,8 @@
</dependency>
<!-- Optional -->
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
@ -119,6 +119,22 @@
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.0.0.GA</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>

View File

@ -27,10 +27,6 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.bootstrap.autoconfigure.batch.BatchAutoConfiguration;
import org.springframework.bootstrap.autoconfigure.data.JpaRepositoriesAutoConfiguration;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
@ -60,9 +56,8 @@ import org.springframework.web.context.ConfigurableWebApplicationContext;
* application:
*
* <ul>
* <li>Create an appropriate {@link ApplicationContext} instance (
* {@link AnnotationConfigApplicationContext} or
* {@link AnnotationConfigEmbeddedWebApplicationContext} depending on your classpath)</li>
* <li>Create an appropriate {@link ApplicationContext} instance (depending on your
* classpath)</li>
*
* <li>Register a {@link CommandLinePropertySource} to expose command line arguments as
* Spring properties</li>
@ -128,7 +123,7 @@ public class SpringApplication {
private static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";
private static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.bootstrap."
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.bootstrap."
+ "context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
@ -499,9 +494,8 @@ public class SpringApplication {
/**
* Sets the type of Spring {@link ApplicationContext} that will be created. If not
* specified defaults to {@link AnnotationConfigEmbeddedWebApplicationContext} for web
* based applications or {@link AnnotationConfigApplicationContext} for non web based
* applications.
* specified defaults to {@link #DEFAULT_WEB_CONTEXT_CLASS} for web based applications
* or {@link AnnotationConfigApplicationContext} for non web based applications.
* @param applicationContextClass the context class to set
* @see #setApplicationContext(ApplicationContext)
*/
@ -512,9 +506,9 @@ public class SpringApplication {
/**
* Sets a Spring {@link ApplicationContext} that will be used for the application. If
* not specified an {@link AnnotationConfigEmbeddedWebApplicationContext} will be
* created for web based applications or an {@link AnnotationConfigApplicationContext}
* for non web based applications.
* not specified an {@link #DEFAULT_WEB_CONTEXT_CLASS} will be created for web based
* applications or an {@link AnnotationConfigApplicationContext} for non web based
* applications.
* @param applicationContext the spring application context.
* @see #setApplicationContextClass(Class)
*/
@ -611,22 +605,4 @@ public class SpringApplication {
}
/**
* A basic main that can be used to launch an autoconfigured application. Useful for
* demos and testing, perhaps less for production use (where the run methods are more
* appropriate).
*
* @param args command line arguments
* @see #run(Object[], String[])
* @see #run(Object, String...)
*/
public static void main(String[] args) {
run(new Class<?>[] { AutoMain.class }, args);
}
@EnableAutoConfiguration(exclude = { JpaRepositoriesAutoConfiguration.class,
BatchAutoConfiguration.class })
public static class AutoMain {
}
}

View File

@ -19,6 +19,7 @@ package org.springframework.bootstrap.autoconfigure.batch;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.bootstrap.CommandLineRunner;
import org.springframework.bootstrap.ExitCodeGenerator;
import org.springframework.bootstrap.context.annotation.ConditionalOnBean;
import org.springframework.bootstrap.context.annotation.ConditionalOnClass;
import org.springframework.bootstrap.context.annotation.ConditionalOnMissingBean;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
@ -42,12 +43,14 @@ public class BatchAutoConfiguration {
@Bean
@ConditionalOnMissingBean({ CommandLineRunner.class })
@ConditionalOnBean({ JobLauncher.class })
public JobLauncherCommandLineRunner jobLauncherCommandLineRunner() {
return new JobLauncherCommandLineRunner();
}
@Bean
@ConditionalOnMissingBean({ ExitCodeGenerator.class })
@ConditionalOnBean({ JobLauncher.class })
public ExitCodeGenerator jobExecutionExitCodeGenerator() {
return new JobExecutionExitCodeGenerator();
}

View File

@ -22,7 +22,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.bootstrap.bind.PropertySourcesBindingPostProcessor;
/**
* Annotation for externalized configuration. Add this to a class definition if you want

View File

@ -20,7 +20,6 @@ import java.lang.reflect.Field;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.bootstrap.bind.PropertySourcesBindingPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@ -63,7 +63,7 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
public @interface EnableAutoConfiguration {
/**
* Exclude a specific auto-configuration class such that it will never be applied.
* Exclude specific auto-configuration classes such that they will never be applied.
*/
Class<?>[] exclude() default {};

View File

@ -14,12 +14,12 @@
* limitations under the License.
*/
package org.springframework.bootstrap.bind;
package org.springframework.bootstrap.context.annotation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.bootstrap.context.annotation.ConfigurationProperties;
import org.springframework.bootstrap.bind.PropertiesConfigurationFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.PropertySources;

View File

@ -0,0 +1,93 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.bootstrap.main;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.LogFactory;
import org.springframework.bootstrap.SpringApplication;
import org.springframework.bootstrap.context.annotation.EnableAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.SpringVersion;
import org.springframework.util.ClassUtils;
/**
* Very simple main class that can be used to launch an application from sources (class,
* package or XML). Useful for demos and testing, perhaps less for production use (where
* the {@link SpringApplication} run methods are often more convenient).
*
* @author Dave Syer
*
*/
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Spring {
private static ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
true);
private static ApplicationContext context;
/**
* @return the context if there is one
*/
public static ApplicationContext getApplicationContext() {
return context;
}
/**
* A basic main that can be used to launch an application.
*
* @param args command line arguments
* @see SpringApplication#run(Object[], String[])
* @see SpringApplication#run(Object, String...)
*/
public static void main(String[] args) throws Exception {
List<String> strings = new ArrayList<String>();
List<Object> sources = new ArrayList<Object>();
for (String arg : args) {
if (ClassUtils.isPresent(arg, null)) {
sources.add(ClassUtils.forName(arg, null));
} else if (arg.endsWith(".xml")) {
sources.add(arg);
} else if (!scanner.findCandidateComponents(arg).isEmpty()) {
sources.add(arg);
} else {
strings.add(arg);
}
}
if (sources.isEmpty()) {
sources.add(Spring.class);
}
context = SpringApplication.run(sources.toArray(new Object[sources.size()]),
strings.toArray(new String[strings.size()]));
LogFactory.getLog(Spring.class).info(
"Running Spring " + SpringVersion.getVersion() + " with sources: "
+ sources);
}
}

View File

@ -26,7 +26,6 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.bootstrap.SpringApplication.AutoMain;
import org.springframework.bootstrap.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
import org.springframework.bootstrap.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
import org.springframework.context.ApplicationContext;
@ -153,15 +152,6 @@ public class SpringApplicationTests {
assertThat(getEnvironment().getProperty("foo"), equalTo("bar"));
}
@Test
public void emptytApplicationContext() throws Exception {
// This is the class that will be used for main()
SpringApplication application = new SpringApplication(AutoMain.class);
this.context = application.run();
assertThat(this.context,
instanceOf(AnnotationConfigEmbeddedWebApplicationContext.class));
}
@Test
public void defaultApplicationContext() throws Exception {
SpringApplication application = new SpringApplication(ExampleConfig.class);

View File

@ -0,0 +1,61 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.bootstrap.main;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.util.ClassUtils;
import static org.junit.Assert.assertNotNull;
/**
* @author Dave Syer
*
*/
public class SimpleMainTests {
private ApplicationContext context;
@After
public void close() {
if (this.context instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) this.context).close();
}
}
@Test
public void emptyApplicationContext() throws Exception {
Spring.main(new String[0]);
this.context = Spring.getApplicationContext();
assertNotNull(this.context);
}
@Test
public void basePackageScan() throws Exception {
Spring.main(new String[] { ClassUtils.getPackageName(Spring.class) });
this.context = Spring.getApplicationContext();
assertNotNull(this.context);
}
@Test
public void xmlContext() throws Exception {
Spring.main(new String[] { Spring.class.getName(),
"org/springframework/bootstrap/sample-beans.xml" });
}
}