很多时候我们程序要查询的数据量太大了,无论怎么进行SQL优化,查询的时间仍可能达到数秒,这个时候对于用户的体验就是非常不好的,这个时候我们就可以采用预加载的方法,在Web容器启动时加载相应的数据查询方法,将得到的数据放入缓存,这样当用户来请求数据的时候,我们就可以将缓存中的数据返回给用户,从而提高用户体验。
实现InitializingBean接口是实现Spring预加载的采用手段,实现流程:
-
创建一个bean(注:InitializingBean接口是基于bean实现的),实现InitializingBean接口,重写afterPropertiesSet方法:
public class DemoCache implements InitializingBean { public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub } }
这里,afterPropertiesSet方法是Web容器启动会执行的方法,所以我们就可以在该方法内写入我们的初始化方法内容。
-
加入初始化方法:
public class DemoCache implements InitializingBean { public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub //写入想要随容器启动的查询语句 } }
-
注入bean到容器中:
由于InitializingBean接口是基于bean实现的,所以我们编写的bean要注入到Spring容器中,这样我们重写的afterPropertiesSet方法就会被Spring容器扫描并执行:<?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:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="demoCache" class="com.gaotime.info.product.web.cache.DemoCache"/> </beans>
这样我们的初始化方法就会被执行了,但是这样仅仅只是执行了一遍,下次用户来请求的时候仍然要执行查询方法,这样我们的查询貌似就没有任何意义了呀,所以我们需要将我们得到的结果存入到缓存中,当用户下次来请求时,就可以直接访问缓存中的数据,提升用户体验:
-
方法一:直接在afterPropertiesSet方法内将得到的结果集存入缓存,这里就仅提供思路了,并不累赘多余的代码。
-
方法二:当我们要初始化的类太多,每一个afterPropertiesSet方法都需要写一遍存入缓存的语句太麻烦,这个时候我们就可以用到AOP的后置通知处理了。
Spring AOP应用实例 -
方法三:xml配置拦截,实际上原理和aop是一样的:
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:/cache/ehcache.xml" /> <!-- cacheManager工厂类,指定ehcache.xml的位置 --> <bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:configLocation="classpath:/cache/ehcache.xml" /> <!-- 声明cacheManager --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cacheManager-ref="cacheManagerFactory" /> <bean id="lowFreCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> <property name="cacheManager" ref="cacheManagerFactory" /> <property name="cacheName" value="lowFreCache" /> </bean> <bean id="lowFreMethodCacheInterceptor" class="com.gaotime.info.product.web.util.MethodCacheInterceptor"> <property name="cache" ref="lowFreCache"/> </bean> <bean id="lowFreMethodCachePointCut" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="advice" ref="lowFreMethodCacheInterceptor" /> <property name="patterns"> <list> <value>com.lr.service.impl.DemoServiceImpl\.getCount</value> <!--拦截的方法 --> </list> </property> </bean>
注:这里用的ehcache。
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" monitoring="autodetect"> <!-- On Windows: java.io.tmpdir:[C:\DOCUME~1\joshua\LOCALS~1\Temp\] On Solaris: java.io.tmpdir:[/var/tmp/] On Linux: java.io.tmpdir: [/tmp] On Mac OS X: java.io.tmpdir: [/tmp] <diskStore path="d:/cache"/>--> <!--使用该标签可以将数据存储至磁盘 --> <diskStore path="java.io.tmpdir/ehcache" /> <!-- 定义缓存时间--> <cache name="lowFreCache" maxElementsInMemory="100000" maxElementsOnDisk="500000" eternal="false" overflowToDisk="true" diskPersistent="false" diskSpoolBufferSizeMB="30" timeToIdleSeconds="900" timeToLiveSeconds="900" memoryStoreEvictionPolicy="LFU" /> </ehcache>