about spring boot how to disable web environment correctly - spring-boot

Spring boot non-web application, when start it has below error
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:185) ~[spring-boot-1.3.5.RELEASE.jar:1.3.5.RELEASE]
Then I tried below manner
new SpringApplication().setWebEnvironment(false);
then start it still have above error.
Then tried
#SpringBootApplication(exclude={SpringDataWebAutoConfiguration.class})
but still have the same error.
At last I tried add below configuration in application.properties
spring.main.web-environment=false
this time it works.
Why the first two manner cannot work?

Starting from Spring Boot 2.0
-web(false)/setWebEnvironment(false) is deprecated and instead Web-Application-Type can be used to specify
Application Properties
spring.main.web-application-type=NONE
# REACTIVE, SERVLET
or SpringApplicationBuilder
#SpringBootApplication
public class SpringBootDisableWebEnvironmentApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(SpringBootDisableWebEnvironmentApplication.class)
.web(WebApplicationType.NONE) // .REACTIVE, .SERVLET
.run(args);
}
}
Where WebApplicationType:
NONE - The application should not run as a web application and should not start an embedded web server.
REACTIVE - The application should run as a reactive web application and should start an embedded reactive web server.
SERVLET - The application should run as a servlet-based web application and should start an embedded servlet web server.
Courtesy: Another SO Answer

This answer is obsolete. Please note the other answer for Spring Boot 2.0
Original answer for Spring Boot 1.x:
The reason this config is not working because these are two different instances:
new SpringApplication().setWebEnvironment(false);
SpringApplication.run(SpringBootDisableWebEnvironmentApplication.class, args);
You are disabling setWebEnvironment(false) in new SpringApplication() object and calling static method run() on SpringApplication.run(...) which is different one.
I figured out 3 ways to do this:
#SpringBootApplication
public class SpringBootDisableWebEnvironmentApplication implements CommandLineRunner{
public static void main(String[] args) throws Exception {
// Method#1: Using SpringApplicationBuilder.
SpringApplication springApplication =
new SpringApplicationBuilder()
.sources(SpringBootDisableWebEnvironmentApplication.class)
.web(false)
.build();
springApplication.run(args);
//--------------------------------------------------------
// Method#2: Using SpringBootDisableWebEnvironmentApplication.
// SpringBootDisableWebEnvironmentApplication springBootDisableWebEnvironmentApplication =
// new SpringBootDisableWebEnvironmentApplication();
// springBootDisableWebEnvironmentApplication.run(args);
//--------------------------------------------------------
// Method#3: Using SpringApplication().
// SpringApplication springApplication = new SpringApplication();
// springApplication.setWebEnvironment(false);
//
// Set<Object> sources = new HashSet<>();
// sources.add(SpringBootDisableWebEnvironmentApplication.class);
// springApplication.setSources(sources);
// springApplication.run(args);
//--------------------------------------------------------
}
#Override
public void run(String... arg0) throws Exception {
System.out.println("Hello, Spring Boot gives many options ;)");
}
}
Here is the complete working Project.
And you don't need to exclude below config:
#SpringBootApplication(exclude = {EmbeddedServletContainerAutoConfiguration.class,
WebMvcAutoConfiguration.class})
Because you don't have spring-boot-starter-web dependency in your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

As already noted in other answers the simplest solution is to add a property:
spring.main.web-application-type=NONE for Spring-boot 2.x
spring.main.web-environment=false for Spring-boot 1.x
But the simplest solution is NOT the best one, it's just quick&dirty.
Spring-boot has a lot of autoconfigurations that are triggered by the content of your classpath, so you probably have some unnecessary web-related dependency in your app.
I had a Spring-batch application that was giving
Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.
It was caused by the presence of javax.servlet-api in my POM. I removed it and the problem disappeared.

public static void main(String[] args) {
SpringApplication(Application.class)
.setWebApplicationType(WebApplicationType.NONE)
.run(args);
}
is another way instead of using the SpringApplicationBuilder.

Related

How SpringBoot works on application servers

