SpingAOP+redis实现缓存

参考地址:点击打开链接

实现思路参考原文,以下是对原文案例代码的补充:

项目结构:

application.xml

<?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"
    xmlns:aop="http://www.springframework.org/schema/aop"
    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-4.3.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
	
	<bean id="dao" class="dao.impl.UserDaoImpl"></bean>
	<bean id="service" class="service.impl.UserServiceImpl">
		<property name="dao" ref="dao"></property>
	</bean>
	<!-- 声明增强方法所在的Bean -->
	<bean id="theLogger" class="aop.UserServiceLogger"></bean>
	
	<!-- 开启注解扫描 -->
    <context:component-scan base-package="service,service.impl,dao"/>
    
    <!-- 开启aop注解方式,此步骤s不能少,这样java类中的aop注解才会生效 -->
    <aop:aspectj-autoproxy/>
    
    <aop:aspectj-autoproxy proxy-target-class="false" />
    
</beans>

UserDao

package dao;

import entity.User;

/**
 * 增加DAO接口,定义了所需的持久化方法
 */
public interface UserDao {
	public User select();
	public int update();
}


UserDaoImpl

package dao.impl;

import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Connection;

import dao.UserDao;
import entity.User;

/**
 * 用户DAO类,实现IDao接口,负责User类的持久化操作
 */
public class UserDaoImpl implements UserDao {

	private Statement st = null;
	private Connection conn = null;
	private ResultSet rs = null;

