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:
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>
Here is the com.example.cache.SpringJmsCacheManagerPeerProvide rFactory class:
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);
	}
}
Thanks in advance.

Thierry