前言


上文讲述ioc框架的实现,本文开始讲述aop。在spring中aop也有3种配置方式,注解形式的我们先不讨论。我们先看看xml形式的配置方式。

<aop:config>
<aop:aspect ref="testInterceptor">
<aop:pointcut expression="execution(public * com.freud.test..*.*(..))"
id="testPointCut" />
<aop:after method="after" pointcut-ref="testPointCut" />
<aop:before method="before" pointcut-ref="testPointCut" />
</aop:aspect>
</aop:config>
<bean id="testInterceptor" class="com.freud.TestInterceptor" />
public class TestInterceptor {

    public void after() {
System.out.println("After");
} public void before() {
System.out.println("before");
}
}

上述配置是纯xml形式的配置,这样的配置结构清晰明了,就是看起来有点臃肿。

spring中提供了四种Advice用来支持对方法调用时施加的不同行为,通过这四种Advice可以帮助我们减少xml的配置

BeforeAdvice:具体接口:MethodBeforeAdvice 在目标方法调用之前调用的Advice
AfterAdvice:具体接口:AfterReturningAdvice 在目标方法调用并返回之后调用的Advice
AroundAdvice:具休接口:MethodInterceptor 在目标方法的整个执行前后有效,并且有能力控制目标方法的执行
ThrowsAdvice:具体接口:ThrowsAdvice 在目标方法抛出异常时调用的Advice

举个例子

<bean id="testInterceptor" class="com.freud.Interceptor.TestInterceptor"></bean>
<aop:config >
<!--切入点-->
<aop:pointcut id="testPointCut" expression="execution(public * com.freud.test.*.*(..))"/>
<!-- 在该切入点使用自定义拦截器 -->
<aop:advisor pointcut-ref="testPointCut" advice-ref="testInterceptor"/>
</aop:config>
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; public class TestInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//Do something before
Object ret = invocation.proceed();
//Do something After
return ret;
}
}

这里的TestInterceptor我们称之为Advice,就是往目标对象(Target)需要增强的内容。

这里MethodInvocation称之为切点(point cut),提供一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配 程序中的方法(join point), 给满足规则的 程序中的方法 添加 Advice.

那么现在我们可以吧aop转变为两个问题

1.如何通过joinpoint匹配到特定的joinpoint
2.如何编写advice代码织入增强

接下来我们看下我们该如何实现上述问题

1.Aop简单实现


前面已经说到spring中提供了四种Advice,我们这里可以使用MethodInterceptor帮助我们实现aop

invoke的参数MethodInvocation参数暴露了被调用的方法; 目标连接点;AOP代理以及传递给方法的参数。

现在我们创建以下几个对象

1.TargetSource 被代理的对象
2.MethodInterceptor实现类
3.AdvisedSupport 封装TargetSource和MethodInterceptor
4.ReflectiveMethodInvocation 继承MethodInvocation

  

那现在一次调用就是这样

现在还有个问题就是要获取被代理的方法和参数。通过反射的方式可以取到,但是这样写起来不够灵活。这里采用动态代理

那么现在,实现aop的操作就很清晰了

2.Aop与Spring的集成


第一段我们将aop的织入过程进行分析,其中有个很重要的东西被我们忽略了。那就是Pointcut表达式。Spring借鉴了AspectJ表达式,封装成AspectJExpressionPointcut。这里不做过多介绍

本文最开始的时候介绍了xml的配置方式实现aop,第一段我们已代码的形式,实现了aop的织入。接下来 我们看下aop与spring是如何结合的。

spring提供了BeanPostProcessor对象,只要你的Bean实现了BeanPostProcessor接口,那么Spring在初始化时,会优先找到它们,并且在Bean的初始化过程中,调用这个接口,从而实现对BeanFactory核心无侵入的扩展。

优先找到BeanPostProcessor代码如下

在实例化的时候,调用beanPostProcessor的方法增强bean。

我们举个例子

配置文件:

<bean id="autoProxyCreator" class="us.codecraft.tinyioc.aop.AspectJAwareAdvisorAutoProxyCreator"></bean>

    <bean id="timeInterceptor" class="us.codecraft.tinyioc.aop.TimerInterceptor"></bean>

    <bean id="aspectjAspect" class="us.codecraft.tinyioc.aop.AspectJExpressionPointcutAdvisor">
<property name="advice" ref="timeInterceptor"></property>
<property name="expression" value="execution(* us.codecraft.tinyioc.*.*(..))"></property>
</bean>

这里可能会有人奇怪这个配置为什么和最开头的配置不一样 ,最开头的配置都是以 <aop:config> 开头,而上面的配置文件只是几个bean而已。

其实spring在解析<aop:config>时会默认的提供包含 AspectJAwareAdvisorAutoProxyCreator 的 BeanDefinition,有兴趣的可以看看(org.springframework.aop.config.AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary)

