由Spring框架中的单例模式想到的

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例

注:Spring源码的版本4.3.4

Spring依赖注入Bean实例默认是单例的,我们由此展开。

Spring的依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean里。getBean的doGetBean方法调用getSingleton进行bean的创建。lazy-init方式,在容器初始化时候进行调用,非lazy-init方式,在用户向容器第一次索要bean时进行调用

同步线程安全的单例核心代码:

/**
     * Return the (raw) singleton object registered under the given name.
     * <p>Checks already instantiated singletons and also allows for an early
     * reference to a currently created singleton (resolving a circular reference).
     * @param beanName the name of the bean to look for
     * @param allowEarlyReference whether early references should be created or not
     * @return the registered singleton object, or {@code null} if none found
     */
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

 

从上面代码可以看到,spring依赖注入时,使用了双重判断加锁的单例模式,首先从缓存中获取bean实例,如果为null,对缓存map加锁,然后再从缓存中获取bean,如果继续为null,就创建一个bean。这样双重判断,能够避免在加锁的瞬间,有其他依赖注入引发bean实例的创建,从而造成重复创建的结果。

    在这里Spring并没有使用私有构造方法来创建bean,而是通过singletonFactory.getObject()返回具体beanName对应的ObjectFactory来创建bean。我们一路跟踪下去,发现实际上是调用了AbstractAutowireCapableBeanFactory的doCreateBean方法,返回了BeanWrapper包装并创建的bean实例。

ObjectFactory主要检查是否有用户定义的BeanPostProcessor后处理内容,并在创建bean时进行处理,如果没有,就直接返回bean本身)

见如下代码:

512行创建bean实例返回给BeanWrapper

540addSingletonFactory增加beanName和ObjectFactory的键值对应关系。

 

    /**
     * Actually create the specified bean. Pre-creation processing has already happened
     * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
     * <p>Differentiates between default bean instantiation, use of a
     * factory method, and autowiring a constructor.
     * @param beanName the name of the bean
     * @param mbd the merged bean definition for the bean
     * @param args explicit arguments to use for constructor or factory method invocation
     * @return a new instance of the bean
     * @throws BeanCreationException if the bean could not be created
     * @see #instantiateBean
     * @see #instantiateUsingFactoryMethod
     * @see #autowireConstructor
     */
    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            instanceWrapper = createBeanInstance(beanName, mbd, args);
        }
        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
        Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

        // Allow post-processors to modify the merged bean definition.
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                isSingletonCurrentlyInCreation(beanName));
        if (earlySingletonExposure) {
            if (logger.isDebugEnabled()) {
                logger.debug("Eagerly caching bean '" + beanName +
                        "' to allow for resolving potential circular references");
            }
            addSingletonFactory(beanName, new ObjectFactory<Object>() {
                @Override
                public Object getObject() throws BeansException {
                    return getEarlyBeanReference(beanName, mbd, bean);
                }
            });
        }

 

getEarlyBeanReference获取bean的所有后处理器,并进行处理。如果是SmartInstantiationAwareBeanPostProcessor类型,就进行处理,如果没有相关处理内容,就返回默认的实现。

 

    /**
     * Obtain a reference for early access to the specified bean,
     * typically for the purpose of resolving a circular reference.
     * @param beanName the name of the bean (for error handling purposes)
     * @param mbd the merged bean definition for the bean
     * @param bean the raw bean instance
     * @return the object to expose as bean reference
     */
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    if (exposedObject == null) {
                        return null;
                    }
                }
            }
        }
        return exposedObject;
    }

 

彩蛋在此:

各种单例实现方式(5种):懒汉模式,饿汉线程非安全模式,饿汉线程安全模式,内部类模式,枚举模式。现在最推荐的方式是枚举单例模式。对这些模式的描述和介绍,请仔细看代码中的注释,会有意想不到的收获呦!

 

package com.xhengxuyuanzhi;

/**
* @author 微信公众号:程序员之路
 *                  博客:http://www.cnblogs.com/chengxuyuanzhilu/
 * 
 * 饿汉式单例模式
 * 特点:可以通过反射机制攻击;线程安全[多个类加载器除外]。
 */
