AOP简介:
在软件业,AOP为Aspect Oriented
Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP操作术语
Joinpoint(连接点):类里面可以被增强的方法,这些方法称为连接点。 Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。通知分为前置通知(在方法之前执行)、后置通知(在方法之后执行)、异常通知(方法出现异常)、最终通知(在后置之后执行)、环绕通知(在方法之前和之后执行)。想要计算方法的执行时间:在方法之前执行,在方法之后执行,两个相减即可得到执行的时间。运用的就是环绕通知。
Aspect(切面):是切入点和通知(引介)的结合。
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field。 Target(目标对象):代理的目标对象(要增强的类)。
Weaving(织入):是把增强应用到目标的过程。把advice 应用到 target的过程。
Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类。
动态代理
- JDK动态代理
JDK动态代理是通过java.lang.reflect.Proxy 类实现的,我们可以调用Proxy类的newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。
JDK的动态代理用起来非常简单,但是有局限性的,使用动态代理的对象必须实现一个或多个接口。 - CGLIB代理
CGLIB(Code Generation Library) 是一个高性能开源的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对子类进行增强。
Spring的通知类型
Spring中的AOP
AOP并不是Spring框架特有的,Spring只是支持AOP编程的框架之一,SpringAOP是一种基于方法拦截的AOP,在Spring中有四种方式去实现AOP的拦截功能。
1)使用 ProxyFactoryBean 和对应的接口实现AOP
2)使用 XML 配置 AOP
3)使用@AspectJ 注解驱动切面
4)使用AspectJ 注入切面
在Spring AOP的拦截方式中,真正常用的是用 @AspectJ 注解的方式实现的切面。
**
在Spring+SpringMVC+maven项目中使用@aspectJ添加切面
**
- 在pom.xml增加
2.在SpringMVC配置文件配置基于注解的aop
<!-- 开启基于注解的aop -->
<aop:aspectj-autoproxy/>
3.定义注解类
基于注解的声明式AspectJ
说明:这是在笔记本项目中使用,切入点在添加笔记本功能。
@Aspect
@Component
public class NoteBookCountAOP {
@Autowired
NoteBookService noteBookService;
@Pointcut("execution(* com.wzc.service.NoteBookService.addNoteBook(..))")
private void pointCut() {
}
@Before("pointCut()")
private void before(JoinPoint joinPoint) {
System.out.println("前置通知:"+joinPoint.getTarget());
System.out.println("前置通知:"+joinPoint.getSignature().getName());
}
@AfterReturning("pointCut()")
public void afterReterning(JoinPoint joinPoint) {
System.out.println("后置通知:"+joinPoint.getSignature().getName());
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("环绕通知开始");
//1、从数据库取出用户信息,判断该用户是否缴费用户
//是缴费用户,可以添加
//不是缴费用户,从数据库查询,该用户已经添加了多少个笔记本
//如果多于5个,不允许添加
//小于5个,允许添加
Object[] args=proceedingJoinPoint.getArgs();
NoteBookParam noteBookParam= new NoteBookParam();
noteBookParam.setUserId(((NoteBook)args[0]).getUserId());
int count=noteBookService.getCount(noteBookParam);
Object obj=null;
if(count<5) {
try {
obj=proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}else {
return -1;
}
}
@AfterThrowing(value="pointCut()",throwing="e")
public void countException(JoinPoint joinPoint,Throwable e) {
System.out.println("异常:"+e.getMessage());
}
@After("pointCut()")
public void fina(JoinPoint joinPoint) {
System.out.println("最终通知");
}
场景为已添加了5个笔记本,再次进行添加
结果添加新的笔记本失败.