1.1 AOP简介
- 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
- AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
- AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
- 经典应用:事务管理、性能监视、安全检查、缓存 、日志等【画图】
- Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入
1.2Aspectj简介
- AspectJ是一个基于Java语言的AOP框架
- Spring2.0以后新增了对AspectJ切点表达式支持
- @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
- 新版本Spring框架,建议使用AspectJ方式来开发AOP
- 主要用途:自定义开发
首先明白一下概念,知道这是个什么玩意之后,在去敲代码,容易理解,编程不在于敲,在于理解!!!!
第一步 导入jar包
第二步,写XML 切记这几个命名空间一定到导
第三步 写Service 和实现类
最后 最重要的一个类 配置切面类
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.AfterThrowing;
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;
//1.配置bean 配置切面对象
//2.配置aop指定一个切面类
@Component
@Aspect
public class MyAspect {
//声明一个公共的切入点
@Pointcut("execution(* com.lq.service.impl.UserServiceImpl.*(..))")
public void myPointcut() {}
//3.声明前置通知
@Before("myPointcut()")
public void myBefore(JoinPoint jp) {
System.out.println("前置通知:"+jp.getSignature().getName());//连接点方法名
}
//4.声明后置通知
/**
* 后置通知获取service方法执行后的返回值
* @param jp
* @param retvalue service方法执行的返回值,如果写了返回值,需要在xml中配置returning
*/
@AfterReturning(pointcut = "myPointcut()",returning = "retvalue")
public void myAfterReturning(JoinPoint jp,Object retvalue) {
System.out.println("3.后置通知..." + jp.getSignature().getName());
System.out.println("返回值:" + retvalue);
}
//环绕通知
@Around("myPointcut()")
public Object myAround(ProceedingJoinPoint pjp) {
System.out.println("2.环绕通知...开启事务..." + pjp.getSignature().getName());
//放行
Object proceed=null;
try {
proceed = pjp.proceed();
System.out.println(proceed);
System.out.println("4.环绕通知....提交事务...");
} catch (Throwable e) {
e.printStackTrace();
System.out.println("异常消息"+e.getMessage());
System.out.println("回滚事务");
}
return proceed;
}
//异常通知
@AfterThrowing(pointcut = "myPointcut()",throwing = "e")
public void myAfterThrowing(JoinPoint jp,Throwable e) {
System.out.println("异常通知..."+jp.getSignature().getName());
}
//最终通知
@After("myPointcut()")
public void myAfter(JoinPoint jp){
System.out.println("最终通知..." + jp.getSignature().getName());
}
}
演示一下 怎么用 这里我故意抛出一个异常 你们就知道强大之处了。在ServieImpl实现类 加上一个算术异常
编写测试类
从下图中 我们很清晰看到 他首先先执行了环绕通知 后面执行了前置通知 然后打印了一句话 接着抛出了那个算术异常。在看看后面
从下图看出 他执行了环绕的回滚 所以发生异常 它就进行了回滚 所以这里就很形象展示了 为什么AOP有事务处理功效呢。接下来我们在重点看看 他们的执行顺序 这个是重点!!!!
AOP通知的一个执行顺序在下面,我们要牢记。
1.service方法有返回值 + 无异常 + XML
***************************************
1.前置通知...deleteUser
2.环绕通知...开启事务...deleteUser
通过id删除用户
3.后置通知...deleteUser
返回值:1
4.环绕通知....提交事务...
最终通知...deleteUser
**************************************
2.service方法有返回值 + 无异常 + 注解
**************************************
2.环绕通知...开启事务...deleteUser
1.前置通知...deleteUser
通过id删除用户
4.环绕通知....提交事务...
最终通知...deleteUser
3.后置通知...deleteUser
返回值:1
**************************************
3.service方法没有返回值 + 无异常 + XML
***************************************
1.前置通知...deleteUser
2.环绕通知...开启事务...deleteUser
删除用户。。。。
3.后置通知...deleteUser
返回值:null
4.环绕通知....提交事务...
最终通知...deleteUser
***************************************
4.service方法没有返回值 + 无异常 + 注解
****************************************
2.环绕通知...开启事务...deleteUser
1.前置通知...deleteUser
删除用户。。。。
4.环绕通知....提交事务...
最终通知...deleteUser
3.后置通知...deleteUser
返回值:null
***************************************
最后,双手奉献上 我研究的AOP web用法。
是的 你没有看错,当程序跑的时候,你发起请求,就能看到请求该方法路径 参数 IP地址等信息都可以被打印出来。
好了 开始总结 这么多注解 相信刚学的人 有点茫然了都。
@Aspect:声明切面,修饰切面类,从而获得 通知。
通知的注解:
@Before:前置
@AfterReturning:后置
@Around:环绕
@AfterThrowing:抛出异常
@After:最终
切入点注解:
@PointCut,修饰方法private void xxx(){} 之后通过“方法名”获取切入点引用 示例
//声明一个公共的切入点
@Pointcut("execution(* com.lq.service.impl.UserServiceImpl.*(..))")
public void myPointcut() {}
//3.声明前置通知
@Before("myPointcut()")
public void myBefore(JoinPoint jp) {
System.out.println("前置通知:"+jp.getSignature().getName());//连接点方法名
}
讲到这里,AOP算是结束了,算是被它搞死,,,我记得刚学时候一点都不喜欢AOP 直接三倍速度跳过,但是后面项目发现,用AOP地方挺多,而且发现这个玩意挺方便的,于是 又回头来深入学习一下。哈哈 虽然还是有一点点痛苦,但是 切面还是要切的、