I am working on migrating our Spring REST applications to Spring Boot microservices. I have some doubt:
As I know spring boot has a main() and it calls static run() which is present in SpringApplication. So, when we run it as "Java Applicaton" in Eclipse IDE, this main() gets called and #SpringBootApplication annotation do the magic. But when I deploy this application on Websphere Application Servers, then how is this working because now the main() will not gets called. Then how all the beans getting loaded without calling the main().
Spring Boot implicitely starts an embedded server, which is included in spring-boot-starter-tomcat dependency. That's why main() method works in boot environment.
Typical solution is to create two profiles - one for boot development and the other for deployment - then you may have several starting points.
Dev config:
#Configuration
#Profile(Profiles.DEV)
#Import(AppConfig.class)
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class)
.profiles(Profiles.DEV)
.run(args);
}
}
Deploy config (for WAS, tomcat, ...):
#Configuration
#Profile(Profiles.DEPLOY)
#Import(AppConfig.class)
public class ApplicationTomcat extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application
.profiles(Profiles.DEPLOY)
.sources(ApplicationTomcat.class);
}
}
Profiles:
public class Profiles {
public final static String DEV = "dev";
public final static String DEPLOY = "deploy";
}
In your deployment profile, don't forget to exclude spring-boot-starter-tomcat dependency and make it war bundle.
This way you can deploy application on WAS (or tomcat, ...) in standard way and start your application localy also with main() method.

Springboot - Thymeleaf tries to resolve files it should not

