Search code examples
javaspringcachingspring-annotationsapplicationcontext

Spring Caching proxy not applying to beans loaded in xml vs those loaded in @Configuration


Is there anyway to get beans loaded via <context:component-scan/> in a xml file to be proxy'ed by an @Coniguration annotated class which has @EnableCaching and declares the SimpleCacheManager? This would be the easiest route for the large applicaiton I'm working with, my ultimate preference would be to convert it all over to a Configuration class, but that is a lot more work and there are next to no unit tests for this application -.- , something would totally break. The other option is to declare the Cache's in the xml which works fine but I feel like is a step backwards.

NOTE: The <context:annotation-config/> is declared in a separate xml file 'integration.xml' I put it back in the applicationContext.xml but it didn't affect anything.

The declaration of the caches and the enabling of the caching via @EnableCaching was moved to the below java class some time ago and I don't think anyone noticed that it stopped working. So I would like to get it working again in the best way.

Application Context (edited for brevity)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:task="http://www.springframework.org/schema/task"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:cache="http://www.springframework.org/schema/cache"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
    "
        >

    <util:properties id="properties" location="classpath:config.properties"/>
    <context:property-placeholder properties-ref="properties"/>

    <!-- TODO: Replace this with MethodInvokingBean - we don't actually *want* a ConfigFactory instance -->
    <bean id="configFactory" class="net.adl.service.ConfigFactory">
        <property name="properties" ref="properties" />
    </bean>

    <!-- Enable Caching -->
    <cache:annotation-driven proxy-target-class="true"/>

    <!-- Declaring the cache manager and caches here works, but I feel is a step backwards to put them back in the XML config -->
    <context:component-scan base-package="
        net.adl.quartz,
        net.adl.config,
        net.adl.dao,
        net.adl.service,
        net.adl.audit,
        net.adl.diagnostic,
        net.adl.loader,
        net.adl.loader"/>


    <!-- add support for @Scheduled -->
    <task:scheduler id="taskScheduler" pool-size="10"/>
    <task:executor id="taskExecutor" pool-size="10"/>

    <!-- Used for real time monitoring of folders for data loads -->
    <task:executor id="realTimeAutoLoaderExecutor" pool-size="1"/>
    <task:annotation-driven scheduler="taskScheduler" executor="taskExecutor"/>

    <!-- enable @Transactional annotations -->
    <bean id="transactionAdvice" class="net.adl.aop.TransactionAdvice"/>
    <!--<bean id="profiler" class="net.adl.util.Profiler"/>-->

    <aop:aspectj-autoproxy proxy-target-class="true">
        <aop:include name="transactionAdvice"/>
        <!--<aop:include name="profiler"/>-->
    </aop:aspectj-autoproxy>

    <!-- set system properties -->
    <bean id="systemPrereqs" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <!--
            "systemProperties" is predefined; see:
            http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-beandef-xml-based
        -->
        <property name="targetObject" value="#{@systemProperties}"/>
        <property name="targetMethod" value="putAll"/>
        <property name="arguments">
            <util:properties>
                <prop key="net.sf.ehcache.skipUpdateCheck">true</prop>
                <prop key="org.terracotta.quartz.skipUpdateCheck">true</prop>
            </util:properties>
        </property>
    </bean>

    <!-- Exception translation bean post processor -->
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

    <bean id="versionInfo" class="net.adl.util.VersionInfo">
        <property name="versionFilePath" value="${labmatrix.home}/version-info.txt"/>
    </bean>

    <!-- Here is where we call in the <context:annotation-config/>, not sure why its done in a separate file -->
    <import resource="resources/spring/integration.xml"/>

</beans>

Integration.xml -- I think the idea is more deployment specific config options can go in this one

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
    "
>

    <context:annotation-config/>

</beans>

MethodCachingConfiguration Class

package net.adl.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.springframework.cache.support.NoOpCacheManager;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;

@Configuration
@EnableCaching
public class MethodCacheConfiguration {
    public static final String STUDY_CONFIG = "config.studies";
    public static final String ACCESS_CONFIG = "config.access";
    public static final String WORKFLOW_CONFIG = "config.workflows";
    public static final String PROCESS_CONFIG = "config.processes";
    public static final String QUERY_CONFIG = "config.queries";
    public static final String AUTOLOADER_CONFIG = "config.autoloader";
    public static final String LOCALIZATION = "localization";
    public static final String FACTORY_CONFIG = "config.factories";


    /**
     * Configures the cacheManager bean for @Cacheable annotation support
     */
    @Bean
    public CacheManager cacheManager() {
            SimpleCacheManager cacheManager = new SimpleCacheManager();

            cacheManager.setCaches(Arrays.asList(
                new ConcurrentMapCache(STUDY_CONFIG),
                new ConcurrentMapCache(ACCESS_CONFIG),
                new ConcurrentMapCache(WORKFLOW_CONFIG),
                new ConcurrentMapCache(PROCESS_CONFIG),
                new ConcurrentMapCache(QUERY_CONFIG),
                new ConcurrentMapCache(AUTOLOADER_CONFIG),
                new ConcurrentMapCache(LOCALIZATION),
                new ConcurrentMapCache(FACTORY_CONFIG)
            ));

            return cacheManager;
    }
}

EDIT: Fixed copy paste reformat typos


Solution

  • <cache:annotation-driven /> and @EnableCaching are equal you can have only one (maybe it can be source of your trouble) Can you provide example of code where you are actually using caching? Which bean should use cache feature.

    Answer provided by chalimartines