Spring AOP 可以靈活地切入目標層的方法,控制或者攔截目標方法的運行。本次通過這種機制,控制service層執行讀取數據庫資源的方法,實現緩存。
步驟:先從緩存區查找。如果緩存裏有則返回結果。若查詢不到,則去執行原方法去數據庫中查詢對應的數據,並將加載出的數據存入緩存區。如果是增、刪、改的操作,先清除緩存裏的數據,然後與數據庫交互
注意:此實例未連接數據庫
實例
實體類
package com.ss.model;
/**
* <p>Title: User</p>
* <p>Description: User實體</p>
* @author Jack.Hu
* <p> @date 2018年11月18日</p>
*/
public class User implements Serializable {
private Long u_id;
private String u_name;
private String u_sex;
public User(Long u_id, String u_name, String u_sex) {
this.u_id = u_id;
this.u_name = u_name;
this.u_sex = u_sex;
}
public User() {
}
@Override
public String toString() {
return "User [u_id=" + u_id + ", u_name=" + u_name + ", u_sex=" + u_sex + "]";
}
public Long getU_id() {
return u_id;
}
public void setU_id(Long u_id) {
this.u_id = u_id;
}
public String getU_name() {
return u_name;
}
public void setU_name(String u_name) {
this.u_name = u_name;
}
public String getU_sex() {
return u_sex;
}
public void setU_sex(String u_sex) {
this.u_sex = u_sex;
}
}
aop配置文件
<?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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd" default-autowire="byType">
<context:component-scan base-package="com.ss"/>
<!-- 自動代理 -->
<aop:aspectj-autoproxy/>
<!-- 註冊需要被橫切的類 -->
<bean id="userService" class="com.ss.service.UserServiceImpl"/>
<!-- 註冊切面類 -->
<bean id="userAspect" class="com.ss.aop.Aspect"/>
<aop:config>
<aop:aspect id="myAspect" ref="userAspect">
<aop:pointcut expression="execution(public * com.ss.service..*.*(..))" id="aspect"/>
<aop:before method="before" pointcut-ref="aspect"/>
<aop:after method="after" pointcut-ref="aspect"/>
<aop:around method="around" pointcut-ref="aspect"/>
<aop:after-returning method="returning" pointcut-ref="aspect"/>
<aop:after-throwing method="throwing" pointcut-ref="aspect"/>
</aop:aspect>
</aop:config>
</beans>
aop切面類
package com.ss.aop;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import com.ss.model.User;
/**
*
* <p>Title: Aspect</p>
* <p>Description: 切面類</p>
* @author Jack.Hu
* <p> @date 2018年11月18日</p>
*/
public class Aspect {
// 緩存
private Map<Integer, User> cache = new HashMap<Integer, User>();
public void before (JoinPoint jp) {
System.out.println("before:" + jp.getSignature());
}
public void after (JoinPoint jp) {
System.out.println("after:" + jp.getSignature());
}
public void returning (JoinPoint jp) {
System.out.println("returning:" + jp.getSignature());
}
public void throwing (JoinPoint jp) {
System.out.println("throwing:" + jp.getSignature());
}
public Object around (ProceedingJoinPoint pj) {
String name = pj.getSignature().getName();
Object[] param = pj.getArgs();
if(name.equals("selectUser")){
if(null != cache.get(param[0])){
return cache.get(param[0]);
}else{
try {
User user = (User) pj.proceed(pj.getArgs());
cache.put((Integer)param[0], user);
return cache.get(param[0]);
} catch (Throwable e) {
e.printStackTrace();
}
}
}else{
try {
cache.clear(); // 清空緩存
Object proceed = pj.proceed(pj.getArgs());
return proceed;
} catch (Throwable e) {
e.printStackTrace();
}
}
return null;
}
}
dao包接口
package com.ss.dao;
import com.ss.model.User;
/**
*
* <p>Title: IUserDao</p>
* <p>Description: UserDao接口</p>
* @author Jack.Hu
* <p> @date 2018年11月18日</p>
*/
public interface IUserDao {
public User selectUser(Long userId);
}
dao包實現類
package com.ss.dao;
import java.util.HashMap;
import java.util.Map;
import com.ss.model.User;
/**
*
* <p>Title: UserDaoImpl</p>
* <p>Description: UserDao包實現類</p>
* @author Jack.Hu
* <p> @date 2018年11月18日</p>
*/
public class UserDaoImpl implements IUserDao{
// 模擬數據庫的數據
private final static Map<Long, User> users = new HashMap<Long, User>();
static {
users.put(12L, new User("張三",12L)); // 簡單寫兩條數據
users.put(23L, new User("李四",23L));
}
@Override
public User selectUser(Long userId) {
System.out.println(userId + " selectUser method successful operation。。。。。。。");
return users.get(userId);
}
}
service層接口
package com.ss.service;
import org.springframework.stereotype.Service;
/**
*
* <p>Title: IUserService</p>
* <p>Description: UserService接口</p>
* @author Jack.Hu
* <p> @date 2018年11月18日</p>
*/
import com.ss.model.User;
public interface IUserService {
User selectUser(Long userId);
}
service層實現類/需要被橫切
package com.ss.service;
import com.ss.dao.IUserDao;
import com.ss.dao.UserDaoImpl;
import com.ss.model.User;
/**
*
* <p>Title: UserServiceImpl</p>
* <p>Description: UserService實現類</p>
* @author Jack.Hu
* <p> @date 2018年11月18日</p>
*/
public class UserServiceImpl implements IUserService {
private IUserDao userDao = new UserDaoImpl();
@Override
public User selectUser(Long userId) {
return userDao.selectUser(userId);
}
}
測試類
package com.ss.testCache;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ss.model.User;
public class TestUser {
@Test
public void test(){
// 加載配置文件
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aopAspect.xml");
IUserService service = context.getBean(IUserService.class);
// 查詢兩條相同的數據
User user = service.selectUser(12L);
User user1 = service.selectUser(12L);
System.out.println(user);
System.out.println(user1);
// 判斷兩個對象地址,如果返回true代表緩存起到作用
System.out.println(user == user1); // 返回爲true
}
}