在解析<aop:before>和<aop:after>时,spring会向候选Advisor链的开头添加一个org.springframework.aop.support.DefaultPointcutAdvisor。所以上述两种配置理论上是一样的。只是现在我们还没有spring解析的那一套代码,所以就直接已bean的形式写成配置文件。

测试代码

初始化的时候优先找到BeanPostProcessor上面已经提过了。getBean的前半段代码也已经提过,我们主要看下beanPostProcessor是如何增强的。

到这里,一个aop框架已经描述完毕了。

Spring Aop分析的更多相关文章

  1. Spring AOP分析(1) -- 基本概念

    AOP全称是Aspect Oriented Programming,面向切面编程,是面向对象编程(OOP:Object Oriented Programming)的补充和完善.一般在系统中,OOP利用 ...

  2. Spring AOP分析(2) -- JdkDynamicAopProxy实现AOP

    上文介绍了代理类是由默认AOP代理工厂DefaultAopProxyFactory中createAopProxy方法产生的.如果代理对象是接口类型,则生成JdkDynamicAopProxy代理:否则 ...

  3. Spring AOP分析(3) -- CglibAopProxy实现AOP

    上文探讨了应用JDK动态代理实现Spring AOP功能的方式,下面将继续探讨Spring AOP功能的另外一种实现方式 -- CGLIB. 首先,来看看类名CglibAopProxy,该类实现了两个 ...

  4. (转)Spring AOP实现方式(转)

    我们可以通过三种方式来使用Spring AOP,它们分别是:@Aspect-based(Annotation),Schema-based(XML),以及底层的Spring AOP API 底层的Spr ...

  5. 关于 Spring AOP (AspectJ) 该知晓的一切

    关联文章: 关于Spring IOC (DI-依赖注入)你需要知道的一切 关于 Spring AOP (AspectJ) 你该知晓的一切 本篇是年后第一篇博文,由于博主用了不少时间在构思这篇博文,加上 ...

  6. spring aop两种配置方式

    基于注解的Spring AOP开发 简单案例快速入门 定义目标类接口和实现类 /** * Created by zejian on 2017/2/19.*/ //接口类 public interfac ...

  7. 关于 Spring AOP (AspectJ) 你该知晓的一切

    版权声明:本文为CSDN博主「zejian_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/javazej ...

  8. Spring AOP在函数接口调用性能分析及其日志处理方面的应用

    面向切面编程可以实现在不修改原来代码的情况下,增加我们所需的业务处理逻辑,比如:添加日志.本文AOP实例是基于Aspect Around注解实现的,我们需要在调用API函数的时候,统计函数调用的具体信 ...

  9. 161220、使用Spring AOP实现MySQL数据库读写分离案例分析

    一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量. 在进行数据库读写分离的时候,我们首先要进行数据库 ...

随机推荐

  1. jquery基础知识随笔

    <html> <head> <script type="text/javascript" src="/jquery/jquery.js&qu ...

  2. String Match

    Finding length of longest common substring /*Finding length of longest common substring using DP * * ...

  3. centos7 安装freetype

    1:下载: wget "http://download.savannah.gnu.org/releases/freetype/freetype-2.4.0.tar.bz2" 2:  ...

  4. 第48章:MongoDB-备份和恢复

    ①文件系统快照(snapshot) 生成文件系统快照这个方法需要满足两个条件: 1:文件系统本身支持快照技术 2:运行mongod时必须开启日记系统 其恢复就是快照的恢复,当然,恢复的时候,确保mon ...

  5. 底图与蒙版的过渡效果transition

    我用2种方法写了底图与蒙版的过渡效果 方法一:用js方法 <!DOCTYPE html> <html> <head> <meta http-equiv=&qu ...

  6. MySQL的计算时间差

    一.MySQL计算两个日期的时间差 TIMESTAMPDIFF(DAY, datetime1, datetime2); 第一个参数为比较类型,有day, month, year, hour等: 第二个 ...

  7. kvm-qcow2派生镜像的远程备份的方法!

    在虚拟化环境中,关于虚拟机的远程备份是一个比较重要的环节,这个是有关于整个机房挂掉之后,仍然可以恢复的最后一招. 在kvm中这种情况可以通过直接备份虚拟机的镜像文件(qcow2)到远端存储解决. 但有 ...

  8. 端口转发 Port Forwarding (一)

    0x00First 最近发现一些好用的端口转发工具和技巧,计划认真梳理一下 SSH.NC.LCX.EW.FRP 0x01 SSH隧道端口转发 目前利用SSH隧道(SSH tunneling)进行端口转 ...

  9. JS中创建多个相同的变量出现的问题

    在做轮播图的时候出现了一个问题:如果定义两个完全相同的变量会发生什么: 1.两个全局变量: var num = 10; var num =100; 这种情况下很明显输出num的话会是100,但是内存中 ...

  10. Android中监控home键

    一.需求 在应用开发过程中,启动服务开启线程锁等待服务返回解锁,为了避免点击home键使线程锁卡死的bug,需要监控home键,解锁线程. 二.实现 在应用时,需要register和unregiste ...