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-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!--开启aAspectj注解自动代理对象 <aop:aspectj-autoproxy></aop:aspectj-autoproxy> -->
<!-- 目标对象 加入到IOC容器中进行管理 -->
<bean id="giftcardService"
class="com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl"></bean>
<!-- 切面对象 加入到IOC容器中进行管理 -->
<bean id="giftcardAspect" class="com.zghw.spring.demo.demo.aop.aspect.GiftcardAspect"></bean>
<!-- 配置AOP -->
<aop:config>
<!-- 定义切面 ref引用切面对象 -->
<aop:aspect ref="giftcardAspect">
<!-- 定义切点 -->
<!-- 表达式: execution(修饰符 返回类型 全类名.方法名(参数1类型,参数2类型,..)) and args(参数1名称,参数2名称)
id一定要设置,用来给通知使用 -->
<aop:pointcut
expression="execution(public * com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl.findByCardNo(String)) and args(cardNo)"
id="pointFindByCardNo" />
<!-- 前置通知 arg-names 要使用的参数名称,在切面前置方法中使用会得到目标方法相同参数名称传过来的参数值, 就可以使用目标参数值了,多个参数用逗号分开 -->
<aop:before method="findByCardNoCacheBefore" pointcut-ref="pointFindByCardNo"
arg-names="cardNo" />
<!-- 后置通知, returning 定义目标方法返回值的返回值名称,可以在定义的切面方法findByCardNoCache(GiftCard
retVal)中使用, -->
<aop:after-returning method="findByCardNoCache"
returning="retVal" arg-names="cardNo,retVal" pointcut-ref="pointFindByCardNo" />
<!-- 最终通知 -->
<aop:after method="findByCardNoCacheAfter"
pointcut="execution(* com.zghw.spring.demo.demo.aop.*.*.findByCardNo(..))" />
<!-- 环绕通知 缓存的使用 -->
<aop:around method="findByCardNoCacheAround" pointcut-ref="pointFindByCardNo"
arg-names="cardNo" />
<!--环绕通知 方法运行时间的测量 -->
<aop:around method="saveTime"
pointcut="execution(* com.zghw.spring.demo.demo.aop.*.*.save(com.zghw.spring.demo.demo.aop.pojo.Giftcard)) and args(giftcard)"
arg-names="giftcard" />
</aop:aspect>
</aop:config>
</beans>
1.目标源
package com.zghw.spring.demo.demo.aop.pojo;
public class Giftcard {
private String name;
private String cardNo;
private double price;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Giftcard [name=" + name + ", cardNo=" + cardNo + ", price="
+ price + ", description=" + description + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((cardNo == null) ? 0 : cardNo.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Giftcard other = (Giftcard) obj;
if (cardNo == null) {
if (other.cardNo != null)
return false;
}
return true;
}
}
接口
package com.zghw.spring.demo.demo.aop.service;
import com.zghw.spring.demo.demo.aop.pojo.Giftcard;
public interface GiftcardService {
public void save(Giftcard giftcard);
public Giftcard findByCardNo(String cardNo);
public Giftcard update(Giftcard giftcard);
}
实现类
package com.zghw.spring.demo.demo.aop.service.impl;
import java.util.HashMap;
import java.util.Map;
import com.zghw.spring.demo.demo.aop.pojo.Giftcard;
import com.zghw.spring.demo.demo.aop.service.GiftcardService;
public class GiftcardServiceImpl implements GiftcardService {
private final Map<String, Giftcard> giftcards = new HashMap<String, Giftcard>();
public void save(Giftcard giftcard) {
System.out.println("开始保存对象。。。。");
giftcards.put(giftcard.getCardNo(), giftcard);
try {
//模拟一下时间
Thread.sleep((int)(Math.random()*100));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
System.out.println("保存完成");
}
public Giftcard findByCardNo(String cardNo) {
Giftcard giftcard = giftcards.get(cardNo);
System.out.println("执行目标方法:findByCardNo");
return giftcard;
}
public Giftcard update(Giftcard giftcard) {
Giftcard card = giftcards.put(giftcard.getCardNo(), giftcard);
return card;
}
}
2.切面
package com.zghw.spring.demo.demo.aop.aspect;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import com.zghw.spring.demo.demo.aop.pojo.Giftcard;
import com.zghw.spring.demo.demo.aop.service.GiftcardService;
/**
* 定义切面
*
* @author zghw
*
*/
public class GiftcardAspect {
// 用来缓存查询到的giftCard
private final Map<String, Object> cardCache = new HashMap<String, Object>();
/**
* 前置通知
* @param cardNo
*/
public void findByCardNoCacheBefore(String cardNo){
System.out.println("前置通知:开始尝试从缓存中取:"+cardNo);
if (cardCache.containsKey(cardNo)) {
System.out.println("存在缓存中"+cardNo);
}else{
System.out.println("不存在缓存中"+cardNo);
}
}
/**
* 在findByCardNo加入缓存
*/
public Giftcard findByCardNoCache(String cardNo,Giftcard retVal) {
if (!cardCache.containsKey(cardNo)) {
System.out.println("后置通知:不存在就加入缓存中"+cardNo);
cardCache.put(retVal.getCardNo(), retVal);
}
return retVal;
}
/**
* JoinPoint可以在任何通知方法中作为第一个参数使用,可以用来访问加入点的很多信息。
*
* @param joinPoint
*/
public void findByCardNoCacheAfter(JoinPoint joinPoint){
System.out.println("最后通知,已经完成。");
System.out.println("来看看这个对象JoinPoint有什么作用");
Object target = joinPoint.getTarget();
System.out.println("目标对象:"+target);
System.out.println("目标对象类型:"+target.getClass());
if(target instanceof GiftcardService){
GiftcardService gs=(GiftcardService)target;
//使用目标类型调用其他方法
System.out.println(gs.findByCardNo("2222222"));
}
Object[] args=joinPoint.getArgs();
System.out.println("参数:长度"+args.length);
int i=0;
for(Object arg:args){
System.out.println("参数"+(++i)+" :类型"+arg.getClass());
}
Object proxy = joinPoint.getThis();
System.out.println("这个得到代理对象 "+proxy);
System.out.println("得到代理对象类型 "+proxy.getClass());
System.out.println("从这里可以看出来它代理的是GiftcardService == "+(proxy instanceof GiftcardService));
System.out.println("方法签名:"+joinPoint.getSignature());
System.out.println(joinPoint.getSourceLocation());
System.out.println(joinPoint.getKind());
System.out.println(joinPoint.getStaticPart().toShortString());
}
/**
* 前置通知和后置通知不再一起很难控制目标对象调用方法,
* 比如前置方法判断出了该对象在缓存中,能够取得值而不能返回值缓存中的对象。
* 后置方法虽然能够返回值,但是不能够在目标方法调用前返回值。
* 使用环绕通知就很好的解决问题。
* 环绕通知
* @param giftcard
* @throws Throwable
*/
public Giftcard findByCardNoCacheAround(ProceedingJoinPoint pjp,String cardNo) throws Throwable{
Giftcard card=null;
System.out.println("Around:前置通知:开始尝试从缓存中取:"+cardNo);
if (cardCache.containsKey(cardNo)) {
System.out.println("Around:存在缓存中"+cardNo);
//如果缓存中存在就不需要从目标对象中取
return (Giftcard) cardCache.get(cardNo);
}
card =(Giftcard)pjp.proceed();//通过一个个通知方法拦截器链得到返回的对象。
if (!cardCache.containsKey(card.getCardNo())) {
System.out.println("Around:后置通知:不存在就加入缓存中"+cardNo);
cardCache.put(card.getCardNo(), card);
}
return card;
}
/**
* 用来测试一个方法的执行时间
* @param pjp
* @param giftcard
*/
public void saveTime(ProceedingJoinPoint pjp,Giftcard giftcard){
StopWatch sw =new StopWatch();
sw.start(giftcard.getDescription());
try {
pjp.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
sw.stop();
System.out.println(sw.prettyPrint());
}
}
3.测试
package com.zghw.spring.demo.demo.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zghw.spring.demo.demo.aop.pojo.Giftcard;
import com.zghw.spring.demo.demo.aop.service.GiftcardService;
public class ApplicationXml {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"application-aop.xml");
GiftcardService giftcardService = (GiftcardService) ctx
.getBean("giftcardService");
//模拟添加数据到数据库中
Giftcard card = new Giftcard();
card.setCardNo("11111111");
card.setDescription("第一个对象");
card.setName("zghw");
card.setPrice(1322546.45);
//模拟保存对象到数据库中
giftcardService.save(card);
Giftcard card2 = new Giftcard();
card2.setCardNo("2222222");
card2.setDescription("第二个对象");
card2.setName("dfsdf");
card2.setPrice(467732346.45);
//模拟保存对象到数据库中
giftcardService.save(card2);
//模拟先从缓存中取去不到就去数据库中取值
System.out.println("=======第一次==========");
giftcardService.findByCardNo("11111111");
System.out.println("=========第二次========");
giftcardService.findByCardNo("11111111");
System.out.println("=========第三次========");
giftcardService.findByCardNo("11111111");
}
}
4.输出
Mar 28, 2016 10:38:41 AM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@57d62a85: startup date [Mon Mar 28 10:38:41 CST 2016]; root of context hierarchy
Mar 28, 2016 10:38:41 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [application-aop.xml]
开始保存对象。。。。
保存完成
StopWatch '': running time (millis) = 14
-----------------------------------------
ms % Task name
-----------------------------------------
00014 100% 第一个对象
开始保存对象。。。。
保存完成
StopWatch '': running time (millis) = 53
-----------------------------------------
ms % Task name
-----------------------------------------
00053 100% 第二个对象
=======第一次==========
前置通知:开始尝试从缓存中取:11111111
不存在缓存中11111111
Around:前置通知:开始尝试从缓存中取:11111111
执行目标方法:findByCardNo
Around:后置通知:不存在就加入缓存中11111111
最后通知,已经完成。
来看看这个对象JoinPoint有什么作用
目标对象:com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@3515a84b
目标对象类型:class com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl
执行目标方法:findByCardNo
Giftcard [name=dfsdf, cardNo=2222222, price=4.6773234645E8, description=第二个对象]
参数:长度1
参数1 :类型class java.lang.String
这个得到代理对象 com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@3515a84b
得到代理对象类型 class com.sun.proxy.$Proxy2
从这里可以看出来它代理的是GiftcardService == true
方法签名:Giftcard com.zghw.spring.demo.demo.aop.service.GiftcardService.findByCardNo(String)
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@6a915c8c
method-execution
execution(GiftcardService.findByCardNo(..))
=========第二次========
前置通知:开始尝试从缓存中取:11111111
存在缓存中11111111
Around:前置通知:开始尝试从缓存中取:11111111
Around:存在缓存中11111111
最后通知,已经完成。
来看看这个对象JoinPoint有什么作用
目标对象:com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@3515a84b
目标对象类型:class com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl
执行目标方法:findByCardNo
Giftcard [name=dfsdf, cardNo=2222222, price=4.6773234645E8, description=第二个对象]
参数:长度1
参数1 :类型class java.lang.String
这个得到代理对象 com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@3515a84b
得到代理对象类型 class com.sun.proxy.$Proxy2
从这里可以看出来它代理的是GiftcardService == true
方法签名:Giftcard com.zghw.spring.demo.demo.aop.service.GiftcardService.findByCardNo(String)
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@6d5321fc
method-execution
execution(GiftcardService.findByCardNo(..))
=========第三次========
前置通知:开始尝试从缓存中取:11111111
存在缓存中11111111
Around:前置通知:开始尝试从缓存中取:11111111
Around:存在缓存中11111111
最后通知,已经完成。
来看看这个对象JoinPoint有什么作用
目标对象:com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@3515a84b
目标对象类型:class com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl
执行目标方法:findByCardNo
Giftcard [name=dfsdf, cardNo=2222222, price=4.6773234645E8, description=第二个对象]
参数:长度1
参数1 :类型class java.lang.String
这个得到代理对象 com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@3515a84b
得到代理对象类型 class com.sun.proxy.$Proxy2
从这里可以看出来它代理的是GiftcardService == true
方法签名:Giftcard com.zghw.spring.demo.demo.aop.service.GiftcardService.findByCardNo(String)
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@6cdc5f76
method-execution
execution(GiftcardService.findByCardNo(..))