Prevent bean from being constructed in the spring cloud bootstrap context - java

Annotated spring beans in my spring-cloud application are being created twice. I assume this is because they get constructed into the bootstrap context and then into a child application context.
For me this is undesirable because some are annotated with #Scheduled to perform periodic refreshes of the data that they provide from a backend data source and this is happening twice in quick succession once for each context.
If it's not otherwise harmful then can I disable all of the application beans from being created in the bootstrap context? If not then can I detect in code when I'm running in the bootstrap context? I use entirely annotation-based beans with component scanning enabled on the Camden SR4 release.

OK I solved this myself. It was down to two different issues in the code and nothing to do with multiple contexts.
Firstly my long held assumption that an #PostConstruct method is only ever called once was false. Moving my one-off bean initialisation code to an implementation of ApplicationListener<ApplicationReadyEvent> solved that one.
Secondly I got bit by multiple initialisation of a bean with an #Scheduled annotation causes the scheduler to run multiple times. To be fair, this behaviour is noted in the documentation. This was easily solved by moving the scheduled task creation to a regular java ScheduledExecutorService set up in the ApplicationReadyEvent implementation.

Related

Is it possible for a spring bean to get notified about application context initialization errors?

I have a singleton bean in my spring context (call it 'beanX' ) that, when started spins off a few other threads and creates some state on the file system.
So I want to stop it in a clean way so that resources are freed when the context is shut down.
I have annotated it with #Bean(destroyMethod = "shutdown") and that works as expected without any problems.
Further information is that this bean loads very early in the context startup sequence (as it has many other beans that use it directly and indirectly) and there are many other beans that loads after it.
Now to the problem: it is fairly common that when we do development one of the other beans fail to start and makes the startup of the spring context to fail - but in these cases the beanX is not shut down properly.
This is perhaps ok in 'productionCode' as that usually means that the whole jvm stops and then resources are cleaned up - BUT when we run our 1000+ unit test suite (and some of the tests has an error causing the context to crash) this becomes a real problem because the test JVM is not stopped between tests, and a new spring context is created after each failing test - even though the test that failed has not properly cleaned up after itself as beanX is started but never stopped!
Today my laptop created 5 million file handles and 13k threads when I ran the test suite because of this.
SO, the only way we could make this work currently is to make beanX be a public static field (ClassX.beanX) that is lazily initialized by the spring context - and then in our test code manually call the ClassX.beanX.shutdown() if any context loading error occurs.
But I am curios if there is a better/different 'Spring' way to do this?
You can use event handling in Spring.
Event handling in the ApplicationContext is provided through the
ApplicationEvent class and ApplicationListener interface. If a bean
that implements the ApplicationListener interface is deployed into the
context, every time an ApplicationEvent gets published to the
ApplicationContext, that bean is notified. Essentially, this is the
standard Observer design pattern.

How do I lazily register Spring 'bean definitions' in order to improve startup time?

Our Java Web application loads with over 1000 plugins that are all registered by us as Spring beans using the ApplicationContext#registerBeanDefinition() method. These beans often have other dependencies which we also register as spring beans using the same method (for a total of about 7,000 Spring bean definitions...not including our core application code).
The problem is that the startup time is long (approximately 6.5 minutes of just plugin bean definition loading). We would prefer to spread this load time out over a much longer period while our app is actually processing other requests utilizing plugins that have already had their bean definitions registered. Most of the plugins are seldom used. Thus, we would really like to lazily register our bean definitions (this is different from lazy-init of singleton beans which we already do today). However, this seems costly with any existing Spring ApplicationContext that supports 'hot' refresh() calls (as the Spring documentation refers to it).
The Spring ApplicationContext classes that support 'hot' refresh start by destroying all of the singleton beans. Most of our plugins are singletons, so each call to refresh() would cause most of our plugins to be destroyed and then recreated...costly. If we don't call refresh, then our newly loaded plugin beans will not be post-processed (e.g., AOP, etc...).
We can guarantee that when we are forced to load another plugin, we will also load any of its dependencies that are not already loaded. So, we would never ben in a situation where a loaded bean definition is invalid.
It seems to me that this calls for a new type of Spring ApplicationContext that supports 'hot' refresh, but only for the purpose of adding new bean definitions. Preexisting bean definitions are not removed/reloaded, and not re-processed by BeanFactoryPostProcessors on subsequent refresh() calls, and pre-existing singletons are not destroyed!
Does this already exist?. Is there a better solution that I'm overlooking?
This sounds like you're looking for #Lazy.
4.4.4 Lazy-initialized beans
A lazy-initialized bean tells the IoC container to create a bean instance when it is first requested, rather than at startup.

