1. 程式人生 > >用spring aop註解橫切方式模擬快取資料庫資源

用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)/~