AOP Aspect Oriented Programming 面向切面编程,面向切面编程侧重点在于切面,在程序中寻找共通组件方法,然后将额外功能通过配置切入到组件方法中。
那么在这个过程种只需要搞清楚3个事情
一是切面(指的是在共通位置,加入的共通处理。封装共通处理的组件被称为切面组件)
二是切入点(Spring使用表达式指定切入的目标组件和方法。)其实切入点 就是用代码的形式 找到切面 ,具体的表达式如下
- 方法表达式
execution(修饰符? 返回类型 方法名(参数列表) throw异常?)
//匹配load打头方法并返回Object结果
execution(Object load*(..))
//匹配DeptController所有方法
execution(* cn.xdl.DeptController.*(..))
//匹配cn.xdl下所有类所有方法
execution(* cn.xdl.*.*(..))
- 类型表达式
within(组件类型)
//匹配DeptController所有方法
within(cn.xdl.DeptController)
//匹配cn.xdl包下所有类所有方法
within(cn.xdl.*)
//匹配cn.xdl包及子包中所有类所有方法
within(cn.xdl..*)
- bean名称表达式
bean(bean的name或id名)
//匹配id=deptController的组件及方法
bean(deptController)
//匹配id名以Controller结尾的组件及方法
bean(*Controller)
三是 通知(啥时候切,指定切入目标方法的时机,例如方法执行前、方法执行后,方法执行前和后、异常发生后等。)
具体如下
<aop:before> 前置通知,在原方法前面切入
<aop:after-returning> 后置通知,在原方法后面切入(出异常不会执行)
<aop:after> 最终通知,在原方法执行后切入(有无异常都可以执行)
<aop:after-throwing> 异常通知,在原方法抛出异常后切入
<aop:around> 环绕通知,在原方法前面和后面切入
那么在知道上述的3个要素以后就可以开始实现了
eg:记录每个服务调用相关信息,例如服务名、组件名、方法名、调用时间、执行时间(以这个列子来说明)
第一步编写一个切面组件
public class OperationAspectBean {
public Object logOperation(ProceedingJoinPoint pjp) throws Throwable{
//记录服务调用日志信息
String className = pjp.getTarget().getClass().getName();//组件名
String methodName = pjp.getSignature().getName();//方法名
String callTime = new Date().toString();//调用时间
StopWatch watch = new StopWatch();
watch.start();//开始计时
Object obj = pjp.proceed();//执行目标组件方法
watch.stop();//结束计时
long executeTime = watch.getTotalTimeMillis();//执行时长
//打印到控制台或写入数据库
System.out.println("执行了"+className+"组件的"+methodName
+"方法,调用时间为"+callTime+" 执行时长"+executeTime);
return obj;
}
}
第二步 把上述的3要素配置进去,并且加入ioc的扫描注入
@Component
@Aspect
public class OperationAspectBean {
@Around("within(cn.xdl.controller..*)")
public Object logOperation(ProceedingJoinPoint pjp) throws Throwable{
//记录服务调用日志信息
String className = pjp.getTarget().getClass().getName();//组件名
String methodName = pjp.getSignature().getName();//方法名
String callTime = new Date().toString();//调用时间
StopWatch watch = new StopWatch();
watch.start();//开始计时
Object obj = pjp.proceed();//执行目标组件方法
watch.stop();//结束计时
long executeTime = watch.getTotalTimeMillis();//执行时长
//打印到控制台或写入数据库
System.out.println("执行了"+className+"组件的"+methodName
+"方法,调用时间为"+callTime+" 执行时长"+executeTime);
return obj;
}
}
第三步:在xml加入配置
<!-- 开启组件扫描 -->
<context:component-scan base-package="cn.xdl.aspect"/>
<!-- 强制采用cglib技术动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
哈哈 我只能理解这么多 至于底层 和 Spring AOP原理:动态代理技术。实现分为JDK Proxy动态代理技术(反射)和CGLIB动态代理技术 这句话希望大家给我科普下