Spring 源码阅读 AOP 二

来源:互联网 发布:单片机 http 编辑:程序博客网 时间:2024/05/18 00:15

上一章和各位一起看了一下springAOP的工作流程,当我们给出AOP相关的配置以后,直接从IOC容器中拿出来的就是已经加强过的bean。这说明spring在这个过程中一定做了什么。

                本章我们就一起来看一下spring是如何完成对bean的增强的,首先我们来看一下,FactoryBean接口中一个方法的定义。

复制代码
复制代码
public interface FactoryBean<T> {    /**     * Return an instance (possibly shared or independent) of the object     * managed by this factory.     * <p>As with a {@link BeanFactory}, this allows support for both the     * Singleton and Prototype design pattern.     * <p>If this FactoryBean is not fully initialized yet at the time of     * the call (for example because it is involved in a circular reference),     * throw a corresponding {@link FactoryBeanNotInitializedException}.     * <p>As of Spring 2.0, FactoryBeans are allowed to return <code>null</code>     * objects. The factory will consider this as normal value to be used; it     * will not throw a FactoryBeanNotInitializedException in this case anymore.     * FactoryBean implementations are encouraged to throw     * FactoryBeanNotInitializedException themselves now, as appropriate.     * @return an instance of the bean (can be <code>null</code>)     * @throws Exception in case of creation errors     * @see FactoryBeanNotInitializedException     */    T getObject() throws Exception;
复制代码
复制代码

                 getObject这个方法,就是用来获取被这个factorybean加强后的对象的,上一章测试的过程中,最终就是调用了这个方法,来完成了对bean的加强。我们来跟踪一下上一次测试的代码,看看到底是在什么地方调用的。这里再次贴出来上次测试的代码,方便解释。

复制代码
复制代码
public class TestAOP {    public static void main(String[] args) {        ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");        TestTarget target = (TestTarget) applicationContext.getBean("testAOP");        target.test();        System.out.println("------无敌分割线-----");        target.test2();    }    }
复制代码
复制代码

其实整个过程也就两行代码,第一行代码,是我们对IOC容器的初始化,这时其实并没有发生对bean的增强,原因就是这个时候只是完成了对ProxyFactoryBean的初始化,也就是相当于我们已经new出来了一个ProxyFactoryBean,但是此时并没有调用接口方法,去获得加强后的bean。

         下面我们去跟进第二行获取testAOP的代码,来看一下究竟。首先我们会找到AbstractApplicationContext中的getBean方法,但是这个类并不负责bean的实例化工作,而是交给了bean工厂,我们跟踪bean工厂的方法,能找到上述第二行其实是调用了如下这个方法。

复制代码
复制代码
@SuppressWarnings("unchecked")    protected <T> T doGetBean(            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)            throws BeansException {        final String beanName = transformedBeanName(name);        Object bean;        // Eagerly check singleton cache for manually registered singletons.        Object sharedInstance = getSingleton(beanName);        if (sharedInstance != null && args == null) {            if (logger.isDebugEnabled()) {                if (isSingletonCurrentlyInCreation(beanName)) {                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +                            "' that is not fully initialized yet - a consequence of a circular reference");                }                else {                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");                }            }            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);        }        else {            // Fail if we're already creating this bean instance:            // We're assumably within a circular reference.            if (isPrototypeCurrentlyInCreation(beanName)) {                throw new BeanCurrentlyInCreationException(beanName);            }            // Check if bean definition exists in this factory.            BeanFactory parentBeanFactory = getParentBeanFactory();            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {                // Not found -> check parent.                String nameToLookup = originalBeanName(name);                if (args != null) {                    // Delegation to parent with explicit args.                    return (T) parentBeanFactory.getBean(nameToLookup, args);                }                else {                    // No args -> delegate to standard getBean method.                    return parentBeanFactory.getBean(nameToLookup, requiredType);                }            }            if (!typeCheckOnly) {                markBeanAsCreated(beanName);            }            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);            checkMergedBeanDefinition(mbd, beanName, args);            // Guarantee initialization of beans that the current bean depends on.            String[] dependsOn = mbd.getDependsOn();            if (dependsOn != null) {                for (String dependsOnBean : dependsOn) {                    getBean(dependsOnBean);                    registerDependentBean(dependsOnBean, beanName);                }            }            // Create bean instance.            if (mbd.isSingleton()) {                sharedInstance = getSingleton(beanName, new ObjectFactory() {                    public Object getObject() throws BeansException {                        try {                            return createBean(beanName, mbd, args);                        }                        catch (BeansException ex) {                            // Explicitly remove instance from singleton cache: It might have been put there                            // eagerly by the creation process, to allow for circular reference resolution.                            // Also remove any beans that received a temporary reference to the bean.                            destroySingleton(beanName);                            throw ex;                        }                    }                });                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);            }            else if (mbd.isPrototype()) {                // It's a prototype -> create a new instance.                Object prototypeInstance = null;                try {                    beforePrototypeCreation(beanName);                    prototypeInstance = createBean(beanName, mbd, args);                }                finally {                    afterPrototypeCreation(beanName);                }                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);            }            else {                String scopeName = mbd.getScope();                final Scope scope = this.scopes.get(scopeName);                if (scope == null) {                    throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");                }                try {                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {                        public Object getObject() throws BeansException {                            beforePrototypeCreation(beanName);                            try {                                return createBean(beanName, mbd, args);                            }                            finally {                                afterPrototypeCreation(beanName);                            }                        }                    });                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);                }                catch (IllegalStateException ex) {                    throw new BeanCreationException(beanName,                            "Scope '" + scopeName + "' is not active for the current thread; " +                            "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",                            ex);                }            }        }        // Check if required type matches the type of the actual bean instance.        if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());        }        return (T) bean;    }
复制代码
复制代码

这是一个重载方法,后面三个参数两个为null,一个为false。下面注意,在这面这一行的时候,我们已经获取到了实例。

Object sharedInstance = getSingleton(beanName);

            所以分支在碰到第一个if判断时,会直接进入if块而不是else块,在这里提醒一下,这个是获取的单例的bean实例,而这个sharedInstance并不是TestTarget,而是ProxyFactoryBean的实例。好了,接下来相信你已经明白了,我们该进入getObjectForBeanInstance这个方法了,来看这个方法。

复制代码
复制代码
protected Object getObjectForBeanInstance(            Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {        // Don't let calling code try to dereference the factory if the bean isn't a factory.        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {            throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());        }        // Now we have the bean instance, which may be a normal bean or a FactoryBean.        // If it's a FactoryBean, we use it to create a bean instance, unless the        // caller actually wants a reference to the factory.        if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {            return beanInstance;        }        Object object = null;        if (mbd == null) {            object = getCachedObjectForFactoryBean(beanName);        }        if (object == null) {            // Return bean instance from factory.            FactoryBean factory = (FactoryBean) beanInstance;            // Caches object obtained from FactoryBean if it is a singleton.            if (mbd == null && containsBeanDefinition(beanName)) {                mbd = getMergedLocalBeanDefinition(beanName);            }            boolean synthetic = (mbd != null && mbd.isSynthetic());            object = getObjectFromFactoryBean(factory, beanName, !synthetic);        }        return object;    }
复制代码
复制代码

方法的刚开始是两个卫语句,第一个判断如果是想获得factorybean本身,却又不是factorybean则抛出异常,第二个则是正常的获得factorybean。但是我们都不属于这两种情况。所以在经过getCachedObjectForFactoryBean获取无果和getCachedObjectForFactoryBean获取到bean定义以后,就进入了getObjectFromFactoryBean方法。

复制代码
复制代码
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {        if (factory.isSingleton() && containsSingleton(beanName)) {            synchronized (getSingletonMutex()) {                Object object = this.factoryBeanObjectCache.get(beanName);                if (object == null) {                    object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);                    this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));                }                return (object != NULL_OBJECT ? object : null);            }        }        else {            return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);        }    }
复制代码
复制代码

进入以后,由于proxyFactorybean是单例bean,所以会进入到if块不是else块,接下来系统再次尝试从cache中获得,自然是无果。接下来依然会进入到和else一样的方法doGetObjectFromFactoryBean,先不说这个方法,看后面,获得以后就会放入cache,然后直接将对象返回。所以如果重复调用,下一次就会从cache当中取出来直接返回。好了,接下来我们进去doGetObjectFromFactoryBean方法。

复制代码
复制代码
private Object doGetObjectFromFactoryBean(            final FactoryBean factory, final String beanName, final boolean shouldPostProcess)            throws BeanCreationException {        Object object;        try {            if (System.getSecurityManager() != null) {                AccessControlContext acc = getAccessControlContext();                try {                    object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {                        public Object run() throws Exception {                                return factory.getObject();                            }                        }, acc);                }                catch (PrivilegedActionException pae) {                    throw pae.getException();                }            }            else {                object = factory.getObject();            }        }        catch (FactoryBeanNotInitializedException ex) {            throw new BeanCurrentlyInCreationException(beanName, ex.toString());        }        catch (Throwable ex) {            throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);        }                // Do not accept a null value for a FactoryBean that's not fully        // initialized yet: Many FactoryBeans just return null then.        if (object == null && isSingletonCurrentlyInCreation(beanName)) {            throw new BeanCurrentlyInCreationException(                    beanName, "FactoryBean which is currently in creation returned null from getObject");        }        if (object != null && shouldPostProcess) {            try {                object = postProcessObjectFromFactoryBean(object, beanName);            }            catch (Throwable ex) {                throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex);            }        }        return object;    }
复制代码
复制代码

此处判断了一下当前是否设置了安全管理器,我们并没有设置,所以将直接调用ProxyFactoryBean的getObject方法,也就是对bean增强的地方。下面我们着重来看一下是如何对bean进行增强的。首先我们进入到ProxyFactoryBean的getObject方法来看一下。

复制代码
复制代码
public Object getObject() throws BeansException {        initializeAdvisorChain();        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();        }    }
复制代码
复制代码

此处主要是先初始化了一下通知器链,然后就会根据是否单例做相应的动作,我们看一下初始化通知器链的进行。

复制代码
复制代码
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {        if (this.advisorChainInitialized) {            return;        }        if (!ObjectUtils.isEmpty(this.interceptorNames)) {            if (this.beanFactory == null) {                throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +                        "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));            }            // Globals can't be last unless we specified a targetSource using the property...            if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&                    this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {                throw new AopConfigException("Target required after globals");            }            // Materialize interceptor chain from bean names.            for (String name : this.interceptorNames) {                if (logger.isTraceEnabled()) {                    logger.trace("Configuring advisor or advice '" + name + "'");                }                if (name.endsWith(GLOBAL_SUFFIX)) {                    if (!(this.beanFactory instanceof ListableBeanFactory)) {                        throw new AopConfigException(                                "Can only use global advisors or interceptors with a ListableBeanFactory");                    }                    addGlobalAdvisor((ListableBeanFactory) this.beanFactory,                            name.substring(0, name.length() - GLOBAL_SUFFIX.length()));                }                else {                    // If we get here, we need to add a named interceptor.                    // We must check if it's a singleton or prototype.                    Object advice;                    if (this.singleton || this.beanFactory.isSingleton(name)) {                        // Add the real Advisor/Advice to the chain.                        advice = this.beanFactory.getBean(name);                    }                    else {                        // It's a prototype Advice or Advisor: replace with a prototype.                        // Avoid unnecessary creation of prototype bean just for advisor chain initialization.                        advice = new PrototypePlaceholderAdvisor(name);                    }                    addAdvisorOnChainCreation(advice, name);                }            }        }        this.advisorChainInitialized = true;    }
复制代码
复制代码

可以看到,其中针对我们配置的interpretorNames进行了循环,我们并非是配置的全局通知器,所以会进入else块,然后因为我们配置的testAdvisor默认是单例的,所以会从bean工厂中去获取这个实例,此时TestAdvisor已经实例化完成的,我们只是去取一下而已。然后就会进入addAdvisorOnChainCreation方法。这个方法不再一一贴进来,各位有兴趣的可以自己去看一下,就是把通知器加到了通知链当中。

              值得注意的是在这个过程中,触发了一个这样的方法this.advisorAdapterRegistry.wrap(next)。这个方法就是用来包装通知器的,如果不是advisor而是advice,就会包装一下返回。

              好了,接着刚才的过程,初始化通知器链完成以后,就会进入getSingletonInstance方法,这是用来获取单例实例的,而真正的加强也是在这里发生的,我们来看一下。

复制代码
复制代码
private synchronized Object getSingletonInstance() {        if (this.singletonInstance == null) {            this.targetSource = freshTargetSource();            if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {                // Rely on AOP infrastructure to tell us what interfaces to proxy.                Class targetClass = getTargetClass();                if (targetClass == null) {                    throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");                }                setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));            }            // Initialize the shared singleton instance.            super.setFrozen(this.freezeProxy);            this.singletonInstance = getProxy(createAopProxy());        }        return this.singletonInstance;    }
复制代码
复制代码

此时第一次获取,单例实例为null,所以会进入if块,首先刷新targetSource,因为我们的Target类没有实现targetSource接口,所以会由spring帮我们产生一个targetSource适配,这里是使用的适配器的模式,有兴趣可以进去看一下,我们此处不关注这个。接下来,会去判断代理接口,并且设置代理接口,但是我们的target未实现任何接口,所以此处interfaces仍然为空的,所以最后一步createAopProxy时,会帮我们创建cglib的proxy。最终由cglib生成代理返回。

执行下国际惯例,说完以后总要稍微总结一下,主要说几点:

1.在IOC容器初始化的过程中,并没有发生增强的动作,而是初始化了proxyFactoryBean。

2.如果配置中不指定,所有bean默认都是单例和非延迟加载的,也就是说所有的bean都将在第一次IOC容器初始化时全部实例化,所以上一章中所配置的三个bean都是在IOC容器初始化时进行的实例化。

3.springAOP代理有两种方式,一种是JDK提供的动态代理,一种是cglib字节码生成的技术,当要代理的类有实现的接口的时候,就会针对接口进行代理,否则就会采用cglib直接生成字节码产生子类。

针对2种代理方式 分别做了如下例子:

package com.chen.aop;import java.lang.reflect.Method;import com.chen.service.imp.PersonServiceImpl;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class CGlibProxy implements MethodInterceptor{    private Object targetObject;    @Overridepublic Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodproxy) throws Throwable {PersonServiceImpl psimpl = (PersonServiceImpl) this.targetObject;if(null==psimpl.getUser()){return null;}Object result = method.invoke(targetObject, args);return result;}public Object createProxyObject(Object targetobj){this.targetObject=targetobj;Enhancer  enhancer  = new Enhancer();enhancer.setSuperclass(this.targetObject.getClass());enhancer.setCallback(this);return enhancer.create();}}

2、
package com.chen.aop;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import com.chen.service.imp.PersonServiceImpl;/** * 当目标对象实现接口时用jdk代理 * 如果目标对象没有实现接口 ,则用cglib实现代理 * @author Administrator * */public class JDKProxyFactory implements InvocationHandler {private Object targetobj;public Object createProxyInstance(Object targetObject){this.targetobj=targetObject;return Proxy.newProxyInstance(this.getClass().getClassLoader(), this.targetobj.getClass().getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("************进入invoke");PersonServiceImpl psimpl = (PersonServiceImpl) this.targetobj;if(psimpl.getUser()==null||psimpl.getUser().equals("")){return null;}Object result = method.invoke(targetobj, args);//目标让代理去执行,需要给代理盖章。System.out.println("************退出invoke");return result;}}
总结:

/**
 * 当目标对象实现接口时用jdk代理
 * 如果目标对象没有实现接口 ,则用cglib实现代理
 * @author cj
 */

0 0