之前有写过关于对AOP的理解,现在系统的学习了之后对其印象更加深刻了,首先肯定是面向切面编程。
就是把我们程序重复执行的代码抽取出来,在需要执行的时候,使用动态代理,上一篇文章讲的
1.AOP的作用
程序运行期间,不修改源码对已有方法进行增强
2.AOP优势
减少重复代码,提高开发效率,维护方便(其实这三个感觉都一样的)
3.AOP的实现方式
动态代理技术
4.AOP相关术语
Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点,一般指的就是业务层的方法。
Pointcut(切入点):
所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义,即对哪些业务层的方法进行了增强,切入点的要求比连接点的要求更高一点。
Advice(通知/增强)
拦截到Joinpoint之后要做的事情就是通知,通知分为:前置,后置,异常,最终,环绕
Target(目标对象)
代理的目标对象
Aspect(切面)
是指切入点和通知相结合
5.基于XML的AOP设置
配置步骤:
5.1、把通知Bean也交给spring来管理
5.2、使用aop:config标签表明开始AOP的配置
5.3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id。
5.4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<bean id="logger" class="com.itheima.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面 -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:before method="printLog" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:before>
</aop:aspect>
</aop:config>
---------------------------
这个时候写测试类的时候,不仅会输出业务层方法,也会输出增强的方法,至于作用时间,由标签<aop:xxx>决定xxx有before,returnning,after-throwing,after,around
切入点的表达式说明
aop:pointcut:
作用: 用于配置切入点表达式。就是指定对哪些类的哪些方法进行增强。
属性: expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识
<aop:pointcut expression="execution(
public void com.itheima.service.impl.AccountServiceImpl.transfer(
java.lang.String, java.lang.String, java.lang.Float) )" id="pt1"/>
如果我们配置切入点表达式如上,那么我们配置关联的时候得写point-ref=“pt1"
环绕通知不同于前面四种通知 ,spring的环绕通知是通过手动配置增强方法何时去执行?
public Object aroundPrintLog(ProceedingJoinPoint pjp){
Object rtValue=null;
try{
Object[] args=pjp.getArgs();
System.out.println("前置通知Logger类中的beforeprintLog方法开始记录日志了...");
rtValue= pjp.proceed();//明确调用业务层方法(切入点方法)
System.out.println("后置通知Logger类中的afterReturnPrintLog方法开始记录日志了...");
return rtValue;
}catch(Throwable t){
System.out.println("异常通知Logger类中的afterthrowingPrintLog方法开始记录日志了...");
throw new RuntimeException(t);
}finally {
System.out.println("最终通知Logger类中的afterPringLog方法开始记录日志了...");
}
}
6.基于注解配置的AOP
配置步骤
6.1把通知类使用注解配置@Component
6.2在通知类上使用@Aspect
声明为切面
6.3在增强的方法上使用@Before
,@AfterReturning
,@AfterThrowing
,@After
配置通知,然后在他们后面的括号里面写上切入点表达式,当然也可以在括号写上("pt1()),然后在上面配置如下代码
` @Pointcut("execution(* com.itheima.service.impl.*.*(..))")
private void pt1(){}
`
这里面如果配置了环绕通知,但是切入点方法没有执行,通知方法执行了,可能是没有在环绕通知中有明确的切入点方法调用,具体代码如下
@Around("pt1()")
public Object aroundPringLog(ProceedingJoinPoint pjp){
Object rtValue = null;
try{
Object[] args = pjp.getArgs();//得到方法执行所需的参数
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置");
rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
return rtValue;
}catch (Throwable t){
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
}
}
至于基于Spring的AOP配置的注解如何配置,我写的demo简单如下,
<!-- 配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 配置spring开启注解AOP的支持 -->,这个一定要写,否则前面根本不支持
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>