什么是 AOP?
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译形式和运行期动静代理实现程序性能的对立保护的一种技术。AOP 是 OOP 的连续,是软件开发中的一个热点,也是 Spring 框架中的一个重要内容,是函数式编程的一种衍生范型。利用 AOP 能够对业务逻辑的各个局部进行隔离。从而使得业务逻辑各个局部之间的耦合性升高,进步程序的可重用性,同时进步了开发的效率。
AOP 在 Spring 中的作用
提供申明式事务;容许用户自定义切面
- 横切关注点:逾越应用程序多个模块的办法或性能。即是,与咱们的业务逻辑无关的,然而咱们须要关注的局部,就是横切关注点。如日志,平安,缓存,事务等等。
- 切面 (ASPECT): 横切关注点 被模块化 的非凡对象。即 它是一个类。【Log】
- 告诉 (Advice): 切面必须要实现的工作。即 它是类中的一个办法。【Log 中的办法】
- 指标 (Target): 被告诉对象。
- 代理 (Proxy): 向指标对象利用告诉之后创立的对象。
- 切入点 (PointCut): 切面告诉执行的“地点”的定义。
- 连接点 (JointPoint): 与切入点匹配的执行点。
SpringAOP 中,通过 Advice 定义横切逻辑,Spring 中反对 5 种类型的 Advice:
即 Aop 在不扭转原有代码的状况下,去减少新的性能。
应用 Spring 实现 AOP
应用 AOP 织入,须要导入一个依赖包
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
- 形式一:应用 Spring 的 API 接口【SpringAPI 接口实现】
applicationContext.xml:
<!-- 形式一:应用原生 Spring API 接口 -->
<!-- 配置 aop: 须要导入 aop 的束缚 -->
<aop:config>
<!-- 切入点:expression: 表达式,execution(要执行的地位)-->
<aop:pointcut id="pointcut" expression="execution(* com.sunfl.service.UserServiceImpl.*(..))"/>
<!-- 执行盘绕减少 -->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
日志类:
public class Log implements MethodBeforeAdvice {
//method: 要执行的指标对象的办法
//objects: 参数
//target: 指标对象
public void before(Method method, Object[] objects, Object target) throws Throwable {System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
}
}
public class AfterLog implements AfterReturningAdvice {
//returnValue: 返回值
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("执行了"+method.getName()+"办法,返回后果为:"+returnValue);
}
}
测试后果:
com.sunfl.service.UserServiceImpl 的 add 被执行了
减少了一个用户
执行了 add 办法,返回后果为:null
- 形式二:自定义来实现 AOP【切面定义】
applicationContext.xml:
<bean id="diy" class="com.sunfl.diy.DiyPointCut"/>
<aop:config>
<!-- 自定义切面:ref 要援用的类 -->
<aop:aspect ref="diy">
<!-- 切入点 -->
<aop:pointcut id="point" expression="execution(* com.sunfl.service.UserServiceImpl.*(..))"/>
<!-- 告诉 -->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
自定义切入点:
public class DiyPointCut {public void before(){System.out.println("========= 办法执行前 ========");
}
public void after(){System.out.println("========= 办法执行后 ========");
}
}
测试后果:
========= 办法执行前 ========
减少了一个用户
========= 办法执行后 ========
- 形式三:应用注解实现
applicationContext.xml:
<!-- 形式三 -->
<bean id="annotationPointCut" class="com.sunfl.diy.AnnotationPointCut"/>
<!-- 开启注解反对 -->
<aop:aspectj-autoproxy/>
切面类:
@Aspect // 标注这个类是一个切面
public class AnnotationPointCut {@Before("execution(* com.sunfl.service.UserServiceImpl.*(..))")
public void before(){System.out.println("======= 办法执行前 ======");
}
@After("execution(* com.sunfl.service.UserServiceImpl.*(..))")
public void after(){System.out.println("======= 办法执行后 ======");
}
// 在盘绕加强中,咱们能够给定一个参数,代表咱们要取得解决切入的点
@Around("execution(* com.sunfl.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println("盘绕前");
Signature signature = jp.getSignature();// 取得签名
System.out.println("signature:"+signature);
// 执行办法
Object proceed = jp.proceed();
System.out.println("盘绕后");
System.out.println(proceed);
}
}
测试后果:
盘绕前
signature:void com.sunfl.service.UserService.add()
======= 办法执行前 ======
减少了一个用户
盘绕后
null
======= 办法执行后 ======