Small Spring系列十:aop (三)

栏目: Java · 发布时间: 6年前

内容简介:山有木兮木有枝,心悦君兮君不知。到目前位置,关于

山有木兮木有枝,心悦君兮君不知。

Small Spring系列十:aop (三)

概述

到目前位置,关于 aop 的部分,我们已经完成了以下功能

  1. 根据 Bean 的名称和方法名,获取 Method 对象。 MethodLocatingFactory
  2. 给定一个类的方法,判断该方法是否符合 Pointcut 的表达式。 AspectJExpressionPointcut
  3. 实现了前置,后置和异常的通知。 AspectJBeforeAdvice , AspectJAfterReturningAdvice , AspectJAfterThrowingAdvice
  4. 实现了 Advice 按次续依次执行。 ReflectiveMethodInvocation
  5. 给定一个 AopConif ,使用 Cglib 生成一个对象的代理。

接下来只剩下最后一个工作,读取 bean-v5.xml 创建 BeanDefinition

分析aop:config标签

在创建 BeanDefinition 之前我们先看一下 aop:config 的定义,之前 Bean 的定义。

<bean id = "nioCoder"
    class = "com.niocoder.service.v1.NioCoderService">
</bean>

现在 Bean 的定义

<!-- aop 配置-->
<aop:config>
    <!-- aop 核心配置 依赖tx-->
    <aop:aspect ref="tx">
        <!-- 切入点配置 包下面的placeOrder 方法-->
        <aop:pointcut id="placeOrder"
                      expression="execution(* com.niocoder.service.v5.*.placeOrder(..))"/>
        <!-- 通知配置,-->
        <aop:before pointcut-ref="placeOrder" method="start"/>
        <aop:after-returning pointcut-ref="placeOrder" method="commit"/>
        <aop:after-throwing pointcut-ref="placeOrder" method="rollback"/>
    </aop:aspect>

</aop:config>

之前如果 Bean 有其它额外的属性,我们都是通过 PropertyValueConstructorArgument 来表示。但 aop:config 的标签该如何表达呢?

spring 还是通过 GenericBeanDefinition 来表示 aop:config 标签,关于标签属性的映射,参考下图

<aop:pointcut id="placeOrder"
              expression="execution(* com.niocoder.service.v5.*.placeOrder(..))"/>

Small Spring系列十:aop (三)

<aop:before pointcut-ref="placeOrder" method="start"/>

Small Spring系列十:aop (三)

通过上图的构造器类型,我们发现这与我们之前创建 AspectJBeforeAdvice 的构造器参数不匹配。

public AspectJBeforeAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, Object adviceObject) {
    super(adviceMethod, pointcut, adviceObject);
}

因上图的第一个构造器参数中含有 methodName ,所以我们只需将修改 adviceObject 修改为 AspectInstanceFactory 。关于 AspectInstanceFactory 的类图设计如下:

Small Spring系列十:aop (三)

FactoryBean

工厂bean,

/**
 * 工厂bean
 * @author zhenglongfei
 */
public interface FactoryBean<T> {

    T getObject() throws Exception;

    Class<?> getObjectType();
}

BeanFactoryAware

有些实现类需要用到 BeanFactory ,实现该接口即可。

public interface BeanFactoryAware {

    /**
     * set beanFactory
     *
     * @param beanFactory
     * @throws BeansException
     */
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

AspectInstanceFactory

/**
 * @author zhenglongfei
 */
public class AspectInstanceFactory implements BeanFactoryAware {

    private String aspectBeanName;

    private BeanFactory beanFactory;

    public void setAspectBeanName(String aspectBeanName) {
        this.aspectBeanName = aspectBeanName;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        if (!StringUtils.hasText(this.aspectBeanName)) {
            throw new IllegalArgumentException(" 'aspectBeanName' is required");
        }
    }

