4.Spring AOP理解
- AOP原理
AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)、Authentication (权限)、Caching(缓存)和调试管理(Debugging)等。
从Spring的角度看,AOP最大的用途就在于提供了事务管理的能力。事务管理就是一个关注点,你的正事就是去访问数据库,而你不想管事务(太烦),所以,Spring在你访问数据库之前,自动帮你开启事务,当你访问数据库结束之后,自动帮你提交/回滚事务!
AOP概念术语
- 切面(aspect):用来切插业务方法的类。
- 连接点(joinpoint):是切面类和业务类的连接点,其实就是封装了业务方法的一些基本属性,作为通知的参数来解析,如方法的调用或特定的异常被抛出。
- 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
- 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
- 引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。
- 目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
- AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
AOP通知类型
- 前置通知(before advice):在切入点之前执行。
- 后置通知(after returning advice):在切入点执行完成后,执行通知。
- 环绕通知(around advice):包围切入点,调用方法前后完成自定义行为。
- 异常通知(after throwing advice):在切入点抛出异常后,执行通知。
AspectJ相关Jar包
aspectjrt.jar:主要是提供运行时的一些注解,静态方法等等东西,通常我们要使用aspectJ的时候都要使用这个包。
aspectjtools.jar:主要是提供赫赫有名的ajc编译器,可以在编译期将将java文件或者class文件或者aspect文件定义的切面织入到业务代码中。通常这个东西会被封装进各种IDE插件或者自动化插件中。
aspectjweaverjar:主要是提供了一个java agent用于在类加载期间织入切面(Load time weaving)。并且提供了对切面语法的相关处理等基础方法,供ajc使用或者供第三方开发使用。这个包一般我们不需要显式引用,除非需要使用LTW。
5.切面示例
@Aspect
@Component
public class ServiceLogAspect {
// 设置 Service层切点
@Pointcut("execution(* com.uaf.nlp.*.service.*.*.*(..))")
public void serviceAspect() {
}
/** * 异常通知 用于拦截service层记录异常日志 * @param joinPoint * @param e * 作者:will * 日期:2016年8月11日下午3:44:45 */
@AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
try {
String packageName = joinPoint.getTarget().getClass().getPackage().getName();
String className = joinPoint.getTarget().getClass().getName().substring(packageName.length() + 1) + ".java";
String methodName = joinPoint.getSignature().getName();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
Map<String, Object> map = new HashMap<String, Object>();
map.put("包名", packageName);
map.put("类名", className);
map.put("方法", methodName);
map.put("参数", joinPoint.getArgs());
map.put("异常信息", sw.toString());
MyLog4j.textError("[ASPECT]评分模型切面异常日志:{0}", JsonUtil.toJson(map));
} catch (Exception ex) {
// 记录本地异常日志
MyLog4j.textError("切面日志处理异常{0}", LogUtil.ExceptionToString(ex));
}
}
/** * 记录Service层请求参数及返回值 * @param joinPoint * @param result * 作者:will * 日期:2016年8月11日下午3:44:53 */
@AfterReturning(pointcut = "serviceAspect()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
try {
String packageName = joinPoint.getTarget().getClass().getPackage().getName();
String className = joinPoint.getTarget().getClass().getName().substring(packageName.length() + 1) + ".java";
String methodName = joinPoint.getSignature().getName();
Map<String, Object> map = new HashMap<String, Object>();
map.put("包名", packageName);
map.put("类名", className);
map.put("方法", methodName);
map.put("参数", joinPoint.getArgs());
map.put("返回值", result);
MyLog4j.textInfo("[ASPECT]评分模型切面请求及返回参数日志:{0}", JsonUtil.toJson(map));
} catch (Exception e) {
// 记录本地异常日志
MyLog4j.textError("切面日志处理异常{0}", LogUtil.ExceptionToString(e));
}
}
}
还没有评论,来说两句吧...