Hi I am currently working on a web project that uses thymeleaf and also JSF (its a legacy system and we can only slowly migrate to thymeleaf thats why JSF is still there and cannot be removed from one day to another since this is a lot of work). Thymeleaf is configured to resolve the views in the webapp directory that lie under the directory "thymeleaf". This works perfectly if I deploy the application directly on a tomcat server. Also pages from other directories then the "thymeleaf" directory are also resolved by the JSF framework.
I added some integration tests in JUnit that are using SpringBoot. Inside these tests I got the problem that thymeleaf now is trying to resolve any page in any directory. JSF is completely ignored and I got a whole bunch of JUnit tests failing because of that. Is there any point why thymeleaf ignores its configuration and wants to resolve all files?
Here is my complete thymeleaf configuration, and as I said this works perfectly if I deploy it on a standalone tomcat.
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
String imagesPattern = "/images/**";
String imagesLocation = basePath() + "resources/images/";
registry.addResourceHandler(imagesPattern).addResourceLocations(imagesLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')",
imagesPattern,
imagesLocation);
String cssPattern = "/css/**";
String cssLocation = basePath() + "resources/css/";
registry.addResourceHandler(cssPattern).addResourceLocations(cssLocation);
log.info("added resourceHandler (pathPattern: '{}'), (resourceLocation: '{}')", cssPattern, cssLocation);
}
#Bean(name = "basepath")
public String basePath()
{
String basepath = "";
File file = new File(Optional.ofNullable(System.getenv("THYMELEAF_APP_RESOURCES"))
.orElse("thymeleaf-resources/"));
if (file.exists())
{
basepath = "file:" + file.getAbsolutePath();
}
if (!basepath.endsWith("/"))
{
basepath += "/";
}
log.info("basepath: {}", basepath);
return basepath;
}
#Bean
#Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver(String basePath)
{
log.info("setting up Thymeleaf view resolver");
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine(basePath));
viewResolver.setCharacterEncoding("UTF-8");
viewResolver.setCache(true);
return viewResolver;
}
public SpringTemplateEngine templateEngine(String basePath)
{
log.info("setting up Thymeleaf template engine.");
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver(basePath));
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
private ITemplateResolver templateResolver(String basePath)
{
log.info("setting up Thymeleaf template resolver");
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix(basePath + "thymeleaf/views/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
return resolver;
}
#Bean
public IMessageResolver thymeleafMessageSource(MessageSource messageSource)
{
SpringMessageResolver springMessageResolver = new SpringMessageResolver();
springMessageResolver.setMessageSource(messageSource);
return springMessageResolver;
}
EDIT
I just found that the problem seems to lie much deeper. Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context... I just deleted my ThymeleafConfig class for testing purposes and still thymeleaf tries to resolve the JSF pages... (yes I did maven clean before executing the test)
EDIT 2
I read it now and tried to exclude the ThymeleafAutoConfiguration class but it does not help. My configurations are still overridden. Here is my configuration for this so far. (And yes this is the ONLY EnableAutoConfiguration annotation in the whole project)
#Configuration
#EnableAutoConfiguration(exclude = {ThymeleafAutoConfiguration.class})
#Import({WebAppConfig.class, ThymeleafConfig.class})
public class SpringBootInitializer extends SpringBootServletInitializer
and my ThymeleafConfig class is already added above.
Having the dependencies of thymeleaf added into my pom.xml seems to be enough for spring boot to load it into the context...
If this has surprised you then I would recommend spending some time to take a step back and read about how Spring Boot works and, in particular, it's auto-configuration feature. This section of the reference documentation is a good place to start.
In short, Spring Boot adopts a convention over configuration approach. If a dependency is on the classpath, Spring Boot assumes that you want to use it, and configures it with sensible defaults. This is what it's doing with Thymeleaf. You can disable this auto-configuration for a specific dependency using the excludes attribute on #SpringBootApplication:
#SpringBootApplication(exclude={ThymeleafAutoConfiguration.class})
public class ExampleApplication {
}
You can also use the spring.autoconfigure.exclude property to provide a comma-separated list of auto-configuration classes to exclude. Each entry in the list should be the fully-qualified name of an auto-configuration class. You could use this property with #TestPropertySource to disable auto-configuration on a test-by-test basis.
I have been struggling with a similar issue for hours and finally found out the root cause.
If you have a dependency to *-data-rest in your pom like this:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
you will have to add Thymeleaf to your pom as well even if you use a another template engine (Freemarker, JSP, ...) everywhere else.
Reason: to expose a JpaRepository as a rest service Spring Boot requires Thymeleaf. I do not understand why this is not defined as a dependency of spring-boot-starter-data-rest so that Maven resolves it automatically.
In my opinion it is a Spring Boot configuration bug.

Spring Boot 1.3.0 creates multiple ContextLoader definitions

I have an application which uses Spring Boot 1.3.0.RELEASE.
The production version is suppoed to run on a Tomcat server (AWS Elastic Beanstalk).
Most of the time, when I deploy the application, I get an error:
18-Nov-2015 14:40:30.301 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log Spring WebApplicationInitializers detected on classpath: [org.glassfish.jersey.server.spring.SpringWebApplicationInitializer#16a15bdb, com.example.ExampleApplication#529635d6, org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration#19b5e8a2]
18-Nov-2015 14:40:37.851 INFO [localhost-startStop-1] org.apache.catalina.core.ApplicationContext.log Initializing Spring embedded WebApplicationContext
18-Nov-2015 14:40:49.148 SEVERE [localhost-startStop-1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
Being a Spring Boot application, I do not even have web.xml.
My ExampleApplication looks like:
#SpringBootApplication(exclude = JerseyAutoConfiguration.class)
#EnableHypermediaSupport(type = EnableHypermediaSupport.HypermediaType.HAL)
public class ExampleApplication extends SpringBootServletInitializer {
private static final Class<ExampleApplication> APPLICATION_CLASS = ExampleApplication.class;
public static void main(final String[] args) {
SpringApplication.run(APPLICATION_CLASS, args);
}
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(APPLICATION_CLASS);
}
#Override
public void onStartup(final ServletContext servletContext) throws ServletException {
servletContext.setInitParameter("contextConfigLocation", "<NONE>");
super.onStartup(servletContext);
}
//...
}
I have read that servletContext.setInitParameter("contextConfigLocation", "<NONE>"); might help, so I've added that, but it didn't.
I thought excluding JerseyAutoConfiguration will help, but it didn't.
The applications runs without any issue using the spring-build:run maven goal, or running the package directly from the command line.
I do not have `#EnableWebMVC' anywhere in my code. (Even if I have, the result is the same.)
It sounds like you're hitting this bug. You can work around the problem by adding #Order(Ordered.HIGHEST_PRECEDENCE) to ExampleApplication so that it runs before Jersey's SpringWebApplicationInitializer and, therefore, has a chance to switch it off.
Actually it was my bad. I had an extra dependency on spring-boot-starter-jersey, which created its own ContextLoader.

Print all the Spring beans that are loaded - Spring Boot

How can I get to know names of all the beans that are loaded as part of my spring boot app? I would like have some code in main method to print the details of beans that are loaded once the server is started up.
As shown in the getting started guide of spring-boot: https://spring.io/guides/gs/spring-boot/
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
}
As #Velu mentioned in the comments, this will not list manually registered beans.
In case you want to do so, you can use getSingletonNames(). But be careful. This method only returns already instantiated beans. If a bean isn't already instantiated, it will not be returned by getSingletonNames().
May I suggest using Actuator? it provides several endpoints including /beans which lists all beans in the application. You say "once the server is started" so this is an option for web applications.
To set up actuator
https://spring.io/guides/gs/actuator-service/
List of endpoints in actuator
http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-endpoints.html
Well, Although, this question is already answered, I still want to provide an answer which is a Java 8 variant :)
Arrays.asList(context.getBeanDefinitionNames()).stream().sorted().forEach(System.out::println);
Lets do Java 8 !!!
Actually I would recommend to create this class aside from modifying your #SpringBootApplication.
#Component
public class ContextTeller implements CommandLineRunner {
#Autowired
ApplicationContext applicationContext;
#Override
public void run(String... args) throws Exception {
System.out.println("-------------> just checking!");
System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));
}}
This way Spring Boot will load this class and execute just after loading context. Then you just can remove the file, and everything is clear.
applicationContext.getBeanDefinitionNames() does not show the beans which are registered without BeanDefinition instance.
For spring boot web applications, all the beans can be listed using the below endpoint.
#RestController
#RequestMapping("/list")
class ExportController {
#Autowired
private ApplicationContext applicationContext;
#GetMapping("/beans")
#ResponseStatus(value = HttpStatus.OK)
String[] registeredBeans() {
return printBeans();
}
private String[] printBeans() {
AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
if (autowireCapableBeanFactory instanceof SingletonBeanRegistry) {
String[] singletonNames = ((SingletonBeanRegistry) autowireCapableBeanFactory).getSingletonNames();
for (String singleton : singletonNames) {
System.out.println(singleton);
}
return singletonNames;
}
return null;
}
}
[
"autoConfigurationReport",
"springApplicationArguments",
"springBootBanner",
"springBootLoggingSystem",
"environment",
"systemProperties",
"systemEnvironment",
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor",
"org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory",
"org.springframework.boot.autoconfigure.condition.BeanTypeRegistry",
"org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry",
"propertySourcesPlaceholderConfigurer",
"org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.store",
"preserveErrorControllerTargetClassPostProcessor",
"org.springframework.context.annotation.internalAutowiredAnnotationProcessor",
"org.springframework.context.annotation.internalRequiredAnnotationProcessor",
"org.springframework.context.annotation.internalCommonAnnotationProcessor",
"org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor",
"org.springframework.scheduling.annotation.ProxyAsyncConfiguration",
"org.springframework.context.annotation.internalAsyncAnnotationProcessor",
"methodValidationPostProcessor",
"embeddedServletContainerCustomizerBeanPostProcessor",
"errorPageRegistrarBeanPostProcessor",
"messageSource",
"applicationEventMulticaster",
"org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat",
"tomcatEmbeddedServletContainerFactory",
"org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration$TomcatWebSocketConfiguration",
"websocketContainerCustomizer",
"spring.http.encoding-org.springframework.boot.autoconfigure.web.HttpEncodingProperties",
"org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration",
"localeCharsetMappingsCustomizer",
"org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration",
"serverProperties",
"duplicateServerPropertiesDetector",
"spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties",
"org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration",
"conventionErrorViewResolver",
"org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration",
"errorPageCustomizer",
"servletContext",
"contextParameters",
"contextAttributes",
"spring.mvc-org.springframework.boot.autoconfigure.web.WebMvcProperties",
"spring.http.multipart-org.springframework.boot.autoconfigure.web.MultipartProperties",
"org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration",
"multipartConfigElement",
"org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration",
"org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DispatcherServletConfiguration",
"dispatcherServlet",
"dispatcherServletRegistration",
"requestContextFilter",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration",
"hiddenHttpMethodFilter",
"httpPutFormContentFilter",
"characterEncodingFilter",
"org.springframework.context.event.internalEventListenerProcessor",
"org.springframework.context.event.internalEventListenerFactory",
"reportGeneratorApplication",
"exportController",
"exportService",
"org.springframework.boot.autoconfigure.AutoConfigurationPackages",
"org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration",
"spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties",
"standardJacksonObjectMapperBuilderCustomizer",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration",
"jsonComponentModule",
"jacksonObjectMapperBuilder",
"org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration",
"jacksonObjectMapper",
"org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration",
"org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration",
"org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration",
"org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration",
"defaultValidator",
"org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration",
"error",
"beanNameViewResolver",
"errorAttributes",
"basicErrorController",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter",
"mvcContentNegotiationManager",
"org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration",
"stringHttpMessageConverter",
"org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration",
"mappingJackson2HttpMessageConverter",
"org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration",
"messageConverters",
"mvcConversionService",
"mvcValidator",
"requestMappingHandlerAdapter",
"mvcResourceUrlProvider",
"requestMappingHandlerMapping",
"mvcPathMatcher",
"mvcUrlPathHelper",
"viewControllerHandlerMapping",
"beanNameHandlerMapping",
"resourceHandlerMapping",
"defaultServletHandlerMapping",
"mvcUriComponentsContributor",
"httpRequestHandlerAdapter",
"simpleControllerHandlerAdapter",
"handlerExceptionResolver",
"mvcViewResolver",
"org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter$FaviconConfiguration",
"faviconRequestHandler",
"faviconHandlerMapping",
"defaultViewResolver",
"viewResolver",
"welcomePageHandlerMapping",
"org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration",
"objectNamingStrategy",
"mbeanServer",
"mbeanExporter",
"org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration",
"springApplicationAdminRegistrar",
"org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration",
"org.springframework.boot.autoconfigure.web.JacksonHttpMessageConvertersConfiguration",
"spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties",
"org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration",
"multipartResolver",
"org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration$RestTemplateConfiguration",
"restTemplateBuilder",
"org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration",
"spring.devtools-org.springframework.boot.devtools.autoconfigure.DevToolsProperties",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$RestartConfiguration",
"fileSystemWatcherFactory",
"classPathRestartStrategy",
"classPathFileSystemWatcher",
"hateoasObjenesisCacheDisabler",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration$LiveReloadServerConfiguration",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration$LiveReloadConfiguration",
"optionalLiveReloadServer",
"org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration",
"lifecycleProcessor"
]
As you can see in the output, environment, systemProperties, systemEnvironment beans will not be shown using context.getBeanDefinitionNames() method.
#Component
public class ContextTeller implements CommandLineRunner {
#Autowired
public ApplicationContext applicationContext;
#Override
public void run(String... args) throws Exception {
System.out.println("<------------- Beans loaded --------------->");
Arrays.asList(applicationContext.getBeanDefinitionNames()).stream().forEach(System.out::println);
}
}
As mentioned by #Zergleb, using Actuator is appropriate too, however, based on the reference documentation this endpoint is no longer exposed via "web" by default. Thus you need to consider the following steps to access the endpoint
Add the below dependency to your pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Add these two propertiers to your application.properties file:
management.endpoints.web.exposure.include=beans
management.endpoint.beans.enabled=true
Access to your application context beans using /actuator/beans http endpoint
I did one small experiment for this requirement and found this solution. I have created SpringBoot while selecting the modules like WEB, Actuator, HAL and Devtools. I have configured the below property in application properties to load all the endpoints present in actuator.
management.endpoints.web.exposure.include=*
You can see actuator information in, http://localhost:8080/actuator. This will show all the application information along with actuator, status, info,etc.. In that, you can find the http://localhost:8080/actuator/beans which will load all the beans internally created by springboot application.
Once you are able to see all the beans information, I think it's not necessary to print again in main class.
Since, I have already configured rest-hal-browser dependency in my application, when I load the URL of http://localhost:8080, will load the UI to search for different endpoints. In the below image I am searching for actuator information.
Simple way to get all beans
ApplicationContext ctx =SpringApplication.run(DemoApplication.class, args);
String [] beans = ctx.getBeanDefinitionNames();
Arrays.sort(beans);
System.out.println("#############");
for(String s:beans) {
System.out.println(s + " of type " + ctx.getBean(s).getClass());
}

Spring boot on glassfish 3.x

I am trying to deploy a Spring Boot application to Glassfish 3.x but I can't get it to work. If I run the project via mvn spring-boot:run or I deploy the war on a Tomcat 7, it works, but if I deploy it on a Glassfish 3.1.2.2 the deploy fails before it even gets to spring boots initialization.
[#|2014-08-04T11:38:36.668+0200|WARNING|glassfish3.1.2|global|_ThreadID=50;_ThreadName=Thread-2;|Error in annotation processing: java.lang.NoClassDefFoundError: org/springframework/batch/core/configuration/annotation/BatchConfigurer|#]
[#|2014-08-04T11:38:36.677+0200|SEVERE|glassfish3.1.2|global|_ThreadID=50;_ThreadName=Thread-2;|Class [ org/flywaydb/core/Flyway ] not found. Error while loading [ class org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$FlywayConfiguration ]|#]
[#|2014-08-04T11:38:36.700+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=50;_ThreadName=Thread-2;|Exception while deploying the app [spring]|#]
[#|2014-08-04T11:38:36.700+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=50;_ThreadName=Thread-2;|sun.reflect.annotation.TypeNotPresentExceptionProxy
java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:673)
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:480)
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:306)
at sun.reflect.annotation.AnnotationParser.parseAnnotation(AnnotationParser.java:241)
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:88)
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:70)
at java.lang.Class.initAnnotationsIfNecessary(Class.java:3217)
at java.lang.Class.getAnnotations(Class.java:3197)
at org.glassfish.apf.impl.AnnotationProcessorImpl.processAnnotations(AnnotationProcessorImpl.java:285)
at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:195)
at org.glassfish.apf.impl.AnnotationProcessorImpl.process(AnnotationProcessorImpl.java:134)
at com.sun.enterprise.deployment.archivist.Archivist.processAnnotations(Archivist.java:598)
at com.sun.enterprise.deployment.archivist.Archivist.readAnnotations(Archivist.java:456)
at com.sun.enterprise.deployment.archivist.Archivist.readAnnotations(Archivist.java:429)
at com.sun.enterprise.deployment.archivist.Archivist.readRestDeploymentDescriptors(Archivist.java:405)
at com.sun.enterprise.deployment.archivist.Archivist.readDeploymentDescriptors(Archivist.java:380)
at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:243)
at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:252)
at com.sun.enterprise.deployment.archivist.Archivist.open(Archivist.java:213)
at com.sun.enterprise.deployment.archivist.ApplicationFactory.openArchive(ApplicationFactory.java:165)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:185)
at org.glassfish.javaee.core.deployment.DolProvider.load(DolProvider.java:94)
at com.sun.enterprise.v3.server.ApplicationLifecycle.loadDeployer(ApplicationLifecycle.java:827)
at com.sun.enterprise.v3.server.ApplicationLifecycle.setupContainerInfos(ApplicationLifecycle.java:769)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:368)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:240)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:389)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$1.execute(CommandRunnerImpl.java:353)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:363)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:1085)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.access$1200(CommandRunnerImpl.java:95)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$ExecutionContext.execute(CommandRunnerImpl.java:1291)
at org.glassfish.deployment.autodeploy.AutoOperation.run(AutoOperation.java:145)
at org.glassfish.deployment.autodeploy.AutoDeployer.deploy(AutoDeployer.java:575)
at org.glassfish.deployment.autodeploy.AutoDeployer.deployAll(AutoDeployer.java:461)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:389)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:380)
at org.glassfish.deployment.autodeploy.AutoDeployService$1.run(AutoDeployService.java:220)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Disclaimer: I am using a Controller which extends an AbstractController, because we have this structure in another web application, and the next step is to migrate it to Spring Boot.
My configuration so far:
SampleController.java
#Controller("myController")
public class SampleController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
response.getWriter().print("Hello world!");
return null;
}
}
Application.java
#EnableAutoConfiguration
#Configuration
#ComponentScan
public class Application extends SpringBootServletInitializer {
#Autowired
ApplicationContext applicationContext;
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
SampleController sampleController = (SampleController) applicationContext.getBean("myController");
mapping.setUrlMap(Collections.singletonMap("index", sampleController));
mapping.setOrder(0);
return mapping;
}
}
This is a bug in both Glassfish 3.X and Glassfish 4.X.
Maybe it is caused by Glassfish when it attempts to find out Classes that are refenced by Spring boot conditional annotations.
A simple try/catch in Glassfish code solves this problem. look at the proposition here.
You've hit a limitation in GlassFish 3.x and I don't think it's possible to get this to work.
The problem you're seeing is caused by GlassFish scanning your application for annotations. It does this by loading all of the classes in the application and it's failing as a class that's referenced by one of the annotations isn't on the classpath. Unfortunately, there's no way in GlassFish 3 to configure what it does and does not scan for annotations. I believe that things have improved in GlassFish 4 so, if upgrading is an option, you might want to try that.

Resources