spring-aop-2
1.Declaring Advice(通知)
通知类型:
before 目标方法执行前执行,前置通知
after 目标方法执行后执行,后置通知
after returning 目标方法返回时执行 ,后置返回通知
after throwing 目标方法抛出异常时执行 异常通知
around 在目标函数执行中执行,可控制目标函数是否执行,环绕通知
/** * 前置通知 * @param joinPoint 可以通过joinPoint获取目标对象的一些信息,比如:类名(Method),其中的参数等等 */ @Before(value = "execution(* cn.cg.target.IndexDao.*(..))") public void before(JoinPoint joinPoint){ //获取表达式+具体的方法全路径 System.out.println(joinPoint.toString()); System.out.println("前置通知"+ Arrays.toString(joinPoint.getArgs())); } /** * 环绕通知 */ @Around(value = "execution(* cn.cg.target.IndexDao.*(..))") public Object around(ProceedingJoinPoint pjp){ System.out.println("around-before"); Object res = null; try {
//目标方法执行 res = pjp.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("around-after"); return res; } /** * 方法return 前的通知 */ @AfterReturning(value = "execution(* cn.cg.target.IndexDao.*(..))",returning = "resObject") public void afterReturning(Object resObject){ System.out.println("方法返回通知"+resObject); } /** * 方法执行结束 * 类似于finally */ @After(value = "execution(* cn.cg.target.IndexDao.*(..))") public void after(){ System.out.println("后置通知"); } @AfterThrowing( value = "execution(* cn.cg.target.IndexDao.*(..))", throwing="ex") public void afterThrowing(Throwable ex) { System.out.println("抛出异常了"+ex.toString()); }
main:
public class MainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); Dao dao = (Dao) ac.getBean("indexDao"); System.out.println(dao.query("222", 2)); } }
console:
around-before
execution(String cn.cg.target.Dao.query(String,Integer))
前置通知[222, 2]
around-after
后置通知
方法返回通知2222
2222
执行顺序:
1.环绕通知 pjp.proccess()方法之前的代码 around
2.前置通知 before
3.pjp.proccess() 目标方法 target
4.环绕通知 pjp.proccess()方法之后的代码 around
5.后置通知 after
6.方法return 前的通知 AfterReturning
如果声明多个@Before通知对同一连接点进行增强,执行顺序为代码的声明顺序.
如果是两个不同的切面呢,切面实现Ordered接口,设置优先级
2.Aop简单应用场景
(1)性能监控
切面:
@Component @Aspect public class PerformanceMonitoringAspect { @Around("execution(* cn.cg.target.IndexDao.query(..))") public Object Around(ProceedingJoinPoint pjp) throws Throwable { //获取目标类名称 System.out.print(pjp.getTarget().getClass().getName()+","); //获取目标对象方法名 System.out.print(pjp.getSignature().getName()+","); //记录当前时间 SimpleDateFormat sim = new SimpleDateFormat("yyyy-MM-dd"); System.out.println(sim.format(new Date())); System.out.println("---------------方法执行-------------------"); long start = System.currentTimeMillis(); Object res = pjp.proceed(); //计算所需时间 Long end = System.currentTimeMillis(); System.out.println("---------------方法执行-------------------"); System.out.println("总用时"+(end-start)); return res; } }
main:
public class MainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class); Dao dao = (Dao) ac.getBean("indexDao"); for (int i = 0; i < 3; i++) { dao.query("222", 2); } } }
console:
cn.cg.target.IndexDao,query,2019-07-27 ---------------方法执行------------------- str+i操作进行中... ---------------方法执行------------------- 总用时1 cn.cg.target.IndexDao,query,2019-07-27 ---------------方法执行------------------- str+i操作进行中... ---------------方法执行------------------- 总用时5 cn.cg.target.IndexDao,query,2019-07-27 ---------------方法执行------------------- str+i操作进行中... ---------------方法执行------------------- 总用时3