    public Object getAspectInstance() throws Exception {
        return this.beanFactory.getBean(this.aspectBeanName);
    }
}

MethodLocatingFactory

实现 FactoryBean<Method>BeanFactoryAware

public class MethodLocatingFactory implements FactoryBean<Method>, BeanFactoryAware {

}

AbstractAspectJAdvice

Object adviceObject 替换成 AspectInstanceFactory adviceObjectFactory ,修改 invokeAdviceMethod() 方法,对象是从 benFactory 中根据 aspectBeanName 获取。

ublic abstract class AbstractAspectJAdvice implements Advice {

    private Method adviceMethod;
    private AspectJExpressionPointcut pointcut;
    private Object adviceObject;

    public AbstractAspectJAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, Object adviceObject) {
        this.adviceMethod = adviceMethod;
        this.pointcut = pointcut;
        this.adviceObject = adviceObject;
    }

    @Override
    public Pointcut getPointcut() {
        return pointcut;
    }

    public Method getAdviceMethod() {
        return this.adviceMethod;
    }

    public void invokeAdviceMethod() throws Throwable {
        adviceMethod.invoke(adviceObject);
    }
}

AspectJBeforeAdvice

因抽象方法修改,子类构造函数也需要修改, AspectJAfterReturningAdviceAspectJAfterThrowingAdvice 也需要修改

ublic class AspectJBeforeAdvice extends AbstractAspectJAdvice {

    public AspectJBeforeAdvice(Method adviceMethod, AspectJExpressionPointcut pointcut, Object adviceObject) {
        super(adviceMethod, pointcut, adviceObject);
    }
......
}

AbstractV5Test

提出公工方法到一个测试类中

public class AbstractV5Test {

    protected BeanFactory getBeanFactory(String configFile) {
        DefaultBeanFactory defaultBeanFactory = new DefaultBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(defaultBeanFactory);
        reader.loadBeanDefinition(new ClassPathResource(configFile));
        return defaultBeanFactory;
    }

    protected Method getAdviceMethod(String methodName) throws Exception {
        return TransactionManager.class.getMethod(methodName);
    }

    protected AspectInstanceFactory getAspectInstanceFactory(String targetBeanName) {
        AspectInstanceFactory factory = new AspectInstanceFactory();
        factory.setAspectBeanName(targetBeanName);
        return factory;
    }
}

CglibAopProxyTest

动态获取 AspectInstanceFactory

public class CglibAopProxyTest extends AbstractV5Test {

    private static AspectJBeforeAdvice beforeAdvice = null;
    private static AspectJAfterReturningAdvice afterAdvice = null;
    private AspectJExpressionPointcut pc = null;
    private BeanFactory beanFactory = null;
    private NioCoderService nioCoderService = null;
    private AspectInstanceFactory aspectInstanceFactory = null;

    @Before
    public void setUp() throws Exception {

        MessageTracker.clearMsgs();

        String expression = "execution(* com.niocoder.service.v5.*.placeOrder(..))";
        pc = new AspectJExpressionPointcut();
        pc.setExpression(expression);
        nioCoderService = new NioCoderService();

        beanFactory = this.getBeanFactory("bean-v5.xml");
        aspectInstanceFactory = this.getAspectInstanceFactory("tx");
        aspectInstanceFactory.setBeanFactory(beanFactory);

        beforeAdvice = new AspectJBeforeAdvice(
                getAdviceMethod("start"),
                pc,
                aspectInstanceFactory);

        afterAdvice = new AspectJAfterReturningAdvice(
                getAdviceMethod("commit"),
                pc,
                aspectInstanceFactory);
    }

    @Test
    public void testGetProxy() {
        AopConfig config = new AopConfigSupport();

        config.addAdvice(beforeAdvice);
        config.addAdvice(afterAdvice);
        config.setTargetObject(nioCoderService);

        CglibProxyFactory proxyFactory = new CglibProxyFactory(config);

        NioCoderService proxy = (NioCoderService) proxyFactory.getProxy();

        proxy.placeOrder();

        List<String> msgs = MessageTracker.getMsgs();

        Assert.assertEquals(3, msgs.size());
        Assert.assertEquals("start tx", msgs.get(0));
        Assert.assertEquals("place order", msgs.get(1));
        Assert.assertEquals("commit tx", msgs.get(2));
    }
}