	public Statement lianjie(Connection conn, Statement st) {
		try {
			// 这里并未实现完整的数据库操作,仅为说明问题
			String URL = "jdbc:mysql://127.0.0.1:3306/example?useUnicode=true&characterEncoding=utf-8";
			String USER = "root";
			String PASSWORD = "yuwen";
			// 1.加载驱动程序
			Class.forName("com.mysql.jdbc.Driver");
			// 2.获得数据库链接
			conn = DriverManager.getConnection(URL, USER, PASSWORD);
			// 3.通过数据库的连接操作数据库,实现增删改查(使用Statement类)
			st = conn.createStatement();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return st;
	}

	public void close(Statement st, Connection conn, ResultSet rs) {
		try {
			if(null!=st){
				st.close();
			}
			if(null!=conn){
				conn.close();
			}
			if(null!=rs){
				rs.close();
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public User select() {
		User u = null;
		try {

			rs = lianjie(conn, st).executeQuery("select * from user where uId=1");
			// 4.处理数据库的返回结果(使用ResultSet类)

			while (rs.next()) {
				u = new User();
				u.setUsername(rs.getString("uName"));
				u.setPassword(rs.getString("uPass"));
			}

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		close(st, conn, rs);
		return u;
	}

	@Override
	public int update() {
		try {

			lianjie(conn, st).execute("update user set uPass='456' where uId=1");


		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		close(st, conn, rs);
		return 1;
	}
}


UserService

package service;

import entity.User;
import zhujie.RedisCache;
import zhujie.RedisEvict;

/**
 * 用户业务接口,定义了所需的业务方法
 */
public interface UserService {
	@RedisCache(type = User.class)
	public User select();

	@RedisEvict(type = User.class)
	public int update();
}

UserServiceImpl

package service.impl;

import service.UserService;

import dao.UserDao;
import entity.User;

/**
 * 用户业务类,实现对User功能的业务管理
 */
public class UserServiceImpl implements UserService {

	// 声明接口类型的引用,和具体实现类解耦合
	private UserDao dao;

	// dao 属性的setter访问器,会被Spring调用,实现设值注入
	public void setDao(UserDao dao) {
		this.dao = dao;
	}

	public User select() {
		return dao.select();
	}

	@Override
	public int update() {
		// TODO Auto-generated method stub
		return dao.update();
	}
}

User

package entity;

/**
 * 用户实体类
 */
public class User implements java.io.Serializable {
	private Integer id; // 用户ID
	private String username; // 用户名
	private String password; // 密码
	private String email; // 电子邮件

	// getter & setter
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

}

RedisCache

package zhujie;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface RedisCache {
    Class type();
}

RedisEvict

package zhujie;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RedisEvict {
    Class type();
}

UserServiceLogger

package aop;

import java.lang.reflect.Method;
import java.util.List;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import com.alibaba.fastjson.JSON;

import entity.User;
import redis.clients.jedis.Jedis;
import zhujie.RedisCache;
import zhujie.RedisEvict;

@Aspect
public class UserServiceLogger {

	public Jedis jed() {
		Jedis jedis = new Jedis("localhost");
		System.out.println("连接成功");
		return jedis;

	}

	public void close(Jedis jedis) {
		jedis.close();
	}

	@Around("execution(* service.impl..*.select*(..))")
	public Object around(ProceedingJoinPoint pjp) {
		try {
			// 连接本地的 Redis 服务
			Jedis jedis = jed();

			// 得到类名、方法名和参数
			String clazzName = pjp.getTarget().getClass().getName();
			String methodName = pjp.getSignature().getName();
			Object[] args = pjp.getArgs();
			// 根据类名,方法名和参数生成key
			String key = genKey(clazzName, methodName, args);
			// 得到被代理的方法
			Method me = ((MethodSignature) pjp.getSignature()).getMethod();
			// 得到被代理的方法上的注解
			Class modelType = me.getAnnotation(RedisCache.class).type();

			// 检查redis中是否有缓存
			String value = jedis.hget(User.class.getName(), key);
			System.out.println("value:" + value);
			// result是方法的最终返回结果
			Object result = null;
			if (null == value) {
				// 缓存未命中
				System.out.println("缓存未命中");

				// 调用数据库查询方法
				result = pjp.proceed(args);

				// 序列化查询结果
				String json = serialize(result);
				System.out.println("json:" + json);
				// 序列化结果放入缓存
				jedis.hset(User.class.getName(), key, json);
			} else {
				// 缓存命中
				System.out.println("缓存命中, value = " + value);
				// 得到被代理方法的返回值类型
				Class returnType = ((MethodSignature) pjp.getSignature()).getReturnType();
				// 反序列化从缓存中拿到的json
				result = deserialize(value, returnType, modelType);
			}
			close(jedis);
			return result;
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 在方法调用前清除缓存,然后调用业务方法
	 * 
	 * @param jp
	 * @return
	 * @throws Throwable
	 */
	@Around("execution(* service.impl..*.update*(..))")
	public Object evictCache(ProceedingJoinPoint jp) throws Throwable {
		// 得到被代理的方法
		Method me = ((MethodSignature) jp.getSignature()).getMethod();
		// 得到被代理的方法上的注解
		Class modelType = me.getAnnotation(RedisEvict.class).type();

		// if (infoLog.isDebugEnabled()) {
		// infoLog.debug("清空缓存:{}", modelType.getName());
		// }

		// 清除对应缓存
		// rt.delete(modelType.getName());
		System.out.println("开始删除缓存");
		Jedis jedis = jed();
		jedis.del(modelType.getName());
		System.out.println("删除缓存成功");
		return jp.proceed(jp.getArgs());
	}

	/**
	 * 根据类名、方法名和参数生成key
	 * 
	 * @param clazzName
	 * @param methodName
	 * @param args
	 *            方法参数
	 * @return
	 */
	protected String genKey(String clazzName, String methodName, Object[] args) {
		StringBuilder sb = new StringBuilder(clazzName);
		sb.append(methodName);

		for (Object obj : args) {
			sb.append(obj.toString());
		}
		return sb.toString();
	}

	/**
	 * 序列化
	 * 
	 * @param target
	 * @return
	 */
	protected String serialize(Object target) {
		return JSON.toJSONString(target);
	}

	/**
	 * 反序列化方法
	 * 
	 * @param jsonString
	 * @param clazz
	 * @param modelType
	 * @return
	 */
	protected Object deserialize(String jsonString, Class clazz, Class modelType) {
		// 序列化结果应该是List对象
		if (clazz.isAssignableFrom(List.class)) {
			return JSON.parseArray(jsonString, modelType);
		}
		// 序列化结果是普通对象
		return JSON.parseObject(jsonString, clazz);
	}
}


AopTest

package test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;
import entity.User;

public class AopTest {

	@Test
	public void aopTest() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("service");
		User user = new User();
		User lis = service.select();
		System.out.println(lis);

	}

	@Test
	public void aopTest2() {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserService service = (UserService) ctx.getBean("service");
		User user = new User();
		service.update();

	}

}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值