AOP是OOP的延续,为Aspect Oriented Programming的缩写,意思为面向切面编程,AOP是Spring框架中的重要内容,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,提高开发效率。
举一个简单的例子,有多个业务需要去计算其中的业务处理时间,但我们不需要在每个业务代码中去编写计算时间代码,而是把这段计算时间的代码去交给代理对象,让代理对象帮我完成,从而减少重复代码、提高效率,并且便于维护。
AOP是基于Spring所提供的动态代理技术实现的,常用的动态代理技术可有JDK代理:基于接口的动态代理技术,和cglib代理:基于父类的动态代理技术。而AOP底层就是通过对这些动态代理的代码进行了封装,我们只需要对需要的代码进行编写,并且通过配置就可以实现对目标方法的增强。
在学习AOP我们需要了解一些相关的术语,常用的术语如下:
- Target(目标对象):代理的目标对象。
- Proxy(代理):一个类被AOP织入增强后就产生一个结果代理类。
- Joinpoint(连接点):指那些被拦截到的点,在spring中这些点就是方法。
- Pointcut(切入点):指我们要对哪些Joinpoint进行拦截的定义。
- Advice(通知/增强):拦截到Joinpoint之后要做的事情。
- Aspect(切面):切入点和通知的结合。
- Weaving(织入):把增强应用到目标对象来创建新的代理对象的过程。
基于XML的AOP开发
① 导入 AOP 相关坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
在此说明一下:在spring-context中虽然包含了spring-aop这个依赖,在spring提倡使用更简便的框架-aspectjweaver框架。
② 创建目标接口和目标类
public class Target implements TargetInterface {
public void save() {
System.out.println("go running.....");
}
}
public interface TargetInterface {
public void save();
}
③ 创建切面类(内部有增强方法)
public class MyAspect {
public void before(){
System.out.println("前置增强..........");
}
public void afterReturning(){
System.out.println("后置增强..........");
}
//Proceeding JoinPoint: 正在执行的连接点===切点
// public Object around(ProceedingJoinPoint pjp) throws Throwable {
// System.out.println("环绕前增强....");
// Object proceed = pjp.proceed();//切点方法
// System.out.println("环绕后增强....");
// return proceed;
// }
//
// public void afterThrowing(){
// System.out.println("异常抛出增强..........");
// }
//
// public void after(){
// System.out.println("最终增强..........");
// }
}
④ 将目标类和切面类的对象创建权交给 spring
<!--目标对象-->
<bean id="target" class="ssm.spring.aop.Target"/>
<!--切面对象-->
<bean id="myAspect" class="ssm.spring.aop.MyAspect"/>
⑤ 在 applicationContext.xml 中配置织入关系
<!--配置织入,告诉spring框架,哪些方法(切点)需要进行增强(前置、后置)-->
<aop:config >
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切点表达式的抽取-->
<aop:pointcut id="myPointcut" expression="execution(* ssm.spring.aop.*.*(..))"/>
<!--切面:切点+通知/增强-->
<aop:before method="before" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
⑥ 测试代码
基于注解的AOP开发
基于注解的aop开发步骤: ① 创建目标接口和目标类(内部有切点)
@Component("target")
public class Target implements TargetInterface {
public void save() {
System.out.println("go running.....");
}
}
public interface TargetInterface {
public void save();
}
② 创建切面类(内部有增强方法)
@Component("myAspect")
@Aspect
public class MyAspect {
@Before("execution(* ssm.spring.anno.*.*(..))")
public void before(){
System.out.println("前置增强..........");
}
public void afterReturning(){
System.out.println("后置增强..........");
}
//Proceeding JoinPoint: 正在执行的连接点===切点
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕前增强....");
Object proceed = pjp.proceed();//切点方法
System.out.println("环绕后增强....");
return proceed;
}
public void afterThrowing(){
System.out.println("异常抛出增强..........");
}
@After("myPoint()")
public void after(){
System.out.println("最终增强..........");
}
@Pointcut("execution(* ssm.spring.anno.*.*(..))")
public void myPoint(){
}
}
⑤ 在配置文件中开启组件扫描和 AOP 的自动代理
<!--设置组件扫描-->
<context:component-scan base-package="ssm.spring.anno"/>
<!--aop自动代理-->
<aop:aspectj-autoproxy/>
代码测试结果和上面的相同。