1.切面
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.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; 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 org.springframework.util.StopWatch; import com.zghw.spring.demo.demo.aop.pojo.Giftcard; import com.zghw.spring.demo.demo.aop.service.GiftcardService; /** * 定义切面 * * @author zghw * */ @Aspect @Component public class GiftcardAspect { // 用来缓存查询到的giftCard private final Map<String, Object> cardCache = new HashMap<String, Object>(); @Pointcut("execution(public * com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl.findByCardNo(String)) && args(cardNo)") public void findByCardNo(String cardNo) { } /** * 前置通知 * * @param cardNo */ @Before(value = "findByCardNo(cardNo)") public void findByCardNoCacheBefore(String cardNo) { System.out.println("前置通知:开始尝试从缓存中取:" + cardNo); if (cardCache.containsKey(cardNo)) { System.out.println("存在缓存中" + cardNo); } else { System.out.println("不存在缓存中" + cardNo); } } /** * 在findByCardNo加入缓存 */ // @AfterReturning(pointcut="findByCardNo(cardNo)",returning="retVal") // 或者使用 @AfterReturning(value = "execution(public * com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl.findByCardNo(String)) && args(cardNo)", argNames = "cardNo,retVal", returning = "retVal") 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 */ @After(value = "execution(* com.zghw.spring.demo.demo.aop.*.*.findByCardNo(..))") 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 */ @Around(value = "findByCardNo(cardNo)") 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 */ @Around(value = "execution(* com.zghw.spring.demo.demo.aop.*.*.save(com.zghw.spring.demo.demo.aop.pojo.Giftcard)) and args(giftcard)", argNames = "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()); } }
2.目标类
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 org.springframework.stereotype.Component; import com.zghw.spring.demo.demo.aop.pojo.Giftcard; import com.zghw.spring.demo.demo.aop.service.GiftcardService; @Component("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; } }
3.测试类
package com.zghw.spring.demo.demo.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import com.zghw.spring.demo.demo.aop.pojo.Giftcard; import com.zghw.spring.demo.demo.aop.service.GiftcardService; @Configuration @ComponentScan //激活AspectJ进行自动代理 @EnableAspectJAutoProxy public class ApplicationAnnotation { public static void main(String[] args) { ApplicationContext ctx =new AnnotationConfigApplicationContext(ApplicationAnnotation.class); 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 11:37:24 AM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@3316f2e6: startup date [Mon Mar 28 11:37:24 CST 2016]; root of context hierarchy 开始保存对象。。。。 保存完成 StopWatch '': running time (millis) = 63 ----------------------------------------- ms % Task name ----------------------------------------- 00063 100% 第一个对象 开始保存对象。。。。 保存完成 StopWatch '': running time (millis) = 73 ----------------------------------------- ms % Task name ----------------------------------------- 00073 100% 第二个对象 =======第一次========== Around:前置通知:开始尝试从缓存中取:11111111 前置通知:开始尝试从缓存中取:11111111 不存在缓存中11111111 执行目标方法:findByCardNo Around:后置通知:不存在就加入缓存中11111111 最后通知,已经完成。 来看看这个对象JoinPoint有什么作用 目标对象:com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@62214c6f 目标对象类型: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@62214c6f 得到代理对象类型 class com.sun.proxy.$Proxy16 从这里可以看出来它代理的是GiftcardService == true 方法签名:Giftcard com.zghw.spring.demo.demo.aop.service.GiftcardService.findByCardNo(String) org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@36db33f6 method-execution execution(GiftcardService.findByCardNo(..)) =========第二次======== Around:前置通知:开始尝试从缓存中取:11111111 Around:存在缓存中11111111 最后通知,已经完成。 来看看这个对象JoinPoint有什么作用 目标对象:com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@62214c6f 目标对象类型: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@62214c6f 得到代理对象类型 class com.sun.proxy.$Proxy16 从这里可以看出来它代理的是GiftcardService == true 方法签名:Giftcard com.zghw.spring.demo.demo.aop.service.GiftcardService.findByCardNo(String) org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@7130779c method-execution execution(GiftcardService.findByCardNo(..)) =========第三次======== Around:前置通知:开始尝试从缓存中取:11111111 Around:存在缓存中11111111 最后通知,已经完成。 来看看这个对象JoinPoint有什么作用 目标对象:com.zghw.spring.demo.demo.aop.service.impl.GiftcardServiceImpl@62214c6f 目标对象类型: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@62214c6f 得到代理对象类型 class com.sun.proxy.$Proxy16 从这里可以看出来它代理的是GiftcardService == true 方法签名:Giftcard com.zghw.spring.demo.demo.aop.service.GiftcardService.findByCardNo(String) org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@24fcdcd2 method-execution execution(GiftcardService.findByCardNo(..))