参考地址:点击打开链接
实现思路参考原文,以下是对原文案例代码的补充:
项目结构:
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(); } }