How to I initiate specific spring bean during server start up

I'm using some support data in my application and I want to load that data at the time of server start. I'm using spring context. If I would be able to load application context at the time of server start up, the problem would be solved.
Not sure about the Spring part as I don't use it, but in JSF you can use an #ApplicationScoped #ManagedBean whose eager attribtue is set to true.
#ManagedBean(eager=true)
#ApplicationScoped
public class Data {
// ...
}
This will autoconstruct the managed bean on webapp's startup.
Register a ServletContextListener and fetch the bean in contextInitialized() (see Servlet Life-Cycle Events).
This has two advantages:
You can fetch several beans in a predefined order (this should never be necessary but, well, reality always wins)
It won't interfere with your tests

Implementing servlet lifecycle methods in a Spring web application?

I am implementing a web application using Spring. I am using Spring's ContextLoaderListener, to load up my application contexts, and Spring's DispatcherServlet, to load the relevant beans from {name}-servlet.xml, which refer to the beans in the main application context. I want to be able to integration test these Spring configurations outside of the container to validate everything is wired up correctly before I deploy to Tomcat. However my application requires some scheduled background processing when running in the container. In a regular HttpServlet I would simply implement init() and destroy(). All the suggestions I have read suggest using an InitializingBean for that kind of initialization.
However, if I use an InitializingBean, afterPropertiesSet() gets called whether I am inside the container or in integration tests - and outside the container, I don't have access to the resources that background task needs. Is there a better way to perform the tasks I would normally perform in init() and destroy() so that they will only run when deployed as a webapp?
Have you considered using a test spring config file that overrides the bean implementing your background process?
This way everything else in the spring configuration would work normally except for the one overridden bean.

Can I dynamically load additional Spring configuration files into an existing WebApplicationContext?

Upon starting my webapp within Tomcat 6.0.18, I bootstrap Spring with only what is necessary to initialize the system -- namely, for now, database migrations. I do not want any part of the system to load until the migrations have successfully completed. This prevents the other beans from having to wait on the migrations to complete before operating, or even instantiating.
I have a startup-appcontext.xml configured with a dbMigrationDAO, a startupManager which is a ThreadPoolExecutor, and lastly, a FullSystemLauch bean. I pass a list of configuration locations to the FullSystemLaunch bean via setter injection. The FullSystemLaunch bean implements ServletContextAware, gets a reference to the current WebApplicationContext and thus I can have a ConfigurableListableBeanFactory. Unfortunately, this bean factory isConfigurationFrozen() returns true, so by calling beanFactory.setConfigLocations(configLocations) has no effect.
Can I accomplish this or is Spring preventing me from doing so because it's a bit out of the ordinary? It seems reasonable if understood, but also a bit dangerous. And yes, I'm willing to blow away the current context b/c the currently loaded Singletons are not needed once initialization is complete.
Thank you for the help.
My opinion would be to allow Spring to initialise your beans is it sees fit - in the order of their declared dependencies.
If you need database migrations there are a couple of patterns to have them run first:
if you're using Hibernate/JPA make your sessionFactory/persistenceManager depend-on the migration beans;
if you're using plain JDBC create a wrapper DataSource and in its init-method invoke the migrations ( code sample)
The advantage is clear: simplicity.
You could use the existing context as parent context for the other contexts, although I doubt that you could replace the existing WebApplicationContext.
If you use EAR - WAR packaging, you get this out-of-the-box (sort of) by loading an application context from the EAR and then adding one in the WAR.
Not sure whether this is applicable in your situation.
Could lazy-initialization be an alternative for what you are trying to achieve?
Possible XmlBeanDefinitionReader can help you?
you can upcat the WebApplicatonContext to ConfigurableWebApplicationContext
then use the setConfigurations method.
dont forget refresh;
There was the same task and I created two contexts: startUpContext.xml and applicationContext.xml. In startUpContext.xml there is a bean, which triggers loading of appliationContext.xml. (application context location is configured in startUpContext.xml as a property of a trigger). And finally the trigger replaces locations of the current context and refreshes it:
applicationContext.setConfigLocations(locations);
applicationContext.refresh();
(startUpContext.xml is loaded with a standard spring context loader listener)

Categories