06spring源码分析-SpringAOP-demo1和实现源码分析

你知道spring事务是如何嵌套到你的业务代码中的吗?如果你告诉我是通过动态代理实现的,那么我可以告诉你,你的技术水平仅仅停留在初级阶段。下面我通过几篇文章来慢慢分析spring是怎么将事务代码嵌入到你的业务逻辑代码里面。

springAOP简单的demo1

demo的包结构
  • Waiter 接口
  • NaiveWaiter Waiter的实现类
  • GreetingBeforeAdvice前置通知(或者叫做前置增强)
  • TestBeforeAdvice测试类

代码如下

Waiter接口

package com.spring.start.aop;

/**
 * @Author: chao.zhu
 * @description:
 * @CreateDate: 2018/12/29
 * @Version: 1.0
 */
public interface Waiter {
    void greetTo(String name);
    void serveTo(String name);
}

NaiveWaiter实现类

package com.spring.start.aop;

/**
 * @Author: chao.zhu
 * @description:
 * @CreateDate: 2018/12/29
 * @Version: 1.0
 */
public class NaiveWaiter implements Waiter {
    @Override
    public void greetTo(String name) {
        System.out.println("greetTo:"+name);
    }

    @Override
    public void serveTo(String name) {
        System.out.println("serveTo:"+name);
    }
}

GreetingBeforeAdvice前置通知

package com.spring.start.aop;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

/**
 * @Author: chao.zhu
 * @description:
 * @CreateDate: 2018/12/29
 * @Version: 1.0
 */
public class GreetingBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        String clientName = (String)objects[0];
        System.out.println("hhh:"+clientName);
    }
}

测试类

下面测试类是通过ProxyFactory创建代理对象Waiter当调用Waiter的方式的时候会进入代理类执行代理类的逻辑。因为设置了代理目标pf.setTarget(tager);还有设置了增强类型。代理会按照约定执行增强和Waiter的方法

package com.spring.start.aop;

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

/**
 * @Author: chao.zhu
 * @description:
 * @CreateDate: 2018/12/29
 * @Version: 1.0
 */
public class TestBeforeAdvice {
    public static void main(String[] args) {
        Waiter tager = new NaiveWaiter();
        BeforeAdvice advice = new GreetingBeforeAdvice();
        ProxyFactory pf = new ProxyFactory();

        pf.setTarget(tager);

        pf.addAdvice(advice);

        Waiter proxy = (Waiter)pf.getProxy();

        proxy.greetTo("aaa");
        proxy.serveTo("bbb");
    }
}

运行结果

hhh:aaa
greetTo:aaa
hhh:bbb
serveTo:bbb

Process finished with exit code 0

可以看到执行结果会先执行我们的设置的前置通知(前置增强)然后才执行正真的业务代码。只要你对动态代理比较熟悉上面的代码应该可以猜个七七八八。下面我们再来看看spring是如何实现的

源码分析

我们按照测试类的代码顺序来逐一分析spring的源码。准备发车.....

实例化

先来看一下ProxyFactory的类结构

ProxyFactory继承结构

我们知道实例化的过程是先实例父类,然后实例子类,所以我们要挨个看一下每一个父类,子类的实例调用了那些方法。下面代码从ProxyConfig到ProxyFactory的顺序列出构造函数

//org.springframework.aop.framework.ProxyConfig
没有构造函数,使用默认的无参构造函数
//org.springframework.aop.framework.AdvisedSupport#AdvisedSupport()
    public AdvisedSupport() {
        initMethodCache();
    }
    private void initMethodCache() {
        this.methodCache = new ConcurrentHashMap>(32);
    }
//org.springframework.aop.framework.ProxyCreatorSupport#ProxyCreatorSupport()
    public ProxyCreatorSupport() {
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }
//org.springframework.aop.framework.ProxyFactory#ProxyFactory()
    public ProxyFactory() {
    }

上面一些列的构造函数都比较简单,实例了一个DefaultAopProxyFactory实例了一个Map用来做缓存。Waiter proxy = (Waiter)pf.getProxy();从ProxyFactory里面获取代理类。看一下实现方式

    public Object getProxy() {
        return createAopProxy().getProxy();
    }

创建生成代理类的工厂,然后生成代理类。在spring中一般使用JDK的动态代理或者CGLib的方式生成代理类。

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

上面 就是判断是用Jdk的方式还是Cglib的方式。我们之分析一下jdk的方式

    @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.advised.getTargetSource());
        }
        Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

我们知道在动态代理中生成的proxy代理类在执行方法的时候都是执行invoke方法。可以在JdkDynamicAopProxy里面找到invoke方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Class targetClass = null;
        Object target = null;

        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;

            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            // Get the interception chain for this method.
            List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // 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.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // 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;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
 
 

这就是我们使用编码的方式实现AOP的简单例子。源码实现也很简单。就是设置需要代理的目标对象,设置代理对象的增强,通过代理类生工厂生成代理类。这个代理类工厂有两种:JDK的方法,Cglib的方式。生成代理类之后再执行方法的时候都是调用代理类的invoke方法。然后在invoke方法里面执行增强和目标对象的方法。
附上增强结构图


image.png

你可能感兴趣的:(06spring源码分析-SpringAOP-demo1和实现源码分析)