I am new to Spring framework and confused how to load properties of a bean ( Instance variables of a bean ) dynamically . Spring expects to use xml based configuration for declaring all the beans and dependencies between beans .
For example ,
public class Bean1
{
int value;
public void setValue(int thisValue)
{
value = thisValue;
}
}
<bean id = "LibraryMgmtBean" class = "Bean1">
<property name = "value" Value = "SampleString"/> </bean>
But here we are mentioning all the properties of a bean statically . But , what if I want to supply these values dynamically . I mean , I may get values from a JSP page from weblayer and should pass to this bean . And as all beans are declard in XML this way , how Spring Injects dependecies of other beans when all bean properties are supplied dynamically ?
Found answers to my question from threads:
How to collect spring properties from multiple files for use on a single bean
Apply dynamic properties to a bean at runtime
Loading Properties with Spring (via System Properties)
Related
I have a question around the usage of new keyword being used when using java configuration in spring. What is the need of using new keyword
Refer below mentioned example:
Code implemented using Java Config
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
The above code will be equivalent to the following XML configuration
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
In XML config, we do not use new keyword whereas in java config we are using new keyword. can someone please explain the difference
In the XML configuration, you explain to the system what class should be instanciated (there is a "new" but it is behind the scene) but in the Java Config you actually have to return an instance so that is why we use the 'new' keyword. 'new' simply creates an instance of your class.
The two examples shown in question are not really equivalent.
What the
<beans>
<bean id="helloWorld"
class="com.test.HelloWorld" />
</beans>
really does, is it tells Spring to instantiate class com.test.HelloWorld, and name the resulting bean "helloWorld".
Then the java-config approach is not really doing this. Instead this follows the factory-method pattern, when we tell Spring, that the return value of the method is the bean, and the method name is the name of that bean.
An equivalent of that in XML would be the mentioned factory-method approach, which in this case would look something like this:
<beans>
<bean id="helloWorldConfig"
class="com.test.HelloWorldConfig" />
<bean id="helloWorld"
factory-bean="helloWorldConfig"
factory-method="helloWorld" />
</beans>
Note that there are several approaches to factory-method. In the above, we are assuming, the `helloWorldConfig" is the factory, and we're specifying the method on that bean. Theare are cases with static factory methods too. See here for more examples.
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
This XML configurations tells Spring to "create an instance of com.test.HelloWorld and put it in the bean context with bean id helloWorld".
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
In this Java configuration, we are returning an instance of com.test.HelloWorld. Because of the #Bean annotation, this instance is put into the bean context. As no specific bean id is given, the bean id is derived from the method hellowWorld() and thus becomes helloWorld.
As you can see, both configurations require an instance of com.test.HelloWorld. The XML configuration implicitly creates the instance whereas in the Java configuration you have to explicitly do it yourself.
I am using a Grails 3.3 application that uses GORM 6.1.6.RELEASE, Spring-Boot 1.5.4.RELEASE and Spring Core 4.3.9.RELEASE behind the scene. I am trying to declare a Spring bean that get initialized just before Hibernate starts to validate the underlying database schema.
Here is what I like to do. I want to register my Flyway as a Spring bean and inject the dataSource bean into it. In order to have Flyway run before Hibernate starts to validate the current database schema, I add my flyway bean as a dependency onto the sessionFactory bean. The order would be as follows:
dataSource bean
flyway bean
hiberateDatastore bean
GORM 6.1 uses org.grails.orm.hibernate.HibernateDatastore as a Spring bean to initialize the Hibernate ORM and the database. The sessionFactory bean declares the hibernateDatastore#getSessionFactory as factory class.
Therefore the hibernateDatastore always is created first.
What is the way in Grails 3.3 to create a custom Spring bean that has to run after the connection to the database is available but before the Hibernate stuff gets initialized?
In previous versions of Grails 3.x it was possible to declare it in resources.groovy like this.
beans = {
if (Environment.current == Environment.PRODUCTION) {
flyway(Flyway) { bean ->
bean.initMethod = 'migrate'
dataSource = ref('dataSource')
locations = 'classpath:db/h2'
baselineOnMigrate = true
}
BeanDefinition sessionFactoryBeanDef = getBeanDefinition('hibernateDatastore')
if (sessionFactoryBeanDef) {
def dependsOnList = ['flyway'] as Set
if (sessionFactoryBeanDef.dependsOn?.length > 0) {
dependsOnList.addAll(sessionFactoryBeanDef.dependsOn)
}
sessionFactoryBeanDef.dependsOn = dependsOnList as String[]
}
}
}
I don't think Spring provides a visualisation of a 'bean instantion tree' however you could set the log level for org.springframework.beans.factory.support.DefaultListableBeanFactory to DEBUG and you'll get output like this:
Creating shared instance of singleton bean '...fully qualified class name...'
Returning cached instance of singleton bean '...fully qualified class name...'
You could review this log output for beans from the Hibernate namespace.
I presume you'll use the results to declare a DependsOn relationship so just for completeness this would look like:
#Bean
public SomeHibernateClass createHibernate() {
...
}
#Bean
#DependsOn("createHibernate")
public MyClass createMine() {
...
}
Grails 3.3.0 changed the mechanism of the dataSource bean creation. The Grails project lead stated in the related issue:
Previous versions of Grails created the dataSource bean separately from the session factory. We would need to restore this behaviour I guess so the dataSource can be referenced without triggering the creation of the sessionFactory
After upgrading to Grails 3.3.1 the dataSource bean is again available before the session factory gets created. This solves the problem.
I noticed that if you define a bean with same id in two xml files, it would be overiden in the second file.
Say in file a.xml i have
<bean id="abc" />
Say in file b.xml i have
<bean id="abc" />
then the bean "abc" of b.xml is picked up. Is there a way in Spring to stop from overiding i.e should be unique no matter how many xml have the bean abc.
You can disable the feature to disallow beanoverriding by calling the setAllowBeanDefinitionOverriding and pass false. This has to be done early on before anything is loaded. You would either need to create your own custom ContextLoader for this or (if you are on Spring 3.1 or up) you can create an ApplicationContextInitializer and register this in your web.xml.
public class OverrideDisablingApplicationContextInitializer implements ApplicationContextInitializer {
public void void initialize(<? extends ConfigurableApplicationContext> applicationContext);
if (applicationContext instanceof AbstractRefreshableApplicationContext) {
(AbstractRefreshableApplicationContext (applicationContext)).setAllowBeanDefinitionOverriding(false);
}
}
in your web.xml add the following (for the ContextLoaderListener use an init-param for the DispatcherServlet when needed)
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>your.package.here.OverrideDisablingApplicationContextInitializer<param-value>
</context-param>
From the top of my head this should disable the overriding behavior. If you use springs WebApplicationInitializer it is even easier as you are probably constructing the ApplicationContext yourself, you can then simply call the method directly and no ApplicationContextInitializer is needed.
Links
ApplicationContextInitializer javadoc
AbstractRefreshableApplicationContext.setAllowBeanDefinitionOverriding javadoc
Also:
final ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();
ctx.setAllowBeanDefinitionOverriding(false);
ctx.setConfigLocations(shardContextImport);
ctx.setParent(refreshedEvent.getApplicationContext());
ctx.refresh();
I am beginner to spring, ESP Inversion of control. I was puzzled understanding the difference between the following
<bean id="demo" class="Demo" lazy-init="false"/>
<bean id="demo" class="Demo" lazy-init="true"/>
<bean id="demo" class="Demo" lazy-init="default"/>
To my understanding : lazy-init=false creates the bean at the startup and lazy-init=true doesn't create a bean at the startup rather creates the bean upon request for a particular bean.
Correct me here, If my interpretation is wrong.
what exactly the default behavior of lazy-init is? How would it instantiate?
The default behaviour is false:
By default, ApplicationContext implementations eagerly create and
configure all singleton beans as part of the initialization process.
Generally, this pre-instantiation is desirable, because errors in the
configuration or surrounding environment are discovered immediately,
as opposed to hours or even days later. When this behavior is not
desirable, you can prevent pre-instantiation of a singleton bean by
marking the bean definition as lazy-initialized. A lazy-initialized
bean tells the IoC container to create a bean instance when it is
first requested, rather than at startup.
I suggest reading up
For those coming here and are using Java config you can set the Bean to lazy-init using annotations like this:
In the configuration class:
#Configuration
// #Lazy - For all Beans to load lazily
public class AppConf {
#Bean
#Lazy
public Demo demo() {
return new Demo();
}
}
For component scanning and auto-wiring:
#Component
#Lazy
public class Demo {
....
....
}
#Component
public class B {
#Autowired
#Lazy // If this is not here, Demo will still get eagerly instantiated to satisfy this request.
private Demo demo;
.......
}
The lazy-init="default" setting on a bean only refers to what is set by the default-lazy-init attribute of the enclosing beans element. The implicit default value of default-lazy-init is false.
If there is no lazy-init attribute specified on a bean, it's always eagerly instantiated.
lazy-init is the attribute of bean. The values of lazy-init can be true and false. If lazy-init is true, then that bean will be initialized when a request is made to bean. This bean will not be initialized when the spring container is initialized
and
if lazy-init is false then the bean will be initialized with the spring container initialization.
When we use lazy-init="default" as an attribute in element, the container picks up the value specified by default-lazy-init="true|false" attribute of element and uses it as lazy-init="true|false".
If default-lazy-init attribute is not present in element than lazy-init="default" in element will behave as if lazy-init-"false".
I have following code inside my class
public void startListeners() throws Exception {
List<QueueConfiguration> queueConfigs = queueConfigResolver.getQueueConfigurations();
for(QueueConfiguration queueConfig : queueConfigs){
//TODO : work on this make it more testable
ICustomListener readerListener = new MyCustomListener(queueConfig);
readerListeners.add(readerListener);
readerListener.start();
}
}
I am using Spring for dependency injection(not in this case but overall). Now there two problems with this code.
I cannot put mock for each of the listeners created, while testing.
I dont want to use ApplicationContext.getBean() because it will have same affect. AFAIK spring cannot do this dynamically , but any other pointers?
As far as I can understand, you want to create a new bean instead of
ICustomListener readerListener = new MyCustomListener(queueConfig);
If that is the case, creating a factory for mycustomlistener and using
public abstract TestClient createTestClient();
to create your beans, and defining
<bean id="testClient" class="com.myproject.testbeans.TestClient" scope="prototype">
</bean>
<bean id="testClientFactory" class="com.myproject.testbeans.TestClientFactory">
<lookup-method name="createTestClient" bean="testClient" />
</bean>
in your context will solve your problem. This way, every time the createTestClient method of the factory is called, a new bean is created and given to your code. However, you have to give the config object via a setter instead of the constructor.