• Spring Aop分析


    前言


    上文讲述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框架已经描述完毕了。

  • 相关阅读:
    分块查找
    vue笔记2022年7月29日21:38:22
    python 高级用法 错误、调试和测试
    python 中级用法
    python 面向对象
    换源笔记
    java Boolean 型不可直接判断
    java 下载或预览文件
    Cipher 使用 RSA非对称加密算法 公钥加密后,只有私钥才可以解密,私钥加密后,只有公钥才可以解密 java具体使用 非对称加密算法 总结心得
    java sprootboot 配置启动时记录进程号
  • 原文地址:https://www.cnblogs.com/xmzJava/p/9139741.html
Copyright © 2020-2023  润新知