public class HungryType {
    public static final HungryType instance = new HungryType();
    
    private HungryType(){
        //初始化HungryType要做的事
    }
    
    public void splitAlipay() {
        System.out.println("饿汉式单利模式");
    }
    
    public static void main(String[] args) {
        HungryType ht =    HungryType.instance;
        ht.splitAlipay();
        
    }
}
package com.xhengxuyuanzhi;

/**
 * @author 微信公众号:程序员之路
 *                  博客:http://www.cnblogs.com/chengxuyuanzhilu/
 * 
 * 懒汉模式单例
 * 特点:延时加载;线程不安全,多线程下不能正常工作;
 */
public class SluggardType {
    private static SluggardType instance = null;
    
    private SluggardType() {
    
    }
    
    public static SluggardType getInstance(){
        if(instance == null){
            instance = new SluggardType();
        }
        return instance;
    }
    
    public void say(){
        System.out.println("懒汉模式单例");
    }
    
    public static void main(String[] args) {
        SluggardType.getInstance().say();
    }
}
package com.xhengxuyuanzhi;

/**
 * @author 微信公众号:程序员之路
 *                  博客:http://www.cnblogs.com/chengxuyuanzhilu/
 * 
 * 懒汉模式(双重校验锁[不推荐])单例
 */
public class SluggardType2 {
    
    //volatile 关键字可以禁止指令重排 :可以确保instance = new SluggardType2()对应的指令不会重排序
    //但是因为对volatile的操作都在Main Memory中,而Main Memory是被所有线程所共享的,这里的代价就是牺牲了性能,无法利用寄存器或Cache
    private volatile static SluggardType2 instance = null;
    
    private SluggardType2(){
        
    }
    
    public static SluggardType2 getInstance(){
        if(instance == null){
            synchronized (SluggardType2.class) {
                if(instance == null){
                    instance = new SluggardType2();
                }
            }
        }
        
        return instance;
    }
    
    public void say(){
        System.out.println(" 懒汉模式(双重校验锁[不推荐])单例");
    }
    
    public static void main(String[] args) {
        SluggardType2.getInstance().say();
    }
    
    
}
package com.xhengxuyuanzhi;

/**
 * @author 微信公众号:程序员之路 
 *         博客:http://www.cnblogs.com/chengxuyuanzhilu/
 * 
 * 借助内部类实现单利模式:
 * 特点:既能实现延迟加载,又能实现线程安全
 */
public class InnerClassSingleton {
    /**
     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例没有绑定关系,而且只有被调用到时才会装载(装在过程是由jvm保证线程安全)
     * ,从而实现了延迟加载
     */
    private static class SingletonHolder {
        /**
         * 静态初始化器,由JVM来保证线程安全
         */
        private static InnerClassSingleton instance = new InnerClassSingleton();
    }

    /**
     * 私有化构造方法
     */
    private InnerClassSingleton() {
    }

    /**
     * 这个模式的优势在于:getInstance方法并没有被同步,并且只是执行一个域的访问,因此延迟初始化并没有增加任何访问成本
     */
    public static InnerClassSingleton getInstance() {
        return SingletonHolder.instance;
    }

}
package com.xhengxuyuanzhi;

/**
 * @author 微信公众号:程序员之路 
 *             博客:http://www.cnblogs.com/chengxuyuanzhilu/
 *
 * 枚举实现线程安全的单例模式:
 * 特点:JVM会保证enum不能被反射并且构造器方法只执行一次
 * 
 */
public class EnumSingleton {
    private EnumSingleton() {
    }

    public static EnumSingleton getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    private static enum Singleton {
        INSTANCE;

        private EnumSingleton singleton;

        // JVM会保证此方法绝对只调用一次
        private Singleton() {
            singleton = new EnumSingleton();
        }

        public EnumSingleton getInstance() {
            return singleton;
        }
    }
}
posted @ 2017-02-16 11:45  RedAnts  阅读(15970)  评论(0编辑  收藏  举报