为什么要使用AOP?
AOP是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。
在传统的业务处理代码中,通常都会进行事务处理、日志记录等操作。虽然使用OOP可以通过组合或者继承的方式来达到代码的重用,但如果要实现某个功能(如日志记录),同样的代码仍然会分散到各个方法中。这样,如果想要关闭某个功能,或者对其进行修改,就必须要修改所有的相关方法。这不但增加了开发人员的工作量,而且提高了代码的出错率。
为了解决这一问题,AOP思想随之产生。AOP采用横向抽取机制,将分散在各个方法的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。这种采用横向抽取机制的方式,采用传统的OOP思想显然是无法办到的,因为OOP只能实现父子关系的纵向的重用。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。
AOP的使用,使开发人员在编写业务逻辑时可以专心于核心业务,而不必过多地关注于其他业务逻辑的实现这不但提高了开发效率,而且增强了代码的可维护性。
AOP中的名词概念
Aspect(切面):指横切性关注点的抽象即为切面,与类相似,只是两者的关注点不同,类是对物体特征的抽象,而切面是对横切面关注点的抽象。
JoinPoint(连接点):连接点是指那些被拦截到的点,spring中这些点指的是方法。
Pointcut(切入点):切入点是指我们要对那些JoinPoint进行拦截的定义。
Advice(通知):通知是指拦截到JoinPoint之后要做的事情,分为前置通知、后置通知、异常通知,最终通知、环绕通知。
前置通知和后置通知一个是在连接点之前执行,一个是在连接点退出的时候执行。异常通知是方法抛出异常退出时执行的逻辑。环绕通知是包围连接点退出的时候执行的逻辑。
AOP注解方式编程的步骤
- 定义一个切面类 @Aspect注解
- 定义@Pointcut切点,即定义一个方法,指定拦截项目中的那些方法
- 定义五中类型中的哪一种通知,即定义了一个方法,表示切点拦截到了方法后,执行什么功能
- beans.xml中添加<aop:aspectj-autoproxy></aop:aspectj-autoproxy>标签,支持aop的注解
package cn.sdut.aop;
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;
/**
* 切面类
* @author DELL
*
*/
@Component //组件注解
@Aspect //注解切面类
public class AspectLog {
//注解切入点作用于cn.sdut.service包下所有的类的方法
@Pointcut(value="execution(* cn.sdut.service.*.*(..))")
private void pointCut() {
}
//注解前置通知
@Before(value="pointCut()")
public void beforeLog(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getDeclaringTypeName()+"."
+joinPoint.getSignature().getName()+" is called.. before");
}
//注解后置通知
@After(value="pointCut()")
public void afterLog(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getDeclaringTypeName()+"."
+joinPoint.getSignature().getName()+" is called.. after");
}
//返回注解通知
@AfterReturning(value="pointCut()")
public void afterReturningLog(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getDeclaringTypeName()+"."+
joinPoint.getSignature().getName()+" ar is called.. return");
}
//环绕通知
@Around(value="pointCut()")
public Object AroundLog(ProceedingJoinPoint point) throws Throwable {
System.out.println(point.getSignature().getDeclaringTypeName()+"."+
point.getSignature().getName()+" ar is called.. start");
Object object = point.proceed();
System.out.println(point.getSignature().getDeclaringTypeName()+"."+
point.getSignature().getName()+" ar is called.. end");
return object;
}
//异常通知
@AfterThrowing(value="pointCut()")
public void afterThrowingLog(JoinPoint joinPoint) {
System.out.println(joinPoint.getSignature().getDeclaringTypeName()+"."+
joinPoint.getSignature().getName()+" ar is called.. throwing");
}
}
AOP的xml方式配置
- 定义切面类,编写切面类中的方法
- beans.xml中配置aop信息
<aop:config>
<aop:aspect id="myAspect" ref="aspectLog">
<aop:pointcut id="mypointcut" expression="execution(* cn.sdut.dao.*.*(..))" />
<aop:before method="beforeLog" pointcut-ref="mypointcut"/>
<aop:after method="afterLog" pointcut-ref="mypointcut"/>
<aop:after-returning method="afterReturningLog" pointcut-ref="mypointcut"/>
<aop:around method="aroundLog" pointcut-ref="mypointcut"/>
<aop:after-throwing method="afterThrowingLog" pointcut-ref="mypointcut"/>
</aop:aspect>
</aop:config>
ref指向的是切面类首字母小写 。