We have a SpringApplication that runs fine with the default ApplicationContext, but we have a scenario in which we need to refresh the context and the default context does not allow us to do this. I've update our main Application class to look like this:
// package and import lines not shown here but are included in original source
#ComponentScan("edge")
#EnableAutoConfiguration
#Configuration
#EnableTransactionManagement
#EnableAsync
#EnableScheduling
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setApplicationContextClass(AnnotationConfigWebApplicationContext.class);
app.run(args);
}
With this code as it is, calling app.run(args) results in the following stack trace:
Exception in thread "main" java.lang.IllegalStateException: BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
at org.springframework.context.support.AbstractRefreshableApplicationContext.getBeanFactory(AbstractRefreshableApplicationContext.java:170)
at org.springframework.boot.context.event.EventPublishingRunListener.registerApplicationEventMulticaster(EventPublishingRunListener.java:70)
at org.springframework.boot.context.event.EventPublishingRunListener.contextPrepared(EventPublishingRunListener.java:65)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:305)
at edge.server.Application.main(Application.java:43)
Stepping through SpringApplication.run(), I noticed that the context's BeanFactory is null. If I remove the line app.setApplicationContextClass(AnnotationConfigWebApplicationContext.class), thereby setting the application to use the default context, the code runs up until the point where we call refresh(). That call results in:
java.lang.IllegalStateException: GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once
Has anyone used AnnotationConfigWebApplicationContext in a SpringApplication in the manner I've described and had it work? If so, do you have any suggestions for getting this to work? I've tried looking for ways to create the BeanFactory manually prior to calling app.run(), but there does not appear to be any public methods for doing that. Thanks in advance for any help provided!
Edit for clarification:
Thanks for the comments and answers thus far. I should have been more explicit in my original post regarding the scenario that requires refreshing the ApplicationContext and my attempt at using AnnotationConfigWebApplicationContext. We have some code that runs after the server starts up that we're using for backup and restore purposes, which involves modifying the content of the JpaRepositories that we're using. My understanding is that after running this code, we need to refresh the ApplicationContext in order to call all of our init methods again.
Attempting to do this with the default context class (AnnotationConfigEmbeddedWebApplicationContext, a subclass of GenericApplicationContext) throws the IllegalStateException that I had mentioned before (GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once). That exception is what prompted my attempt to explicitly set the context to AnnotationConfigWebApplicationContext, which is a subclass of AbstractRefreshableApplicationContext. My assumption was that I needed the application to use an AbstractRefreshableApplicationContext in order to make multiple calls to the refresh method successfully. Is there a way to get the code I have above to work, or is there some alternative approach I should be taking that would allow us to refresh the context multiple times?
You are using Spring Boot which already does this for you, you are just making it overly complex. Change your class to the following.
#EnableAsync
#EnableScheduling
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And make sure it is in the edge package and make sure you have the spring-boot-starter-web dependency which enables a web application. There is no need to mess around with the context class yourself.
Related
This question already has answers here:
Running code after Spring Boot starts
(18 answers)
Closed 4 years ago.
I am building an application using Java Spring where I would like to run some environment setup code before my application starts handling requests. In this particular example, I'm using PayPal Rest SDK and I would like to set up some notification webhooks for my application. For obvious reasons I don't want to have an endpoint to call to set up the webhooks after the application is started, so putting it in my controller is probably not a good idea, and I need some Spring configuration information to set it up so I can't put it in main(). I'm ok with (in fact I'd even prefer) the application crashing if the webhooks fail to be created, if that's a constraint that needs to be considered.
What's a good way to do this?
Thanks.
and I need some Spring configuration information to set it up so I can't put it in main()
The above statement is not true. You can access your Spring configuration in a main. Consider the following example.
#SpringBootApplication
public class Main {
#Autowire
private MyService service;
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(InterviewHqApplication.class, args);
ctx.getBean(Main.class).setup();
}
private void setup() {
service.doStuff();
}
}
In this example, the setup() method is called after the application context has loaded.
There are actually several ways to do what you are attempting. Spring boot also supports using ApplicationRunner and CommandLineRunner, which both call a run method after the application context has been loaded an alternative to what I have shown above. You can also listen for an ApplicationReadyEvent and you could call #PostConstruct do perform some specific configuration on a bean after it's initialized.
I am trying to find out in spring-boot, which implementation of WebApplicationInitializer actually register the dispatcher servlet.
I didn't found any piece code from SpringBootServletInitializer or its parent types did that.
Instead, AbstractDispatcherServletInitializer does the job, but it's abstract, I can't find any of its concrete implementation with help of Eclipse.
So, which piece of code from which class is actually invoked to register the dispatcher servlet for springMVC?
This is a subsequent question of: How does spring-boot able to serve specific url?
Below is the description of Spring Boot initialization steps that eventually register DispatcherServlet.
Example Code
#EnableAutoConfiguration
public class TestSpring {
public static void main(String[] args) throws Exception {
SpringApplication.run(TestSpring.class, args);
}
}
Spring Boot Initialization Steps
Here are the steps:
SpringApplication.run() creates EmbeddedWebApplicationContext application context;
Calls its refresh() method;
Refresh process reads annotations of the starting class TestSpring. It looks for import annotations. EnableAutoConfiguration is one of them. For an import annotation the refresh process gets the corresponding class from the annotation value and invokes its selectImports() method;
In case of #EnableAutoConfiguration the corresponding class is EnableAutoConfigurationImportSelector whose selectImports() loads tons of other import selectors from the META-INF/spring.factories;
This process continues recursively. Also, all bean definitions, that are inside these import selectors, are read. I.e. it includes beans defined by a method with the #Bean annotation, i.e. beans that require the Spring context to call the corresponding method automatically to instantiate them;
The resfresh() continues and reaches onRefresh(), the createEmbeddedServletContainer() method is called inside;
Among read bean defitions at the previous step, beans implementing ServletContextInitializer are searched for and instantiated. One of them is the bean, defined by the DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration() method of ServletRegistrationBean type that extends ServletContextInitializer. As you can guess from the name of the class, such initializers add a given servlet (in this case DispatcherServlet) to a given ServletContext, when their onStartup() method is invoked;
A tomcat embedded server is created (not started completely yet). All found ServletContextInitializers at the previous step are passed to this tomcat initialization - this is where the onStartup() methods of those ServletContextInitializers are called and DispatcherServlet gets created and registered as servlet;
End of onRefresh() of application context;
The finishRefresh() is called where tomcat is finally started by TomcatEmbeddedServletContainer.start();
End of refresh() of application context and other final initialization steps;
The app is running.
When you look for something Spring Boot does during auto-configuration, you should look in the *AutoConfiguration classes. In this case, DispatcherServletAutoConfiguration.
If you want to deploy the Spring Boot application as a traditional WAR, then the Servlet 3.0 specification details how service providers can set it up so that the 3.0 compliant servlet container will automatically bootstrap any web assets (Servlet, Filter, ServletContextInitializer's) into the servlet container. The "magic" is accomplished in the spring-web dependency. If you un'jar it, you'll find file "spring-web/META-INF/services/javax.servlet.ServletContainerInitializer". Open the file and you'll see single line "org.springframework.web.SpringServletContainerInitializer". This class delegates to all classes that implement WebApplicationInitializer, more specifically their onStartup(ServletContext servletContext) method. There's one such concrete class I'm aware of in Spring Boot, namely SpringBootServletInitializer.
In the example below, is there a way to avoid doing a context.getBean()? All the other beans subsequently used by the testService get autowired. (It is a console application)
public class Test {
private static ITestService testService;
private static ApplicationContext context;
public static void main(String[] args) {
context = new ClassPathXmlApplicationContext(
new String[]{"/META-INF/spring/app-context.xml"});
ITestService testService = context.getBean(ITestService.class);
}
}
I tried adding autowire annotation to ApplicationContext, but it didnt work. Besides how does it know where my app-context.xml is located if I autowire it?
Update: I found what I needed over here
Right, you're missing out a few details here.
Below is a short explanation of how Spring works.
1- The application context is loaded somehow (we will get there soon).
2- After loaded, app context will initialize/create all beans defined. Here is when beans get injected as dependencies. After this Whenever you get a bean back from the app context, that bean is all initialized and ready to go with all the dependencies in place (considering everything went fine).
RE the first step, there are a few way to automate the Spring initialization.
One way is what you are doing, explicitly instantiating one. Other way could be via a context listener in case you're in a web environment, or maybe with the #RunWith. (You can find more here)
In your case, I believe you are looking for using Spring in a (Unit?!?) test environment so you are looking for something like
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTest {
#Autowired
private ApplicationContext applicationContext;
// class body...
}
further details here
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#testing
You cannot call beans without initializing the application context first.
Secondly in your case Test class should be bean itself to be managed by spring then to autowire ITestService. The purpose of Application context as a container is to manage the bean lifecycle so u need to initialize it first by ClassPathXmlApplicationContextand then it will initialize all beans declared by you in ur xml file. About avoiding the getBean method if you are using servlets for creating web app you can avoid getBean. If not you should handle it manually.
I agree with what #Desorder has said. When I started working with #RunWith(SpringJUnit4ClassRunner.class) and #ContextConfiguration, I used to get my test cases working. But it took me some time to understand how these two are working internally and their default configurations.
If you would like to take some different approach and would like to try without #RunWith and #ContextConfiguration, take a look at the link - TUTORIAL: JUNIT #RULE. With this, you will be very clear which spring xml file locations are provided.
I want to integrate Spring Shell within a spring boot application. I am able to execute the examples from the official git-repo. But when migrating the example code to my own project that is very very similar to this code, my individual shell is not shown or usable. Instead the default Spring Shell splash is shown is usable:
<SpringShell ASCII-Art>
1.1.0.RELEASE
Welcome to Spring Shell. For assistance press or type "hint" then hit ENTER
spring-shell>
Compilation gives no errors, but the individual sample #component marked classes are not used. All annotations are properly set. A standard loader outside is existent. I am not executing the code in an IDE.
Although the documentation (chapter 3.5) tells, that the components are automatically collected as far as i understood.
So my question is more or less how to setup the usage better than
this:
public class Main {
public static void main(String[] args) throws Exception {
Bootstrap.main(args);
}
}
And to defeat the default splash!
That comment in the documentation is a bit misleading (I'll change it).
For your components to be picked up, they need to be on the classpath AND you'll need to scan for them somehow.
See for example how in the Spring XD project, there is a scan for the org.springframework.xd.shell package. You need to do something similar for your own package.
SOLUTION:
ebottard's answer brought me to the point of creating a "spring-shell-plugin.xml" under resources\META-INF\spring\... Although the component scan was set externally already, this seems to be necessary. The following code shows how to start it up within an Spring Boot Application where CommandLineRunner is implemented. This should bridge starting problems.
#Component
public class CLIBean implements CommandLineRunner {
#Override
public void run(String... args) throws Exception {
Bootstrap bootstrap = new Bootstrap();
bootstrap.run();
}
}
My colleagues very often use word "application context". In many articles this collocation used very often too.
My current understanding: application context is single xml file.
But I understand that if I was right, people wouldn't use "application context" instead of configuration xml file.
Can you help me to deal with this issue?
#feak gives a straight answer about the meaning of ApplicationContext in terms of Spring. In short, it is an object that loads the configuration (usually a XML file annotation based) and then Spring will start managing the beans and its benefits:
Beans declared in package
Beans declared by annotations
Constructor and method autowiring
Bean injection
Configuration, .properties and .yaml file loading
etc
To start an application context, you may use one of the following:
Manually load the application context at the beginning of your application. This is done for sample purposes or in standalone applications:
public class Foo {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("path/to/applicationContext.xml");
//use the context as you wish...
}
}
In case of Java web applications using Spring MVC, the DispatchServlet will load the application context for you, so you only have to create a springapp-servlet.xml file in WEB-INF folder of the application.
Note that an application context is associated to a single configuration (XML based or not). Period.
After understanding this, you could also understand that you can have more than a single application context per application. This is, having two or more ApplicationContexts in the same application. From the last example in the console application, this is easy to check:
public class Foo {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("path/to/applicationContext.xml");
ApplicationContext context2 =
new ClassPathXmlApplicationContext("path/to/applicationContext.xml");
//use the context as you wish...
}
}
Note that we have two application contexts using the same XML configuration. Can you do this? Yes, you're actually seeing it here. What's the difference, then? The main difference is that Spring beans singleton scopes are singleton per application context, this mean when retrieving a Bar bean that's configured in applicationContext.xml file from context will not be the same as retrieving it from context2, but several retrieves from context will return the same Bar bean instance.
Is this considered a good or bad practice? Neither, it will depend on the problem to be solved (in case of last example, I would say it is a bad practice). Most people would recommend having all your beans configured in a single place (via XML or another) and loaded by a single application context.
Let's understand this in simple words.
The ApplicationContext is the central interface within a Spring application that is used for providing configuration information to the application. It's created when the application starts running.
It provides the entire configuration needed by our application:
Bean Factory - Responsible for creation of java objects called beans. One example is components in the application.
Application listeners - all listeners needed for events.
WebServer information.
Application current environment specific information.
Resource pattern resolver - resource loader with path matcher.
Life cycle Processor.
Class Loader.
Start and shutdown monitor.
Servlet Context.
Reader and Scanner.
Logger
etc.
package com.srmhitter9062.spring;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
We can get some idea about the Application object in below snapshot.
In summary, we can say the Application context is a Configuration object created for application to run.
The applicationContext.xml defines the beans for the "root webapp context". It's a web aware ApplicationContext.
It is used to have beans that are shared between all servlets in a web application.
I hope this is helpful.
I guess that you colleagues meant the loaded spring application context, which allows access to:
configuration of application,
initialized beans,
application events api,
etc
From the javadoc:
Central interface to provide configuration for an application. This is
read-only while the application is running, but may be reloaded if the
implementation supports this.
An ApplicationContext provides: [...]