用spring aop註解橫切方式模擬快取資料庫資源
阿新 • • 發佈:2018-12-22
spring aop 可以靈活地切入目標層的方法,控制或者攔截目標方法的執行。本次通過這種機制,控制dao層讀取資料庫資源的方法,實現快取。
實現目標:
查詢:先從快取區檢索。若檢索到則返回結果。若檢索不到,則去資料庫中載入資料,並將加載出的資料存入快取區。
刪除、修改、查詢:與資料庫互動,並且清除快取。
具體實現:
- 實體類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 } }
- 模擬的資料庫介面。模擬一個數據庫,有自帶的增刪改查的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);
}
- 模擬的資料庫實現類
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()]) ; } }
- 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);
}
- 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); } }
- 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>
- 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;
}
}
- 測試
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); //如果不相同,則說明快取已經被清空
}
}
- 控制檯輸出結果
(o)/~