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
Related
I have dependency in my spring boot project which fetches values of some properties using Spring's EnvironmentPostProcessor.
Now these properties are database credentials and not everyone has access to the credential since there is no dev environment for the db in question. I just want to change the configuration that the credentials don't get fetched on dev or local environment on application startup as that would result in a error and the application will fail to start.
Class A implements EnvironmentPostProcessor{}
I tried to use #Lazy annotation on the Class Annoteted with #ConfigurationProperties. I also tried using my own BeanFactoryPostProcessor (with #Order(HighestPrecedence) to programmatically set the A to lazy load, but it gets called before my BeanFactoryPostProcessor's postProcessBeanFactory method.
Is what I'm trying to achieve possible and am I going about it the wrong way?
#Lazy is only to be used with #Bean or #Component (Or any #Component-based annotations ex. #Service)
Take note: You can also add it to a #Configuration class, but that just means that all Beans in the class are annotated with #Lazy
#Lazy is a bit of a weird annotation in general; it should be seen as an IF possible then lazy load. If some other bean needs the lazy bean, the lazy bean will be initialized. (It's like the Pirate code, more of a guideline than an enforced rule)
Finally, marking #ConfigurationProperties with #Lazy seems a bit odd. As Spring will need these Configuration property "beans" to create the Spring Context.
However, the common use case for #Lazy is a failing database connection, preventing the application from starting. See the question if that is what you are running into.
Summary:
You can configure your repositories to be lazy-loaded with:
spring.data.jpa.repositories.bootstrap-mode=lazy
Last remark (Me just guessing)
If you wish to change properties once your application is already running, I would look at the following tutorial. It goes into manually reloading configuration and also #RefreshScope.
According to documentation EnvironmentPostProcessors must be registered via META-INF/spring.factories:
Allows for customization of the application's Environment prior to the
application context being refreshed. EnvironmentPostProcessor
implementations have to be registered in META-INF/spring.factories,
using the fully qualified name of this class as the key.
Implementations may implement the Ordered interface or use an #Order
annotation if they wish to be invoked in specific order.
I try to deploy an EJB 2.1 based application on a Websphere Application Server v7.0.0.23 with some Spring initialization code into the onEjbCreate method of the MDB:
#Override
protected void onEjbCreate() {
getBeanFactory().getBean("myBean");
}
But this method is called on the reception of the message and not at the application startup. How can i force WAS to instanciate my MDB before the message reception ?
Edited my response to be more correct and highlight the information Tracy mentioned:
By default, the EJBContainer defers initializing beans until they are first called. Furthermore, ejbCreate() is called each time a new bean is created. MDB instances are not created until a relational resource adapter (RAR) asks for one; typically when a message is delivered. Since, ejbCreate runs for every instance, so if the RAR asks for say 50, then ejbCreate will be called 50 times.
You could programmatically look up the bean and create it somehow before it receives a message to trigger your initialization code, but you probably don't want to run your initialization code every time a bean is created anyway, so the best option is to use a startup bean. Since you are using EJB2.1 beans and Was7 EJB Container has a 'legacy' startup bean
In EJB3.0 Startup Singleton beans were introduced which can be added either by annotating the class with #Singleton #Startup or configured on individual beans with ejb-jar.xml file:
<session name="[bean-name]">
<start-at-app-start value="true"/>
</session>
Moving up WAS/EJB versions and using this is your best bet.
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.
I'm far from an expert of the intricacies of Resource Injection, and of indeed DataSources in Java, but I generally understand the process of doing a lookup for a predefined JNDI resource to get a datasource from.
Using Resource Injection as an alternate method, the below syntax works:
#Resource(name="jdbc/Foo")
private javax.sql.DataSource con;
However, I am using this in a servlet and as such wondering, how long this injected connection object's value will exist? Presumably, as it's simply an object within the servlet, it will inject when the servlet is first instantiated and exist for the same duration as the servlet (assuming I don't manually change it). Is this correct? Or does the servlet re-inject the resource everytime the servlet is used?
Thanks
A servlet container only ever creates one instance of your servlet. The IoC container you're using will then instantiate and inject the DataSource, so the value in con will remain the same for the life of your servlet, ie. the life of the application.
As to the underlying connection the DataSource is trying to make will, that's up to your datasource.
it will inject when the servlet is first instantiated and exist for the same duration as the servlet
Correct.
Or does the servlet re-inject the resource everytime the servlet is used?
No, this couldn't be happening because each request is served by a different thread. It wouldn't be good if those threads would modify the fields of the servlet. Request processing methods of the servlet must not modify its fields.
Generally container managed resources are injected using #Resources annotation. And container managed resources live as long as the container is running ( unless your are not manually kill it or any exception happens). Several applications can use the same resource object, provided that they live in the same application server ecosystem (same application server or cluster or server domain). But servlets are managed by your applications and lives within the application's scope as long as your application is running! So in terms of life span, if you compare resources are longer living than servlets.
And yes you are right, if you inject resources to a servlet, the reference of the resource will remain from the creation of the servlet to the end of the servlet's life cycle. The injection is not related with, how you are using the servlet or the resource.
Hope, this answers your question, Thanks!
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)