How to do conditional bean creation using SPEL? - java

I have two beans in my application context and a property ${applicationType}
BeanTypeA
<bean id="beanTypeA" class="com.ext.library.A">
<constructor-arg><value>boot</value></constructor-arg>
</bean>
BeanTypeB
<bean id="beanTypeB" class="com.ext.library.B">
<constructor-arg><value>boot</value></constructor-arg>
</bean>
How do I control which beans to be created based on the SPEL in xml configurations using the property ${applicationType}
I am already using spring profiles for a different purpose in the application. So in this case, I won't be able to overload multiple spring profiles. Trying to achieve the conditional creation of bean using SPEL.
Thanks for the inputs.

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?

Advice on how to refactor spring mvc into plain servlets or jetty handler

I have a spring mvc app that I want to refactor out, speficially removing the spring related code and wiring.
It is a simple spring mvc at this point, so the key things I have to do our dependancy injection.
My application.xml has wirings for my Dao objects, injecting the datasource into my Dao objects.
How can I use a spring agnostic DI now? What do I have to change? I want to use guice unless you guys recommend otherwise
application.xml:
<bean id="userDao" class="com.blah.dao.UserDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
What do you suggest I use to setup my datasource and connection pooling now?
The actual page/url mapping is specific to if I choose servlets or a jetty handler.
You can use the standard annotation #Inject for dependency injection. Both Spring and Guice support it.

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.

Correct usage Of LOG4J in Spring Framework Via DI

I am trying to use Log4j as part of the Spring Framework,
as far as i understand through the use of a an appropriate bean
the system is supposed to map a singleton instance accessible in the code
while mapping the logging depth automatically to the class
Similar to the normal use of Log4J as in
Logger log = Logger.getLogger(getClass());
i have been using the following Spring bean definition
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>conf\log4j.xml</value>
</list>
</property>
</bean>
But i am unable to map this bean to a specific member in a given class
nor am i able to use it through #autowired
Please let me know if there are any better ways to integrate Log4j and Spring
Best Regards
Mark
The short answer to your question is that log4j is not DI friendly.
The Log4jConfigurer.initLogging() method has a void return value, so there's nothing to inject. The idea is that you call that method, which bootstraps log4j, and then you use the Log4j API as usual (using Logger.getLogger(getClass())).
You generally wouldn't configure Log4jConfigurer as a Spring bean, though, but more usually you'd invoke it directly from your own code during application startup.
If this is a webapp, then Spring provides alternatives to Log4jConfigurer that are better suited to that environment (Log4jWebConfigurer, Log4jConfigListener).
Incidentally, 2 years ago I filed a feature request to allow loggers to be autowired, and it's finally been marked as fix for Spring 3.1. Horray.

Categories

Resources