1. 程式人生 > >從零開始造Spring09---實現AOP的JDK代理

從零開始造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();
    }

原始碼地址