您的位置:首页 > 编程语言 > Java开发

Spring源代码分析(10)---ProxyFactoryBean(旁敲侧击的AOP时代终于来临)

2008-10-02 14:40 627 查看
我们知道,AOP是面向切面编程,在java领域的AOP中,最著名莫过于牛逼哄哄的AspectJ了,我们在前几节的源码分析中,也复习了一下动态代理的知识,在那里,我们采用了几种手段来实现切面效果以及他们之间的区别和利弊;

从这一节,我们来分析一下Spring中的Aop的实现细节;

首先,我们先来看一个Spring AOP的例子:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

    <bean id="name" name="name" class="org.corey.demo.Name"
        abstract="false" lazy-init="default" autowire="default"
        dependency-check="default">
        <constructor-arg value="cui" />
        <constructor-arg value="chizhou"></constructor-arg>
    </bean>

    <bean id="person" name="person" class="org.corey.demo.Person">
        <property name="name" ref="name"></property>
    </bean>

    <bean name="advice" id="advice" class="org.syna.demo.BeforeAdvice"></bean>

    <bean name="pointcut" id="pointcut"
        class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedName">
            <value>*say</value>
        </property>
    </bean>

    <bean id="advisor" name="advisor"
        class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice">
            <ref local="advice" />
        </property>
        <property name="pointcut">
            <ref local="pointcut" />
        </property>
    </bean>

    <bean name="proxyBean"
        class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target">
            <ref local="person" />
        </property>
        <property name="interceptorNames">
            <list>
                <idref local="advisor" />
            </list>
        </property>
    </bean>
装备:package org.syna.demo;

import java.lang.reflect.Method;

import org.springframework.aop.MethodBeforeAdvice;

public class BeforeAdvice implements MethodBeforeAdvice {

    public void before(Method arg0, Object[] arg1, Object arg2)
            throws Throwable {
        System.out.println("before logging");
    }

}

package org.corey.demo;

public interface IPerson {
    public Name getName();

    public void setName(Name name);

    public void setAddress(String address);

    public String getAddress();
    
    public void say();
}

package org.corey.demo;

public class Person implements IPerson {

    private String name2;

    public void setBeanName(String name) {
        System.out.println("set name aware");
        this.name2 = name;
    }

    private Name name;
    private String address;

    public Person() {
    }

    public Person(Name name, String address) {
        this.name = name;
        this.address = address;
    }

    public Name getName() {
        return name;
    }

    public void setName(Name name) {
        System.out.println("set name field");
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
    
    public void say(){
        System.out.println("say");
    }

}

package org.syna.demo;

import org.corey.demo.IPerson;
import org.corey.demo.Person;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        IPerson person=(IPerson)ac.getBean("proxyBean");
        person.say();
    }
}

console:

set name field
before logging   //这就是切面输出;
say

从上述代码,我们可见,我们主要的应用到了advice,advisor,pointcut,还有ProxyFactoryBean类,proxyFactoryBean继承于FactoryBean接口,这个接口的神奇我们在前一节就已经详细的分析过了,那么,我们就从这个接口来分析一下,我们是怎么从FactoryBean的getObject()方法取得代理对象的,以及这个代理对象是如何生成的;



可见ProxyFactoryBean继承了图示中的几个接口和类,他们分别的作用是

BeanFactoryAware:BeanFactory的回调接口,可以在ProxyFactoryBean类中获取当前BeanFactory;

AdvisedSupportListener是监听ActionSupport的监听接口,是一个监听者;

FactoryBean:如同前一节所解释的;

AdvisedSupport:提供了有关这个代理的一些详细信息:比如当前代理类代理的是那一个类等等;

我们会在ProxyFactoryBean中设置如下几个属性:
1):代理类的实现的接口(可选);
    public void setProxyInterfaces(String[] interfaceNames) throws ClassNotFoundException {
        Class[] interfaces = AopUtils.toInterfaceArray(interfaceNames);
        setInterfaces(interfaces);
    }
2):advisor类的名字,从这个我们可以知道代理规则;    public void setInterceptorNames(String[] interceptorNames) {
        this.interceptorNames = interceptorNames;
    }

3):代理类的名字;
    public void setTargetName(String targetName) {
        this.targetName = targetName;
    }

然后我们来分析一下getObject()方法:
public Object getObject() throws BeansException {
        if (isSingleton()) {
            return getSingletonInstance();
        }
        else {
            if (this.targetName == null) {
                logger.warn("Using non-singleton proxies with singleton targets is often undesirable." +
                        "Enable prototype proxies by setting the 'targetName' property.");
            }
            return newPrototypeInstance();
        }
    }
从这个方法,我们可见,ProxyBeanFactory根据上述信息给我们构造了一个PrototypeInstance();

private synchronized Object newPrototypeInstance() {
        // In the case of a prototype, we need to give the proxy
        // an independent instance of the configuration.
        // In this case, no proxy will have an instance of this object's configuration,
        // but will have an independent copy.
        if (logger.isDebugEnabled()) {
            logger.debug("Creating copy of prototype ProxyFactoryBean config: " + this);
        }

        AdvisedSupport copy = new AdvisedSupport();
        // The copy needs a fresh advisor chain, and a fresh TargetSource.
        TargetSource targetSource = freshTargetSource();
        copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
        if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
            // Rely on AOP infrastructure to tell us what interfaces to proxy.
            copy.setInterfaces(ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass()));
        }
        copy.setFrozen(this.freezeProxy);

        if (logger.isDebugEnabled()) {
            logger.debug("Copy has config: " + copy);
        }
        return getProxy(copy.createAopProxy());
    }
构造proxy对象是有ProxySupport类完成的,他把这个对象委托给了一个AopProxyFactory工厂,而这个理之所有要委托给一个工厂,是因为,生成这个代理类是有选择的:
public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
        if (advisedSupport.isOptimize() || advisedSupport.isProxyTargetClass() ||
            advisedSupport.getProxiedInterfaces().length == 0) {
            if (!cglibAvailable) {
                throw new AopConfigException(
                        "Cannot proxy target class because CGLIB2 is not available. " +
                        "Add CGLIB to the class path or specify proxy interfaces.");
            }
            return CglibProxyFactory.createCglibProxy(advisedSupport);
        }
        else {
            return new JdkDynamicAopProxy(advisedSupport);
        }
    }
这里生成动态代理类有两种方式,一种是如果用户没有给被代理类实现接口,那么,就会使用cglib来生成代理类,如果制定了实现接口,那么就会使用jdk的InvocationHandler接口实现代理;

这个AopProxy类是一个Proxy Object的包装类;

public interface AopProxy {

    /**
     * Create a new proxy object.
     * <p>Uses the most optimal default class loader (if necessary for proxy creation):
     * usually, the thread context class loader.
     * @see java.lang.Thread#getContextClassLoader()
     */
    Object getProxy();

    /**
     * Create a new proxy object.
     * <p>Uses the given class loader (if necessary for proxy creation).
     * <code>null</code> will simply be passed down and thus lead to the low-level
     * proxy facility's default, which is usually different from the default chosen
     * by the AopProxy implementation's <code>getProxy</code> method.
     * @param classLoader the class loader to create the proxy with
     * (or <code>null</code> for the low-level proxy facility's default)
     */
    Object getProxy(ClassLoader classLoader);

}
能够从中得到代理的Object;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息