zoukankan      html  css  js  c++  java
  • SpringAOP源码之 --- 代理

    概述

    1.增强的生成

    2.代理的获取

    从上一章可以看到,在获取到增强后,就可以通过createProxy创建代理了,源码如下:

    buildAdvisors

    protected Object createProxy(
                Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
    
            ProxyFactory proxyFactory = new ProxyFactory();
            proxyFactory.copyFrom(this);//获取当前类的属性
    
            if (!proxyFactory.isProxyTargetClass()) { //设置ProxyTargetClass属性,为true使用CGLIB方式代理,为false使用JdkDynamicProxy方式
                if (shouldProxyTargetClass(beanClass, beanName)) {
                    proxyFactory.setProxyTargetClass(true);
                }
                else {
                    evaluateProxyInterfaces(beanClass, proxyFactory);
                }
            }
    
            Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); //创建切面
            for (Advisor advisor : advisors) {
                proxyFactory.addAdvisor(advisor); //将创建的切面加入的PRoxyFactory中
            }
    
            proxyFactory.setTargetSource(targetSource); //设置要代理的类
            customizeProxyFactory(proxyFactory);
    
            proxyFactory.setFrozen(this.freezeProxy);
            if (advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
            }
    
            return proxyFactory.getProxy(getProxyClassLoader()); //获取代理
        }
    protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
            // Handle prototypes correctly...
            Advisor[] commonInterceptors = resolveInterceptorNames();
    
            List<Object> allInterceptors = new ArrayList<Object>();
            if (specificInterceptors != null) {//加入拦截器
                allInterceptors.addAll(Arrays.asList(specificInterceptors));
                if (commonInterceptors != null) {
                    if (this.applyCommonInterceptorsFirst) {
                        allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                    }
                    else {
                        allInterceptors.addAll(Arrays.asList(commonInterceptors));
                    }
                }
            }
            if (logger.isDebugEnabled()) {
                int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
                int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
                logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
                        " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
            }
    
            Advisor[] advisors = new Advisor[allInterceptors.size()];
            for (int i = 0; i < allInterceptors.size(); i++) {
                advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));//拦截器进行封装转换为advisor
            }
            return advisors;
        }
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
            if (adviceObject instanceof Advisor) {//如果要封装的对象本身就是Advisor就不需要处理
                return (Advisor) adviceObject;
            }
            if (!(adviceObject instanceof Advice)) {//此封装方法只对advice和advisor有效
                throw new UnknownAdviceTypeException(adviceObject);
            }
            Advice advice = (Advice) adviceObject;
            if (advice instanceof MethodInterceptor) { //如果是method拦截器,就使用defaultPointCutAdvisor封装
                // So well-known it doesn't even need an adapter.
                return new DefaultPointcutAdvisor(advice);
            }
            for (AdvisorAdapter adapter : this.adapters) { //如果存在advisor的适配器,也需要封装
                // Check that it is supported.
                if (adapter.supportsAdvice(advice)) {
                    return new DefaultPointcutAdvisor(advice);
                }
            }
            throw new UnknownAdviceTypeException(advice);
        }

    由于 Spring 中涉及过多的拦截器、通知器、增强方法等方式来对逻辑进行增强,所以非常有必要统一封装成 Advisor 来进行代理的创建,完成了增强的封装过程。

    接下来就是创建代理的过程了

    proxyFactory.getProxy(getProxyClassLoader())    public Object getProxy(ClassLoader classLoader) {

    return createAopProxy().getProxy(classLoader);
        }
    
    protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }
    
        public ProxyCreatorSupport() {
            this.aopProxyFactory = new DefaultAopProxyFactory();
        }
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    /**
    (1)optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略。除非完全了解AOP。否则不推荐。目前这个属性也仅仅用于 CGLIB。
    (2)proxyTargetClass:这个属性为 true 时,目标类本身本代理而不是目标类的接口。如果这个属性值被设为 true,CGLIB 代理将被创建,设置方式:<aop:aspectj-autoproxy proxy-target-class="true"/>。
    */(3)hasNoUserSuppliedProxyInterfaces:是否存在代理接口。
    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()) { //如果是接口则使用JdkDynamicAopProxy来生成代理 return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config);//使用cglib来生成代理 } else { return new JdkDynamicAopProxy(config); } }

     这里只看JDK方式的,返回了一个JdkDynamicAopProxy类,其中的getProxy方法为:

    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);
            findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); //看过前面的jdk动态代理的文章就比较熟悉这里了
        }

    所以proxy代理时的实际调用其实为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]);
                }
                if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    // The target does not implement the hashCode() method itself.
                    return hashCode();
                }
                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<Object> 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.
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
                }
                else {
                    // We need to create a method invocation...,将拦截器封装在ReflectiveMethodInvocation
                    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.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);
                }
            }
        }
    public Object proceed() throws Throwable {
            //    We start with an index of -1 and increment early.
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return invokeJoinpoint();
            }
    
            Object interceptorOrInterceptionAdvice =
                    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);//获取下一个要执行的拦截器
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                // Evaluate dynamic method matcher here: static part will already have//动态匹配规则
                // been evaluated and found to match.
                InterceptorAndDynamicMethodMatcher dm =
                        (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
                if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                    return dm.interceptor.invoke(this);
                }
                else {
                    // Dynamic matching failed.
                    // Skip this interceptor and invoke the next in the chain.
                    return proceed();
                }
            }
            else {
                // It's an interceptor, so we just invoke it: The pointcut will have
                // been evaluated statically before this object was constructed.
                return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
            }
        }

    通过源码我们知道,invoke 方法是其核心逻辑实现的地方。其主要的工作就是创建一个拦截器链,然后使用 ReflectiveMethodInvocation 类对链进行封装,最后通过 proceed 方法对拦截器进行逐个调用,而 proceed 方法负责实现方法前调用以及后置调用的逻辑处理,然后将工作委托给各个增强器,在增强器内部实现具体逻辑。

  • 相关阅读:
    4:4 自定义拦截器
    DDD学习笔记一
    Winform/WPF国际化处理
    NPOI 操作Excel
    将输入的字符串进行大写格式化
    将输入的字符串分2个字符添加空格并大写格式化
    VS使用技巧
    NotifyIcon用法
    C#Winfrom系统打印机调用/设置默认打印机
    TextBox(只允许输入字母或者数字)——重写控件
  • 原文地址:https://www.cnblogs.com/dpains/p/7730020.html
Copyright © 2011-2022 走看看