用spring aop注解横切方式模拟缓存数据库资源

spring aop 可以灵活地切入目标层的方法,控制或者拦截目标方法的运行。本次通过这种机制,控制dao层读取数据库资源的方法,实现缓存。

实现目标:
查询:先从缓存区检索。若检索到则返回结果。若检索不到,则去数据库中加载数据,并将加载出的数据存入缓存区。
删除、修改、查询:与数据库交互,并且清除缓存。

具体实现:

  1. 实体类User
package com.ss.pojo;

public class User {
	private Long id;
	private String name;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + "]";
	}
	public User(Long id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public User() {
		super();
		// TODO Auto-generated constructor stub
	}
	
}

  1. 模拟的数据库接口。模拟一个数据库,有自带的增删改查的sql
package com.ss.db;

import com.ss.pojo.User;

public interface DBPr {
	void insert(User user);
	void delete(User user);
	void update(User user);
	User select(Long id);
}

  1. 模拟的数据库实现类
package com.ss.db;

import com.ss.pojo.User;

public class Mysql implements DBPr{
	// 模拟的数据库中存放的数据
	String[] users = {"大大","王五","呃呃","嘤嘤嘤","去去去","我是谁是谁","嘎嘎嘎","哈哈哈","冰冰冰","密密麻麻"};

	@Override
	public void insert(User user) {
		System.out.println("insert method in mysql invoted successfully");
	}

	@Override
	public void delete(User user) {
		System.out.println("delete method in mysql invoted successfully");		
	}

	@Override
	public void update(User user) {
		System.out.println("update method in mysql invoted successfully");		
	}

	@Override
	public User select(Long id) {
		System.out.println("select method in mysql invoted successfully");
		return new User(id, users[id.intValue()]) ;
	}
	
}

  1. dao层接口
package com.ss.dao;

import com.ss.pojo.User;

public interface IDao {
	void insert(User user);
	void delete(User user);
	void update(User user);
	User select(Long id);
}

  1. dao层实现类
package com.ss.dao;

import org.junit.Test;

import com.ss.db.DBPr;
import com.ss.db.Mysql;
import com.ss.pojo.User;
/**
 * 被切入的类
 * @author Administrator
 *
 */
public class Dao implements IDao{
	DBPr db = new Mysql();


	@Override
	public void insert(User user) {
		System.out.println("dao insert method invoked");
	}

	@Override
	public void delete(User user) {
		System.out.println("dao delete method invoked");
	}

	@Override
	public void update(User user) {
		System.out.println("dao update method invoked");
	}

	@Override
	public User select(Long id) {
		System.out.println("dao select method invoked");
		return db.select(id);
	}
	
}

  1. container.xml配置spring bean容器
<?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-4.3.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-4.3.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="com.ss" />
	
	<aop:aspectj-autoproxy />

	<!-- 注册需要被横切的类 -->
	<bean id="dao" class="com.ss.dao.Dao" />
	

</beans>
  1. aspect实现缓存
package com.ss.spring;

import java.util.HashMap;
import java.util.Map;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import com.ss.pojo.User;

/**
 * 切面类
 * @author Administrator
 *
 */
@Aspect
@Component
public class DaoAspect {
	/**
	 * 标记
	 */
	@Pointcut("execution(* com.ss.dao..*.*(..))")
	public void myPointcut(){}
	
	/**
	 * 缓存区
	 */
	private final Map<Long,User> cache = new HashMap<Long,User>();
	
	/**
	 * 切面方法。注意方法名对应
	 */
	
	
	@Around("myPointcut()")
	public Object aroundMe(ProceedingJoinPoint jp ){
		String method = jp.getSignature().getName();		  // 获取被切入的方法名
		Object[] args = jp.getArgs();						  // 获取传入的参数
		if(method.equals("select")){						  // 如果是查询方法
			User user = cache.get(args[0]);
			if(null != user){								  // 如果在缓存区检索到了
				System.out.println("get user from cache");
				return user;
			}else{
				try {
					System.out.println("else");
					user = (User) (jp.proceed(jp.getArgs())); // 如果在缓存区检索不到,执行原方法。
					cache.put(user.getId(), user);			  // 将检索结果存入缓存区
					System.out.println("put");
					return user;
				} catch (Throwable e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}else{
			cache.clear();									  // 如果是增、删、改方法,清空缓存区
			System.out.println("clear");
			try {
				return jp.proceed(jp.getArgs());			  // 执行原方法
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}
	
	
}

  1. 测试
package com.ss.service;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ss.dao.IDao;
import com.ss.pojo.User;
public class Service {
	@Test
	public void test(){
		// 初始化容器
		ApplicationContext ctx = new ClassPathXmlApplicationContext("container.xml");
		// 从容器中获取对象
		IDao dao = (IDao)ctx.getBean("dao");
		// 调用方法
		User user1 = dao.select(1L);				//第一次检索
		User user2 = dao.select(1L);				//第二次检索
		System.out.println(user1==user2);			//如果对象的地址相同,则说明第二次是从缓存区检索到的
		dao.update(user1);							//调用增删改方法。更新数据。
		User user3 = dao.select(1L);				//第三次检索
		System.out.println(user2==user3);			//如果不相同,则说明缓存已经被清空
	}
}

  1. 控制台输出结果
    在这里插入图片描述
    (o)/~
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值