项目使用缓存

       缓存对于提高项目的并发量作用巨大,但怎么更好地使用它,仁者见仁智者见智,没有什么方案是最好的,悠悠然然的一编博文《缓存相关代码的演变》写的较好,推荐一个:http://my.oschina.net/tinyframework/blog/322913,受此启发,我写了一个Maven插件利用javassist改写Class文件加入缓存部分代码来解决项目的缓存问题,这样也就使项目与缓存完全解藕。需要的朋友可以在:http://maven.oschina.net/content/repositories/thirdparty/cn/rjzjh/cache/下载并安装到本地使用,下面来介绍此Maven插件插件的用法。

  •       要使用此插件,添加插件依赖库: 

<repository>
			<id>oschina-third</id>
			<url>http://maven.oschina.net/content/repositories/thirdparty/</url>
</repository>

  • 在pom中加入

<build>
		<plugins>
			<!-- 加强缓存 -->
			<plugin>
				<groupId>cn.rjzjh</groupId>
				<artifactId>cache</artifactId>
				<executions>
					<execution>
						<id>encache</id>
						<phase>install</phase>
						<goals>
							<goal>addcache</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.eclipse.m2e</groupId>
					<artifactId>lifecycle-mapping</artifactId>
					<version>1.0.0</version>
					<configuration>
						<lifecycleMappingMetadata>
							<pluginExecutions>
								<pluginExecution>
									<pluginExecutionFilter>
										<groupId>cn.rjzjh</groupId>
										<artifactId>cache</artifactId>
										<versionRange>[1.0.0,)</versionRange>
										<goals>
											<goal>addcache</goal>
										</goals>
									</pluginExecutionFilter>
									<action>
										<ignore />
									</action>
								</pluginExecution>
							</pluginExecutions>
						</lifecycleMappingMetadata>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

其它  “pluginManagement”元素部分代码是因为maven的eclipse插件在覆盖“<phase>process-classes</phase>”等生命周期里会出现编译错误,如果只是覆盖“<phase>install</phase>”就可以直接这样:

                        <plugin>
				<groupId>cn.rjzjh</groupId>
				<artifactId>cache</artifactId>
				<version>1.0</version>
				<executions>
					<execution>
						<id>encache</id>
						<phase>install</phase>
						<goals>
							<goal>addcache</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

  • 第三步需要配置设置缓存的配置文件 ,缓存的配置文件会指示插件需要加入缓存的Java类和方法,可以通过配置插件的参数“config”来设置缓存的配置文件,如果没有配置插件的这个参数,插件会默认找项目编译后的输出目录下的cache.xml文件,插件的配置见:

        /**
	 * 需要加入缓存的配置文件 project.build.resources
	 *
	 * @parameter expression="${project.build.outputDirectory}/cache.xml"
	 * @required
	 */
	private File config;

  • 还需要定义插件来源Classpath路径,默认是项目编译后的输出目录。

       /**
	 * class产生的路径
	 *
	 * @parameter expression="${project.build.outputDirectory}"
	 * @required
	 */
	private String classroot;

  • 接下来是定义cache.xml文件,我写了一个像这样的:

<caches>
	<cache>
		<get classname="cn.rjzjh.tapestry.busi.tools.BusiAssit" staticname="findByRedis" />
		<put classname="cn.rjzjh.tapestry.busi.tools.BusiAssit" staticname="putRedis" />
		<method classname="cn.rjzjh.tapestry.busi.model.OptionItem" name="get" expire="100000" key="OptionItem%s"  idcol="id"/>
		<method classname="cn.rjzjh.tapestry.busi.service.impl.CommonServiceImpl" name="saveOptionItem" key="OptionItem%s"  idcol="id" param="saveobj"/>
	</cache>
</caches>

解释一下,“get、put”是指整个 cache区域要加入的用于获取缓存或是放置缓存的方法,它一定是一个静态方法,method就是指需要加入缓存的代码,里面有一些属性需要了解:

classname:要加强的方法所在的类

name:要加强的方法所在的方法名

expire:缓存有效期,可以不设

idcol:缓存对象的主键的属性名

key:缓存存储时的key,最后主键会是这个样子的 String.format(key,主键值);

param:如果要加强的方法是用来更新缓存的需要设置此属性,表示保存对象时传入的参数的参数名。

围观一下要加强的用于获取缓存对象的方法(仅供参考,实际项目需跟据实际情况做处理):

public final static <T extends Serializable> T findByRedis(Class clazz,
			Serializable key) {
		try {
			Jedis jedis = RedisClient.getConnection(SpringInit.conf);
			String jsonstr = jedis.get(String.valueOf(key));

			Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
					.create();
			T retobj = (T) gson.fromJson(jsonstr, clazz);
			RedisClient.returnResource(jedis);
			return retobj;
		} catch (Exception e) {
			logger.error("连联Redis异常", e);
		}
		return null;
	}

示例用的是谷歌的gson包,从缓存中取到json对象把它转为方法中要返回的对象。再看看用于放置缓存对象的方法的方法:

public final static <T extends Serializable> void putRedis(T obj,
			String key, Integer expire) {
		try {
			Jedis jedis = RedisClient.getConnection(SpringInit.conf);
			Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
					.create();
			String json = gson.toJson(obj);

			jedis.set(key, json);
			// jedis.append(key, json);
			if (expire != null) {
				jedis.expire(key, expire);
			}
			// jedis.hmset(key, hash)//放到Redis中
			RedisClient.returnResource(jedis);
		} catch (Exception e) {
			logger.error("连联Redis异常", e);
		}
	}

	public final static <T extends Serializable> void putRedis(T obj, String key) {
		putRedis(obj, key, null);
	}

把对象转为json对象保有存到redis缓存中。

看看Option的get方法长什么样:

public static final OptionItem get(String id) {
		OptionItem item = BusiAssit.findById(OptionItem.class, id);
		return item;
	}

这个方法很简单,BusiAssit.findById是我实现的一个工具类,就是Hibernate的通过id得到相关po,注意这里不用加入任何缓存代码。

再看看CommonServiceImpl类的saveOptionItem的方法长什么样:

public void saveOptionItem(OptionItem saveobj) {
		hbService.saveOrUpdate(saveobj);
	}

直接用hibernate的saveOrUpdate方法去保存对象,注意,这里不用加入任何缓存代码。

好了,一切准备就绪,看看结果吧,因为我们覆盖了生命周期中的install,那么我们在做 mvn install时就会自动把get/put所指定的缓存代码加入配置的方法中。如果暂时不想install,只想测试一下缓存代码,可以直接通过命令行的方式强制把  get/put指定的缓存代码 织入 我们指定的方法中:

192635_6vjd_1865914.jpg

不过要使用插件的短名称,还需要在maven的配置文件setting.xml加入如下片段:

 <pluginGroups>
     <pluginGroup>cn.rjzjh</pluginGroup>
  </pluginGroups>

我们用 ASM的二进制代码查看工具查看 OptionItem类的 get方法, 可以看到我们确实把缓存代码织入成功了

193122_CtOU_1865914.jpg

其中已加入了获取缓存方法:

mv.visitMethodInsn(INVOKESTATIC, "cn/rjzjh/tapestry/busi/tools/BusiAssit", "findByRedis", "(Ljava/lang/Class;Ljava/io/Serializable;)Ljava/io/Serializable;", false);

最后调用一下方法,我们能在Redis找到要找的缓存对象了。

193502_c5pK_1865914.jpg

缓存加强成功。




转载于:https://my.oschina.net/rjzjh/blog/351570

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值