Results 1 to 3 of 3

Thread: @Configurable wiring fails in afterPropertiesSet

  1. #1
    Join Date
    Feb 2008
    Posts
    2

    Default @Configurable wiring fails in afterPropertiesSet

    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

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,695

    Default

    You are still in bootstrapping your configuration and as such the @Configurable processing/detecting processors aren't active yet, so as such in that part of the container lifecycle @Configurable will not work.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3
    Join Date
    Feb 2008
    Posts
    2

    Default

    Quote Originally Posted by Marten Deinum View Post
    You are still in bootstrapping your configuration and as such the @Configurable processing/detecting processors aren't active yet, so as such in that part of the container lifecycle @Configurable will not work.
    I Marten,

    OK, this is what I feared. I also tried to put explicit depends-on attributes to see if it could solve it, to no avail...

    So how would you do it? I managed to have it working by having another InitializingBean injecting the JMS-related objects using static setters in a custom subclass of Ehcache JMS replication stuff. This is clearly an ugly hack and poses problems by itself, e.g. for testing.

    The problem is really that Ehcache initializes all its stuff eagerly. A solution would be to somehow delay the initialization, but that implies rewriting an EhcacheManagerFactoryBean and some other ehcache-specific classes. Well, I guess I will have to bite the bullet anyway.

    Thanks anyway.

    Thierry

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •