Springソースコード解析(五):Spring AOP取得Proxy


次に、SpringのAOPの関連コードのいくつかを見てみます.Proxyはどうやって入手できますか?まず、AOPとSpring AOPの基本概念を見てみましょう.
Advice:
    リンクポイントで何をするかを通知します.Spingにおいて、彼は主にSpringが注入を呼び出すための追加的な行動を説明します.Springが提供する通知の種類は以下の通りです.
    before advice、AfterReturningAdvice、ThrowAdvice、MethodBefore Advice、これらはすべてSpring AOPで定義されているインターフェースクラスで、具体的な動作はユーザープログラムが完成する必要があります.
Pointcut:
    アドヴィスがどの接続点に適用すべきかを決定する点、すなわち追加の処理を挿入する必要がある場所の集合、例えば、あるアドヴィスをターゲットとする方法のセット.Spring pointcutは典型的には標示方法を意味しており、pointcutとして呼び出される方法のセットを選択することができ、Springは具体的な接点を提供してユーザに使用される.例えば、正規表現の接点JdkRegexpMethodPoint cutは、正規表現によって方法名をマッチングする.それはAbstractJdkRegexpMethodPointcutにおけるMethodMatchインターフェースの実現を使用してpointcut機能を完成する.
public final boolean matches(Method method, Class targetClass) {   
    //                
    String patt = method.getDeclaringClass().getName() + "." + method.getName();   
    for (int i = 0; i < this.patterns.length; i++) {   
        //                      
        boolean matched = matches(patt, i);   
        if (matched) {   
            for (int j = 0; j < this.excludedPatterns.length; j++) {   
                boolean excluded = matchesExclusion(patt, j);   
                if(excluded) {   
                    return false;   
                }   
            }   
            return true;   
        }   
    }   
    return false;   
}  

    public final boolean matches(Method method, Class targetClass) {
        //             
        String patt = method.getDeclaringClass().getName() + "." + method.getName();
        for (int i = 0; i < this.patterns.length; i++) {
            //                   
            boolean matched = matches(patt, i);
            if (matched) {
                for (int j = 0; j < this.excludedPatterns.length; j++) {
                    boolean excluded = matchesExclusion(patt, j);
                    if(excluded) {
                        return false;
                    }
                }
                return true;
            }
        }
        return false;
    }
JDKRegexpMethodPoint cutではJDKの正規表現マッチングによってpointcutの最終的な決定を完了します.
protected boolean matches(String pattern, int patternIndex) {   
    Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);   
    return matcher.matches();   
}  

    protected boolean matches(String pattern, int patternIndex) {
        Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
        return matcher.matches();
    }
アドバイザー:
追加の動作設計(advice)と追加の動作挿入点の設計(pointcut)を完成すると、それらを結びつける対象が必要です.これは通知器-advisorです.どの通知をどこで適用すべきかを定義します.Advisorの実現は、Default Point Advisorの二つの属性adviceとpoint cutがあります.
続いて、ProxyFactoryBeanを通じて、私たちの代理先と各方面の行動を配置します.ProxyFactoryBeanにはinterceptorNamesがあります.定義された通知器-advisorを配置します.ここの名前はinterceptNamesといいますが、実際にはadvisorを配置するところです.eanはFactoryBeanです.ProxyFactoryBeanではgetObject()を通じて直接代理先を得ることができます.
public Object getObject() throws BeansException {   
    //            
    initializeAdvisorChain();   
    if (isSingleton()) {   
    //           Proxy   
        return getSingletonInstance();   
    }   
    else {   
    .......   
        //          Prototype   Proxy   
        return newPrototypeInstance();   
    }   
}  

    public Object getObject() throws BeansException {
        //         
        initializeAdvisorChain();
        if (isSingleton()) {
        //           Proxy
            return getSingletonInstance();
        }
        else {
        .......
            //          Prototype   Proxy
            return newPrototypeInstance();
        }
    }
どのようにして単品の代理対象を生成するかを見てみます.
private synchronized Object getSingletonInstance() {   
    if (this.singletonInstance == null) {   
        this.targetSource = freshTargetSource();   
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {   
            //               
            setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));   
        }   
        // Eagerly initialize the shared singleton instance.   
        super.setFrozen(this.freezeProxy);   
        //           ProxyFactory        Proxy   
        this.singletonInstance = getProxy(createAopProxy());   
        // We must listen to superclass advice change events to recache the singleton   
        // instance if necessary.   
        addListener(this);   
    }   
    return this.singletonInstance;   
}   
  
//  createAopProxy   AopProxy       。   
protected Object getProxy(AopProxy aopProxy) {   
    return aopProxy.getProxy(this.beanClassLoader);   
}  

    private synchronized Object getSingletonInstance() {
        if (this.singletonInstance == null) {
            this.targetSource = freshTargetSource();
            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
                //            
                setInterfaces(ClassUtils.getAllInterfacesForClass(this.targetSource.getTargetClass()));
            }
            // Eagerly initialize the shared singleton instance.
            super.setFrozen(this.freezeProxy);
            //           ProxyFactory        Proxy
            this.singletonInstance = getProxy(createAopProxy());
            // We must listen to superclass advice change events to recache the singleton
            // instance if necessary.
            addListener(this);
        }
        return this.singletonInstance;
    }

    //  createAopProxy   AopProxy       。
    protected Object getProxy(AopProxy aopProxy) {
        return aopProxy.getProxy(this.beanClassLoader);
    }
ProxyFactoryBeanの父はAdviedSupportであり、SpringはAopProxyインターフェースを使ってAOPエージェントの実現とフレームの他の部分を分離しています.Advied Supportではこのような方式でAopProxyを取得します.もちろんここではAopProxyFactoryの助けが必要です.希望のエージェント:
protected synchronized AopProxy createAopProxy() {   
    if (!this.isActive) {   
        activate();   
    }   
    return getAopProxyFactory().createAopProxy(this);   
}  

    protected synchronized AopProxy createAopProxy() {
        if (!this.isActive) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }
ProxyConfigで使用するAopProxyFactoryを定義しました.
//  DefaultAopProxyFactory Spring    AopProxy   ,   
//      JDK Cglib      。   
private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();  

    //  DefaultAopProxyFactory Spring    AopProxy   ,
    //      JDK Cglib      。
    private transient AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();
この中でDefault AopProxyFactoryではAopProxyが生成されます.
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {   
    //      cglib       ,                       
    if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||   
        advisedSupport.getProxiedInterfaces().length == 0) {   
        //         cglib ,      。   
        if (!cglibAvailable) {   
            throw new AopConfigException(   
                    "Cannot proxy target class because CGLIB2 is not available. " +   
                    "Add CGLIB to the class path or specify proxy interfaces.");   
        }   
        //     Cglib   Proxy,  target         ,  cglib   AopProxy   
        return CglibProxyFactory.createCglibProxy(advisedSupport);   
    }   
    else {   
        //     JDK   Proxy,  JDK   AopProxy   
        return new JdkDynamicAopProxy(advisedSupport);   
    }   
}  

    public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
        //      cglib       ,                    
        if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
            advisedSupport.getProxiedInterfaces().length == 0) {
            //         cglib ,      。
            if (!cglibAvailable) {
                throw new AopConfigException(
                        "Cannot proxy target class because CGLIB2 is not available. " +
                        "Add CGLIB to the class path or specify proxy interfaces.");
            }
            //     Cglib   Proxy,  target         ,  cglib   AopProxy
            return CglibProxyFactory.createCglibProxy(advisedSupport);
        }
        else {
            //     JDK   Proxy,  JDK   AopProxy
            return new JdkDynamicAopProxy(advisedSupport);
        }
    }
JDKまたはCglibによって生成されるプロキシオブジェクトを見ることができます.JdkDynamicAopProxy類とCglib 2 AopProxy両方が実現するのはAopProxyのインターフェースです.JdkDynamicAopProxy実現において、Proxyはどのように生成されたのかを見ることができます.
public Object getProxy(ClassLoader classLoader) {   
    if (logger.isDebugEnabled()) {   
        Class targetClass = this.advised.getTargetSource().getTargetClass();   
        logger.debug("Creating JDK dynamic proxy" +   
                (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));   
    }   
    Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);   
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);   
    //      JDK Proxy      Proxy     
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);   
}  

    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            Class targetClass = this.advised.getTargetSource().getTargetClass();
            logger.debug("Creating JDK dynamic proxy" +
                    (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
        }
        Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        //      JDK Proxy      Proxy  
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
このようにProxyでtargetを包装した後、Proxy FactoryBeanを通じてその方法に対する呼び出しを受けてProxyにブロックされました.Proxy FactoryBeanのgetObject()方法で得られたのは、実はProxyです.私たちのtargetオブジェクトはすでにパッケージされています.Proxy FactoryBeanという工場benにとって、その生産の対象はパッケージの対象となります.