0

I am using Apache Ignite 2.3 with cassandra 2.1.9 as my persistence layer. I am using cacheStoreFactory class which saves and gets data from the db. I am auto-wiring some dependencies in this class but it is coming as null.

here is my sample ignite confifuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       ">
    <description>Main Spring file for ignite configuration.</description>

    <bean id="cacheIgniteBean" class="org.apache.ignite.IgniteSpringBean">
        <property name="configuration">
            <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
                <property name="dataStorageConfiguration">
                    <bean class="org.apache.ignite.configuration.DataStorageConfiguration">
                        <property name="dataRegionConfigurations">
                            <list>
                                <!--
                                    Defining a data region that will consume up to 2 GB of RAM.
                                -->
                                <bean class="org.apache.ignite.configuration.DataRegionConfiguration">
                                    <!-- Custom region name. -->
                                    <property name="name" value="2GB_Region"/>

                                    <!-- 500 MB initial size (RAM). -->
                                    <property name="initialSize" value="#{500L * 1024 * 1024}"/>

                                    <!-- 2 GB maximum size (RAM). -->
                                    <property name="maxSize" value="#{2L * 1024 * 1024 * 1024}"/>

                                    <!-- Enabling RANDOM_LRU eviction for this region.  -->
                                    <property name="pageEvictionMode" value="RANDOM_LRU"/>
                                </bean>
                            </list>
                        </property>
                    </bean>
                </property>
                <property name="cacheConfiguration">
                    <list>
                        <bean class="org.apache.ignite.configuration.CacheConfiguration">

                            <property name="name" value="item"/>
                            <property name="cacheMode" value="PARTITIONED"/>
                            <property name="atomicityMode" value="ATOMIC"/>
                            <property name="backups" value="0"/>
                            <property name="cacheStoreFactory">
                                <bean class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
                                    <constructor-arg value="com.tgt.gom.cacheserver.store.ItemCacheStore"/>
                                </bean>

                            </property>

                            <property name="readThrough" value="${ignite.config.cache.item.readThrough}"/>
                            <property name="writeThrough" value="${ignite.config.cache.item.writeThrough}"/>
                            <property name="writeBehindEnabled" value="${ignite.config.cache.item.writeBehindEnabled}"/>
                            <property name="writeBehindFlushSize"
                                      value="${ignite.config.cache.item.writeBehindFlushSize}"/>
                            <property name="writeBehindFlushFrequency"
                                      value="${ignite.config.cache.item.writeBehindFlushFrequency}"/>
                            <property name="writeBehindFlushThreadCount"
                                      value="${ignite.config.cache.item.writeBehindFlushThreadCount}"/>
                            <property name="writeBehindBatchSize"
                                      value="${ignite.config.cache.item.writeBehindBatchSize}"/>
                        </bean>

                        <bean class="org.apache.ignite.configuration.CacheConfiguration">

                            <property name="name" value="location"/>
                            <property name="cacheMode" value="PARTITIONED"/>
                            <property name="atomicityMode" value="ATOMIC"/>
                            <property name="backups" value="0"/>
                            <property name="cacheStoreFactory">
                                <bean class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
                                    <constructor-arg value="com.tgt.gom.cacheserver.store.LocationCacheStore"/>
                                </bean>
                            </property>
                            <property name="readThrough" value="${ignite.config.cache.item.readThrough}"/>
                            <property name="writeThrough" value="${ignite.config.cache.item.writeThrough}"/>
                            <property name="writeBehindEnabled" value="${ignite.config.cache.item.writeBehindEnabled}"/>
                            <property name="writeBehindFlushSize"
                                      value="${ignite.config.cache.item.writeBehindFlushSize}"/>
                            <property name="writeBehindFlushFrequency"
                                      value="${ignite.config.cache.item.writeBehindFlushFrequency}"/>
                            <property name="writeBehindFlushThreadCount"
                                      value="${ignite.config.cache.item.writeBehindFlushThreadCount}"/>
                            <property name="writeBehindBatchSize"
                                      value="${ignite.config.cache.item.writeBehindBatchSize}"/>
                        </bean>

                    </list>
                </property>

                <!--<property name="includeEventTypes">
                    <util:constant static-field="org.apache.ignite.events.EventType.EVTS_TASK_EXECUTION"/>
                </property>-->
                <property name="failureDetectionTimeout" value="5000"/>
                <property name="discoverySpi">
                    <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
                        <property name="ipFinder">
                            <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
                                <!-- <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder"> -->
                                <property name="addresses">
                                    <list>
                                        <value>127.0.0.1:47500..47509</value>
                                    </list>
                                </property>
                            </bean>
                        </property>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>

Here is my ItemCacheStore class code:

@Slf4j
@Service
public class ItemCacheStore extends CacheStoreAdapter<String, ItemV1DTO> implements Serializable {
    private static final long serialVersionUID = 1L;


    @Autowired
    private ItemRepository itemRepository;

    @Autowired
    private ItemCacheStoreAsync itemCacheStoreAsync;

    private static final String LOG_OP_INFO = "Item_Cache_Store";


    @Override
    public ItemV1DTO load(String item_id) throws CacheLoaderException {
        ItemV1DTO itemV1DTO = null;
        System.out.println("in item cache store ");

        try {
            ItemEntity itemEntity = itemRepository.findOne(item_id);
            if (itemEntity != null) {
                itemV1DTO = mapToItemDTO(itemEntity);
            }
        } catch (Exception e) {
            throw new CacheLoaderException("failed to load item data from cassandra" + e.getMessage());
        }
        return itemV1DTO;
    }
}

In ItemCacheStore class when the load method is called, the itemRepository field is null. However, when I autowire the same ItemRepository bean in another controller class, it works fine.

One more thing I noticed is that if I put one method with @PostConstruct annotation in the ItemCacheStore class then at that time I can see that dependency of ItemRepository got injected but when load method is called then it is again null.

g00glen00b
  • 41,995
  • 13
  • 95
  • 133

1 Answers1

0

The issue is the following configuration:

<property name="cacheStoreFactory">
    <bean class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
        <constructor-arg value="com.tgt.gom.cacheserver.store.ItemCacheStore"/>
    </bean>
</property>

You're creating a Spring bean of type FactoryBuilder and you pass the classname ItemCacheStore. What happens behind the screens is that the FactoryBuilder will create a new instance of ItemCacheStore. This new instance won't be managed by Spring, so all fields will be null.

So basically you'll end up with two instances of ItemCacheStore:

  • One created by the Spring container thanks to the @Service annotation. All autowired fields will work.
  • Another one create by the FactoryBuilder. It won't be managed by Spring and all autowired fields will be null.

To fix this, there are a few possibilities:

  1. Use a different factory or write your own that will use a Spring managed bean rather than creating a new one. According to the documentation, there is already a CassandraCacheStoreFactory.
  2. Use an AutowireHelper as mentioned in this answer, or use Springs SpringBeanAutowiringSupport to inject beans in a non-Spring managed bean.

Related: Why is my Spring @Autowired field null?

g00glen00b
  • 41,995
  • 13
  • 95
  • 133