Hi,
While trying to configure Ehcache JMS replication, I stumbled upon a weird (to me) behavior: a class with the @Configurable annotation has its dependencies *not* wired if it is instantiated from a bean's afterPropertiesSet method.
We use AspectJ compile-time weaving, together with the usual <context:annotation-config/>, <context:component-scan base-package="..."/> and <context:spring-configured/>. Everything works as expected in the rest of the application. Here is what we have at context loading time:
- The ehcache.xml configuration is read
- The CacheManager instance is created an initialized
- The SpringJmsCacheManagerPeerProviderFactory class name is found in the config
- This class is loaded and an instance created (by reflection). Now I would expect the instance to have its dependencies wired
- The class tries to do its stuff (connecting to JMS, etc.) -> This fails with NPE because of missing dependencies.
The issue seems to be that the Ehcache stuff is initialized in EhcacheManagerFactoryBean.afterPropertiesSet method. I could reproduce it with a similar setup not involving reflection.
Is it expected behavior?
Here is (some of) the code:
The cache manager bean is configured with an EhcacheManagerFactoryBean. I have the following ehcache.xml file:
Here is the com.example.cache.SpringJmsCacheManagerPeerProvide rFactory class:HTML Code:<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect" dynamicConfig="true"> <diskStore path="java.io.tmpdir" /> <cacheManagerPeerProviderFactory class="com.example.cache.SpringJmsCacheManagerPeerProviderFactory" properties="listenToTopic=true" propertySeparator="," /> <defaultCache maxEntriesLocalHeap="0" eternal="false" timeToIdleSeconds="1200" timeToLiveSeconds="1200"> </defaultCache> <cache name="jdo.cache" maxEntriesLocalHeap="1000" eternal="false" overflowToDisk="true" diskPersistent="false" timeToIdleSeconds="300" timeToLiveSeconds="600" diskExpiryThreadIntervalSeconds="1" memoryStoreEvictionPolicy="LFU"> <cacheEventListenerFactory class="net.sf.ehcache.distribution.jms.JMSCacheReplicatorFactory" properties="replicateAsynchronously=false, replicatePuts=false, replicateUpdates=false, replicateUpdatesViaCopy=false, replicateRemovals=false, loaderArgument=sampleCacheNorep" propertySeparator="," /> </cache> </ehcache>
Thanks in advance.Code:@Configurable public class SpringJmsCacheManagerPeerProviderFactory extends CacheManagerPeerProviderFactory { @Autowired @Qualifier("jmsConnectionFactory") private TopicConnectionFactory topicConnectionFactory; @Autowired @Qualifier("jmsConnectionFactory") private QueueConnectionFactory queueConnectionFactory; @Autowired @Qualifier("jmsCacheReplicationTopic") private Topic replicationTopic; @Autowired @Qualifier("jmsCacheGetQueue") private Queue getQueue; private TopicConnection replicationTopicConnection; private QueueConnection getQueueConnection; @Override public CacheManagerPeerProvider createCachePeerProvider( CacheManager cacheManager, Properties properties) { String username = properties.getProperty(JMSUtil.USERNAME); String password = properties.getProperty(JMSUtil.PASSWORD); AcknowledgementMode mode = AcknowledgementMode.forString(properties .getProperty(JMSUtil.ACKNOWLEDGEMENT_MODE)); boolean listenToTopic = Boolean.valueOf(properties .getProperty(JMSUtil.LISTEN_TO_TOPIC)); try { // this fails with a NPE since topicConnectionFactory was not wired replicationTopicConnection = topicConnectionFactory.createTopicConnection(username, password); getQueueConnection = queueConnectionFactory.createQueueConnection(username, password); } catch (JMSException e) { throw new CacheException("Problem creating connections: " + e.getMessage(), e); } return new JMSCacheManagerPeerProvider(cacheManager, replicationTopicConnection, replicationTopic, getQueueConnection, getQueue, mode, listenToTopic); } }
Thierry


Reply With Quote