Loading Bean without explicitly referencing or retrieving it - spring

In my application I use an XML Application Context to configure and build Spring beans.
I have a bean which is an observer and an observed bean. The configuration looks something like
<bean class="com.example.Observer">
<property name="observedBean">
<bean class="com.example.Observed" />
</property>
</bean>
My problem is, that there is nobody explicitly asking for a reference of the observer neither the observer nor the observed bean will be created.
Since there is no need of an explicit reference I would like to avoid just asking the ApplicationContext for a reference to just ignore it again.
Is there any solution for my problem or do I have a problem with my concept?

Related

context:property-placeholder doesn't resolve references

I have next applicationContext.xml file on the root of classpath:
<context:annotation-config />
<context:property-placeholder location="classpath:props/datasource.properties" />
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"
p:username="${jdbc.username}"
p:password="${jdbc.password}"
p:url="${jdbc.url}"
p:driverClassName="${jdbc.driverclass}"
p:validationQuery="SELECT sysdate FROM dual" />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="datasource"
p:mapperLocations="classpath:mappers/*-mapper.xml" />
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="datasource" />
<bean id="mappeScannerConfigurere" class="org.mybatis.spring.mapper.MapperScannerConfigurer"
p:sqlSessionFactory-ref="sqlSessionFactory"
p:basePackage="com.mypackage" />
props/datasource.properties also exists on the root of classpath with such content:
jdbc.url=myjdbcurl
jdbc.driverclass=myClass
jdbc.username=myUserName
jdbc.password=myPassword
I have a spring managed test where I declare to use previously mentioned applicationContext.xml via next annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:applicationContext.xml"})
When I invoke test method i get next error from spring:
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${jdbc.driverclass}'
As I understand sping didn't resolve reference to jdbc.driverclass.
What have I done wrong?
PS: I'm using spring 3.2.3.RELEASE
**
EDIT
**
Perhaps the problem may be in MapperScannerConfigurer. It is a BeanDefinitionRegistryPostProcessor and as Javadoc says:
Extension to the standard BeanFactoryPostProcessor SPI,
allowing for the registration of further bean definitions
before regular BeanFactoryPostProcessor detection kicks in
So MapperScannerConfigurer instantiates datasource object via sqlSessionFactory with BeanFacoryPostProcessor(which is responsible for <context:property-placeholder/>) have not been utilized.
So my question transforms to how to reorder BeanFacoryPostProcessor from <context:property-placeholder/> and BeanDefinitionRegistryPostProcessor(MapperScannerConfigurer)?
Resolved
After a couple hours of investigation I found the solution:
As I said earlier MapperScannerConfigurer is a BeanDefinitionRegistryPostProcessor which fires before BeanFactoryPostProcessor which is responsible for <context:property-placeholder/>. So, during the creation of MapperScannerConfigurer references to external properties will not be resolved. In this case we have to defer the creation of datasource to the time after BeanFactoryPostProcessorhave been applied. We can do that in several ways:
remove p:sqlSessionFactory-ref="sqlSessionFactory" from MapperScannerConfigurer. In this case datasource object will not be created before MapperScannerConfigurer, but after BeanFactoryPostProcessor which is responsible for <context:property-placeholder/>. If you have more than one sqlSessionFactory in applicationContext, than can be some troubles
In versions of mybatis-spring module higher than 1.0.2 there is a possibility to set sqlSessionFactoryBeanName instead of sqlSessionFactory. It helps to resolve PropertyPlaceHolder issue with BeanFactoryPostProcessor. It is a recommended way to solve this issue described in mybatis-spring doc
I was having the same issue and came across this post but I was unable to resolve it the same way maks did. What ended up working for me was to set the ignoreUnresolvablePlaceholders property value to true.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:database.properties</value>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
I am using Spring 3.2.3.RELEASE as well. I realize this post is over 4 months old but I figured someone might find it useful.
Short form: What is the proper way to load an implementation of: BeanDefinitionRegistryPostProcessor?
Expanded form: Is there a way to load BeanDefinitionRegistryPostProcessor before any beans have been created. If you look at the javadoc:
Extension to the standard {#link BeanFactoryPostProcessor} SPI, allowing for
the registration of further bean definitions before regular
BeanFactoryPostProcessor detection kicks in.
So it's meant to be loaded when bean definitions have been created but before any beans have been created. If we just create it as a regular bean in the application xml then it defeats the purpose of having this bean in the first place.

Setting property reference for a bean programmatically

Right now i am using the following bean entry
<bean id="Service" >
<property name="target">
<bean class="someClass" lazy-init="false">
<property name="SessionFactory1"><ref bean="SessionFactory1"/></property>
<property name="SessionFactory2"><ref bean="SessionFactory2"/></property>
<property name="SessionFactory3"><ref bean="SessionFactory3"/></property>
</bean>
</property>
</bean>
Now the requirement is to first check which all session factories have an active datasource and include those only in the above bean definition. So that the application does not break if we try to initialize a session factory with inactive datasource.
sessionfactory initialization will be take care by using seperate config xml for session factories and loading only the ones with active datasources.
Please help on how can this be achieved.
You can use Spring InitializingBean interface, which makes you implement an afterPropertiesSet() method. This method will be executed after Spring instantiates your class, and you could check if your session factories are available or not.
InitializingBean: Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory: for example, to perform custom initialization, or merely to check that all mandatory properties have been set.
link: Spring InitializingBean

Trouble integrating a library using Apache Commons Config with Spring project using PropertyPlaceholderConfigurer

I have a custom library that sends a JMS notification. The idea is that you can use the library by simply by setting some properties in your project.
The custom library is using the Apache Commons Configuration. (The reason I mention this is that I suspect it may be playing a role in my problem). I'm trying to use it in my current Spring project which doesn't use Commons Config but uses the PropertyPlaceholderConfigurer. I've got the properties I need written out in a .properties file.
I've added the library as a dependency in my pom.xml file. I tried adding it into my web.xml like so
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
...
classpath:mylibrary-context.xml
</param-value>
</context-param>
When creating a bean in my Spring project, I tried to reference one of the beans defined in the library, so I could use it. There's an error creating one of the library beans that requires a property from my properties file.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'libraryBean' defined in class path resource [mylibrary-context.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type 'java.lang.String' to required type 'boolean' for property 'useCompression'; nested exception is java.lang.IllegalArgumentException: Invalid boolean value [${foo.bar.use.compression}]
I know some of the other properties files in the project have boolean properties set the exact same way without issue. Here is how I'm loading the properties files in the applicationContext.xml(which after checking the logs, seems to load correctly)
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
...
<!-- loaded in order-->
<value>classpath:foo/bar/some-props.properties</value>
<value>classpath:foo/bar/some-monitoring.properties</value>
<value>file:/${user.home}/foo/bar/some-monitoring.properties</value>
<value>file:/etc/foo/bar/some-monitoring.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
and finally my some-monitoring.properties file:
foo.bar.use.compression=true
foo.bar.name=foobar
foo.bar.broker.url=someurl
So I'm just wondering what's going on with the boolean property and why? If its a general problem with the PropertyPlaceholderConfigurer not loading boolean properties, its odd that I'm not having a problem with the other properties files. Is it that there is some conflict because of the library using the Commons Configuration? My knowledge of how Spring loads up these properties is pretty shallow so this seems like a chance to get a better handle on what's going on under the covers.
If anyone can shed some light on what's going on and how to fix/get around it, any help is greatly appreciated!
Quoting Jurgen on the spring-dev list:
PropertyPlaceholderConfigurer is an implementation of the BeanFactoryPostProcessor interface: This interface and its sibling
BeanPostProcessor just apply to the BeanFactory that defines them,
that is, to the application context that defines them.
If you combine multiple config files into a single
contextConfigLocation, a PropertyPlaceholderConfigurer defined in any
of the files will apply to all of the files, because they are loaded
into a single application context.
As far as I understand, you tried to combine all your application contexts into the contextConfigLocation. According to the quotation, it should work fine. I think that you have other kind of problem. In my opinion both boolean and string properties are not loaded at all. Maybe it seems as string properties are loaded, but I think that their values are set to ${foo.bar.name} and ${foo.bar.broker.url}. Since they are Strings, they can hold these values. When Spring tries to set ${foo.bar.use.compression} to the boolean, you have typecast problem which just reveals wider issue.
Probably, if you set:
<property name="ignoreResourceNotFound" value="false"/>
<property name="ignoreUnresolvablePlaceholders" value="false"/>
you will see that PropertyPlaceHolderConfigurer cannot resolve your properties files.
Please also try using classpath*: notation when you refer to resources from other JARs.

Why is autowiring required? What is the explanation of the concept of autowiring?

Why is autowiring required? What is the explanation for the concept of autowiring?
#autowired annotation in Spring Framework.
Autowiring is not required, just convenient.
It means that if you have a property that requires an InterfaceA and a single bean has been declared in Spring that is of type InterfaceA, instead of using XML to manually "wire up" the relationship (setting a bean reference as a property of another), you can let Spring do the wiring for you.
This is a common question for the beginners. As the beans are injected using DI (setter injections, constructor injections), why do we need auto-wiring? Auto-wiring also doing the same thing, right?
The answer is, it saves you from writing more code.
If using an XML file, using autowire attribute saves you from writing the wiring code in the bean definition.
Please look at code below.
Configuration code without Auto-wiring:
<bean id="employee" class="com.Employee">
<property name="name" value="Dexter"></property>
</bean>
<bean id="employeeService" class="com.EmployeeService">
<property name="employee" ref="employee"></property>
</bean>
Configuration code with Auto-wiring:
<bean id="employee" class="com.Employee">
<property name="name" value="Dexter"></property>
</bean>
<bean id="employeeService" class="com.EmployeeService" autowire="byName" />
Note that we did not have to write anything to refer property of EmployeeService, i.e., Employee. But still it was injected. Autowiring makes the container to search the bean configurations and do the collaboration among beans, without the developer specifically mentioning these.
If we use annotation, even we don’t have to write anything in XML files, including this autoware="byName", etc. Simply #Autowired on bean's setter/field/constructor is sufficient.

how Spring MVC find its handler mapping

in Spring MVC we can configure handler mapping as bean.but how spring examine what is the handler mapping we mentioned in xml?
simpliy
<bean id="simplehandler" class="" />
do we need to specify "simplehandler" bean id to somewhere for spring to identify bean handler?
First thing that must be clear is that: Spring has several handler mappings.
And the "DefaulAnnotationHandlerMapping" is activated by default (See DispatcherServlet.properties in the Spring distribution or just google for it. All default handlers are listed there). Spring will choose "DefaulAnnotationHandlerMapping" by default.
If you want Spring to use another handler mapping strategy, you have to tell him explicitly
e.g.:
<bean class="org.blablabla......ControllerClassNameHandlerMapping" />
Note that this cancels the use of the default handler mapping strategy
You can also tell Spring to use several handler mapping strategy and prioritized them by using the order property in the mappers declaration
something like
<bean class="org.blabla....DefaulAnnotationHandlerMapping" >
<property name="order" value="0"/>
</bean>
<bean class="org.blablabla......ControllerClassNameHandlerMapping">
<property name="order" value="1"/>
</bean>
Hope this helps. And sorry if the syntax of my bean declaration is not 100% correct. I had to write quickly ;-)

Resources