ReflectiveMethodInvocationTest

动态获取 AspectInstanceFactory

public class ReflectiveMethodInvocationTest extends AbstractV5Test{

    private AspectJBeforeAdvice beforeAdvice = null;
    private AspectJAfterReturningAdvice afterReturningAdvice;
    private AspectJAfterThrowingAdvice afterThrowingAdvice;
    private NioCoderService nioCoderService;
    private AspectJExpressionPointcut pc = null;
    private BeanFactory beanFactory = null;
    private AspectInstanceFactory aspectInstanceFactory = null;


    @Before
    public void setUp() throws Exception {
        nioCoderService = new NioCoderService();
        String expression = "execution(* com.niocoder.service.v5.*.placeOrder(..))";
        pc = new AspectJExpressionPointcut();
        pc.setExpression(expression);

        beanFactory = this.getBeanFactory("bean-v5.xml");
        aspectInstanceFactory = this.getAspectInstanceFactory("tx");
        aspectInstanceFactory.setBeanFactory(beanFactory);

        MessageTracker.clearMsgs();
        beforeAdvice = new AspectJBeforeAdvice(TransactionManager.class.getMethod("start"), pc, aspectInstanceFactory);
        afterReturningAdvice = new AspectJAfterReturningAdvice(TransactionManager.class.getMethod("commit"), pc, aspectInstanceFactory);
        afterThrowingAdvice = new AspectJAfterThrowingAdvice(TransactionManager.class.getMethod("rollback"), pc, aspectInstanceFactory);
    }


    @Test
    public void textMethodInvocation() throws Throwable {

        Method targetMethod = NioCoderService.class.getMethod("placeOrder");
        List<MethodInterceptor> interceptorList = new ArrayList<>();
        interceptorList.add(beforeAdvice);
        interceptorList.add(afterReturningAdvice);

        ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, targetMethod, new Object[0], interceptorList);
        mi.proceed();

        List<String> msgs = MessageTracker.getMsgs();

        Assert.assertEquals(3, msgs.size());
        Assert.assertEquals("start tx", msgs.get(0));
        Assert.assertEquals("place order", msgs.get(1));
        Assert.assertEquals("commit tx", msgs.get(2));
    }

    @Test
    public void testAfterThrowing() throws Throwable{

        Method targetMethod = NioCoderService.class.getMethod("placeOrderWithException");
        List<MethodInterceptor> interceptorList = new ArrayList<>();
        interceptorList.add(beforeAdvice);
        interceptorList.add(afterThrowingAdvice);

        ReflectiveMethodInvocation mi = new ReflectiveMethodInvocation(nioCoderService, targetMethod, new Object[0], interceptorList);

        try {
            mi.proceed();
        } catch (Throwable t) {
            List<String> msgs = MessageTracker.getMsgs();

            Assert.assertEquals(2, msgs.size());
            Assert.assertEquals("start tx", msgs.get(0));
            Assert.assertEquals("rollback tx", msgs.get(1));
            return;
        }

        Assert.fail("No Exception thrown");
    }
}

代码下载

解析aop:config标签

TODO ….

代码下载

参考资料

从零开始造Spring


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

集体智慧编程

集体智慧编程

TOBY SEGARAN / 莫映、王开福 / 电子工业出版社 / 2009-1 / 59.80元

本书以机器学习与计算统计为主题背景,专门讲述如何挖掘和分析Web上的数据和资源,如何分析用户体验、市场营销、个人品味等诸多信息,并得出有用的结论,通过复杂的算法来从Web网站获取、收集并分析用户的数据和反馈信息,以便创造新的用户价值和商业价值。全书内容翔实,包括协作过滤技术(实现关联产品推荐功能)、集群数据分析(在大规模数据集中发掘相似的数据子集)、搜索引擎核心技术(爬虫、索引、查询引擎、Page......一起来看看 《集体智慧编程》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具