Small Spring系列十一:aop (四)

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

内容简介:回眸一笑百媚生,六宫粉黛无颜色。在前四篇,我们已经实现了使用

回眸一笑百媚生,六宫粉黛无颜色。

Small Spring系列十一:aop (四)

概述

在前四篇,我们已经实现了使用 Cglib 实现了 aop 动态代理。但是在 spring 中如果代理对象实现了接口,则默认使用 jdk 动态代理,也可以通过配置强制使用 cglib 代理。本篇,我们使用 jdk 动态代理来完善 aop

准备工作

INioCoderService

新增接口类,因为使用 jdk 动态代理,代理对象必须实现接口。

package com.niocoder.service.v6;

/**
 * 测试 JDK 动态代理
 */
public interface INioCoderService {

    void placeOrder();
}

NioCoderService

实现 INioCoderService 接口。

@Component(value = "nioCoder")
public class NioCoderService implements INioCoderService {

    public NioCoderService() {

    }


    public void placeOrder() {
        System.out.println("place order");
        MessageTracker.addMsg("place order");
    }

    public void placeOrderV2() {
        System.out.println("no interception");
    }
}

bean-v6.XML

设置 Pointcutv6 包下面的 placeOrder 方法。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 增加namespace-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop">

    <!-- 扫描哪个包下面的文件 -->
    <context:component-scan base-package="com.niocoder.service.v6">

    </context:component-scan>

    <!-- 模拟 TransactionManager-->
    <bean id="tx" class="com.niocoder.tx.TransactionManager"/>

    <!-- aop 配置-->
    <aop:config>
        <!-- aop 核心配置 依赖tx-->
        <aop:aspect ref="tx">
            <!-- 切入点配置 包下面的placeOrder 方法-->
            <aop:pointcut id="placeOrder"
                          expression="execution(* com.niocoder.service.v6.*.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>
</beans>

创建jdk代理工厂

根据类图aop 动态获取代理实例 创建 JdkAopProxyFactory 代理工厂。

JdkAopProxyFactory

package com.niocoder.aop.framework;

import com.niocoder.aop.Advice;
import com.niocoder.util.Assert;
import com.niocoder.util.ClassUtils;
import lombok.extern.java.Log;
import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhenglongfei
 */
@Log
public class JdkAopProxyFactory implements AopProxyFactory, InvocationHandler {

    private final AopConfig config;

    public JdkAopProxyFactory(AopConfig config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvices().size() == 0) {
            throw new AopConfigException("No advices specified");
        }
        this.config = config;
    }

    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {

        log.info("Creating JDK dynamic proxy: target source is " + this.config.getTargetObject());

        Class<?>[] proxiedInterfaces = config.getProxiedInterfaces();

        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object target = this.config.getTargetObject();
        Object retVal;
        List<Advice> chain = this.config.getAdvices(method);
        if (chain.isEmpty()) {
            retVal = method.invoke(target, args);
        } else {
            List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>();
            interceptors.addAll(chain);
            // We need to create a method invocation...
            retVal = new ReflectiveMethodInvocation(target, method, args, interceptors).proceed();
        }

        return retVal;
    }
}

AspectJAutoProxyCreator

AspectJAutoProxyCreatorcreateProxy 方法中添加 JDK 代理支持。

public class AspectJAutoProxyCreator implements BeanPostProcessor {
  ......
  protected Object createProxy(List<Advice> advices, Object bean) {
       AopConfigSupport config = new AopConfigSupport();
       for (Advice advice : advices) {
           config.addAdvice(advice);
       }

       Set<Class> targetInterfaces = ClassUtils.getAllInterfacesForClassAsSet(bean.getClass());
       for (Class<?> targetInterface : targetInterfaces) {
           config.addInterface(targetInterface);
       }

       config.setTargetObject(bean);

       AopProxyFactory proxyFactory = null;
       if (config.getProxiedInterfaces().length == 0) {
           proxyFactory = new CglibProxyFactory(config);
       } else {
           // JDK 代理
           proxyFactory = new JdkAopProxyFactory(config);
       }

       return proxyFactory.getProxy();
   }
  ......
}

ApplicationContextTest

测试 jdk 动态代理。

public class ApplicationContextTest {
    @Before
    public void setUp() {
        MessageTracker.clearMsgs();
    }

    @Test
    public void testGetBeanProperty() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-v6.xml");
        INioCoderService nioCoderService = (INioCoderService) ctx.getBean("nioCoder");

        nioCoderService.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));
    }
}

输出:

start tx
place order
commit tx

代码下载

代码下载

参考资料

从零开始造Spring


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

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

现代操作系统(第3版)

现代操作系统(第3版)

Andrew S. Tanenbaum / 陈向群、马洪兵 / 机械工业出版社 / 2009-7 / 75.00元

本书是操作系统领域的经典之作,与第2版相比,增加了关于Linux、Windows Vista和Symbian操作系统的详细介绍。书中集中讨论了操作系统的基本原理,包括进程、线程、存储管理、文件系统、输入/输出、死锁等,同时还包含了有关计算机安全、多媒体操作系统、掌上计算机操作系统、微内核、多核处理机上的虚拟机以及操作系统设计等方面的内容。此外,还在第2版的基础上对部分习题进行了增删,更有助于读者学......一起来看看 《现代操作系统(第3版)》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具