Announcement Announcement Module
Collapse
No announcement yet.
@Configurable wiring fails in afterPropertiesSet Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • @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
    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.

    Comment


    • #3
      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

      Comment

      Working...
      X