Reference "auto detected" bean in Spring's context - java

I configured spring to auto-detect some DAOS using
<context:component-scan base-package="com.mycomp.app" />
<tx:annotation-driven />.
#Repository("transactionDao")
public class TransactionDao {
...
}
Now I'm configuring manually in context another bean which references this one.
<property name="schedulerContextAsMap">
<map>
<entry key="transactionDao" value-ref="transactionDao" />
</map>
</property>
Now Spring's complaining:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'transactionDao' is defined
Is it possible to reference auto detected bean inside context?

Is it possible to reference auto detected bean inside context?
Yes it is very much possible.
In order to see why transactionDao bean was not found, you can verify the following things:
TransactionDao should be in classpath and lies in some sub-package of com.mycomp.app
If Step-1 is already there, run the application with Logger level for org.springframework set to DEBUG and you can see in the startup logs of spring which all beans got initialized.

Related

Spring-Boot: Jmx annotation not working in library

I have a Spring-Boot application that just have a simple rest controller. On this controller, I added the jmx annotations #ManagedResource and #ManagedOperation and it is working fine. It is correctly exposed in Jmx.
This application depends on a "global-commons" library to share many basic functionality to all of our modules.
But if I add the same annotations to a class in this library, it is ignored!
And before you ask, yes the library is imported with the latest change.
There is no error or warning message in the logs.
I am configuring all my beans using an xml file. Both classes are beans defined in the same file.
One is a #RestController. The other one is a simple utility class.
Any idea?
Make sure the classes from the global-commons library as managed by Spring. As long as none of the classes in the library are managed by Spring, the annotions don't have any effect.
I found the problems:
The bean that was not working was defined as an "inner" bean:
<bean id="imMetrics" class="com.imetrik.global.common.metrics.ImGlobalMetrics" init-method="init">
...
<property name="reporterList">
<util:list>
<bean id="jmxReporter" class="com.imetrik.global.common.metrics.reporters.ImJmxReporter">
<property name="registryId" value="metricRegistry1"/>
<property name="durationUnit" value="SECONDS"/>
<property name="rateUnit" value="SECONDS"/>
<property name="domain" value="com.imetrik.global.metric"/>
</bean>
</util:list>
</property>
</bean>
The annotated beans is "jmxReporter".
But if I put it outside as a normal "first level" bean and use a reference instead, it is working.
But it is annoying! Is there a way to make it work even as a inner beans?

Spring Property Consolidation

I've got a Spring bean:
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="#{ config['app.name'] }"/>
</bean>
This bean is defined in a jar and used in two apps that both get deployed to the same tomcat server. I've only got one properties file the apps share and I'd like to keep it that way if possible. You might see the problem - I need two values for app.name (one for each web app).
I need to set the app.name independently in each app. I don't mind hard coding the value in the Java (but don't think I can inject the value in that direction). I know I can introduce another properties file at a different path and override but I'm hoping there is a better way I can accomplish this through Spring that will allow me to maintain only one shared properties file.
Possible solutions, in recommended order:
1 - is there a reason why the shared bean is declared in a separate jar file? Certainly, the bean class can be located there, but why not declare the actual bean inside the individual web apps where it's being used?
2 - if you absolutely need to keep the bean definition in the shared jar you can use bean inheritance; (a) change your bean class to use a property rather than a constructor arg:
<bean id="sharedBean" class="com.bean.SharedBean">
<property name="app-name" value="default"/>
</bean>
(b) in your web app context file:
<bean id="instanceBean" parent="sharedBean">
<property name="app-name" value="app1"/>
</bean>
3 - use a Spring profile; in your shared jar context.xml:
<beans profile="app1">
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="app1"/>
</bean>
</beans>
<beans profile="app2">
<bean id="sharedBean" class="com.bean.SharedBean">
<constructor-arg name="app-name" value="app2"/>
</bean>
</beans>
note: <beans profile=... MUST be the last entries in your context file.
Add a context param to each web.xml (changing value as appropriate):
<context-param>
<param-name>spring.profiles.default</param-name>
<param-value>app1</param-value>
</context-param>

property not found with multiple context:property-placeholder

I am using spring 3.1 with spring profiles to load the beans. In my app context file, I load the properties like :
<context:property-placeholder order="1" location="classpath*:META-INF/spring/*_${spring.profiles.active}.properties" ignore-unresolvable="true"/>
And then I use the property value to load the data source bean like
<property name="driverClassName" value="${database.driverClassName}"/>
It works fine.
The problem starts when I add a couple of more property placeholders so that properties from some database tables can be loaded.
This uses a properties reference loaded by
<bean id="configFactoryBean"
class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
<constructor-arg ref="globalSystemConfiguration"/>
</bean>
To add to the details, this configFactoryBean uses the datasource to load the properties from the database.
When I do this, I have the following exception:
java.lang.ClassNotFoundException: ${database.driverClassName}
My analysis is that its trying to load the datasource before resolving the property from the first context property placeholder. I may be wrong. Or maybe spring profile variable is not resolved properly.
Can anyone please help me to fix this.
Thanks
Akki
This bug about multiple property placeholders might relate to your problem: https://jira.spring.io/browse/SPR-9989
When using multiple PropertyPlaceholderConfigurer in conjunction with
#Value annotation and default value for placeholders syntax (ie
${key:defaultValue}), only the first PropertyPlaceholderConfigurer is
used. If this configurer does not contain the desired value, it falls
back to #Value default even if the second
PropertyPlaceholderConfigurer contains the value.
Affects Version/s: 3.1.3
Each <context:property-placeholder> creates a new instance of PropertyPlaceholderConfigurer - it gets messy easily. You should have one such thing per application and on application level, not on libraries' one - that makes maintenance much easier.
For more details and a suggestion how to cope with it look here:
http://rostislav-matl.blogspot.cz/2013/06/resolving-properties-with-spring.html
In my application I am using property-placeholder configurer in following way and it works very well. You can try that.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/spring/*_${spring.profiles.active}.properties</value>
</list>
</property>
</bean>
I think this should resolve your problem. :)
Since you have suggested hardcoding the path to the configuration file works, try using the profiles attribute on the tag to selectively include the configuration.
<beans profile="profileName">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
<beans profile="profileName2">
<context:property-placeholder order="1" location="classpath*:META-INF/spring/hardcoded.properties" ignore-unresolvable="true"/>
</beans>
See this article explaining profiles: http://java.dzone.com/articles/using-spring-profiles-xml

Changing scope of many Spring beans during tests

I'm running tests using spring (SpringJUnit4ClassRunner and #ContextConfiguration). The tests are run in parallel.
Some of my beans are singleton, and I would like to change them to be in scope "thread" of the tests. I want each test to have its own instance of the bean.
I've managed to it by having an applicationContext.xml file and a applicationTestContext.xml file which is used for tests.
In the applicationTestContext.xml I define those beans with scope "thread".
The problem with this is that everytime we add a new bean of that type, we'll have to add it to both applicationContext.xml and applicationTestContext.xml which is pretty annoying.
Is there a way to do it with less boilerplate?
Gather up all the beans whose scope you want to customize and put them in a separate bean config file, included from both applicationContext and applicationTestContext, e.g.
<import resource="customScopedBeans.xml"/>
Then use a placeholder for the scope
<bean class="com.Foo" scope="${threadOrSingleton}" />
and declare the property differently in the parent config file.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>threadOrSingleton=thread</value>
</property>
</bean>

Bean that uses ehcache cannot be injected

I use Spring 3.0 and ehcache. I have added #Cacheable annotations to some methods of a bean. I am injecting that bean into other beans and it is registered in my application context xml file. The application was working before adding ehcache annotations (I use com.googlecode.ehcache-spring-annotations v 1.2.0), but after adding the annotations, Spring is unable to properly inject the beans that contain the annotations. The error I see in my log file is:
org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type '$Proxy67 implementing java.io.Serializable,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type '{my bean type}' for property '{property}'.
Here is what I have added to my application context for ehcache to work:
<context:annotation-config />
<context:component-scan base-package="{my root package}" />
<ehcache:annotation-driven cache-manager="cacheManager" />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>
I think the configuration is OK, because at first I had some issues loading the ehcache.xml file and there was a corresponding error in the logs for that. After I fixed the problem, I got the error above. It seems that spring creates a proxy for my bean that internally calls the caching logic for ehcache, but fails to make that proxy convertible to the bean type.
See Spring (3.1) Reference: Chapter 27. Cache Abstraction
In your configuration, you are using, Interface Base Proxies.
So the Bean that uses the Bean with the cached Method must refer to its interface, not to its concrete class.
Or you can change the configuration proxy-target-class="true" to use class based proxies.

Categories

Resources