从零开始造Spring09---实现AOP的JDK代理

前言

接上一篇从零开始造Spring08—AOP(介绍以及实现ReflectiveMethodInvocation和AopProxyFactory),这篇文章我们接着来讲Spring的AOP的JDK代理,这是学习刘欣老师的《从零开始造Spring》的学习笔记。

JDK代理的说明

与Cglib代理有所不同的是,JDK代理是针对接口的代理。所有要使用JDK代理必须要有接口。

测试类

public interface IPetStoreService {
    void placeOrder();
}
@Component(value = "petStoreService")
public class PetStoreService implements IPetStoreService {
    public PetStoreService() {
    }

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

XML中的配置

        <context:component-scan
        base-package="com.jay.spring.service.v6">
    </context:component-scan>

    <!--作为一个切面-->
    <bean id="tx" class="com.jay.spring.tx.TransactionManager" />

    <aop:config>

        <aop:aspect ref="tx">
            <!--切点-->
            <aop:pointcut id="placeOrder"
                expression="execution(* com.jay.spring.service.v6.*.placeOrder(..))" />
            <aop:after-throwing pointcut-ref="placeOrder" method = "rollback"/>
            <aop:after-returning pointcut-ref="placeOrder"
                method="commit" />

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

JdkAopProxyFactory

public class JdkAopProxyFactory implements AopProxyFactory,InvocationHandler {
    private static final Log logger = LogFactory.getLog(JdkAopProxyFactory.class);

    private final AopConfig aopConfig;

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

    /**
     * 获取代理
     * @return
     */
    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }

    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.aopConfig.getTargetObject());
        }
        Class<?>[] proxiedInterfaces = aopConfig.getProxiedInterfaces();
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        获取目标对象
        Object target = this.aopConfig.getTargetObject();
        Object retVal;

        // Get the interception chain for this method.
        //获取通知点
        List<Advice> chain = this.aopConfig.getAdvices(method);
        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            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();


        }
        // Massage return value if necessary.
        /*Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target && returnType.isInstance(proxy) ) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }*/

        return retVal;
    }
}

说明 JDK代理类必须要实现InvocationHandler 接口。
调用JDK代理的方法在AspectJAutoProxyCreator

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();
    }

源码地址



作者:码农飞哥

微信公众号:码农飞哥