在前面中,我们知道如果一个bean需要被加载,首先需要获取资源的位置,然后根据资源位置获取xml文件,然后将其变成document,然后根据document对元素进行解析,然后放入beanDefintionMap中,然后通过getBean获取bean,而这个过程是bean加载的过程。而这里关注的重点是doGetBean。
public class BeanFactoryTest { public static void main(String[] args) { //获取xml资源 Resource resource = new ClassPathResource("spring-factory.xml"); //获取bean工厂 BeanFactory beanFactory = new XmlBeanFactory(resource); //获取bean Product car1 = (Product) beanFactory.getBean("car"); Product car2 = (Product) beanFactory.getBean("car"); car1.show(); System.out.println(car1 == car2); } }
在getBean中,在这个过程中,首先会将bean进行转换,然后执行获取单例对象操作,然后执行后续操作。而获取单例的过程是值得我们学习的。
AbstractBeanFactory#doGetBean
Object sharedInstance = getSingleton(beanName);
获取单例对象:采用的是单例模式,这里采用双重校验double check。
/** * 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 */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { //获取单例bean对象 Object singletonObject = this.singletonObjects.get(beanName); //如果单例bean对象为空,同时当前被创建对象,则首先对单例对象进行锁定,进行再一次判空,然后进行获取 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; }
单例模式的创建过程:首先定义类,在类的基础上定义对象,提供空参构造函数,然后基于对象创建一个方法获取单例对象,而为了防止获取单例对象出现并发问题,需要对获取的单例对象进行double check,同时定义的对象为了防止出现指令重排的问题,需要加内存屏障,因此可以加volitale进行修饰。
常见的单例模式中:
饿汉式:
/** * 获取单例对象 */ public class Singleton { //创建对象 private static Singleton instance = new Singleton(); //提供空参构造 private Singleton() { } //返回对象 public static Singleton getInstance() { return instance; } }
懒汉式:
/** * 获取单例对象 */ public class Singgleton { //创建对象 private static Singgleton singleton = null; //提供空参构造函数 private Singgleton(){}; //静态工厂方法 public static Singgleton getSingleton(){ if(singleton==null){ singleton = new Singgleton(); } return singleton; } }
使用双重校验:
/** * 创建单例对象 双重校验 */ public class Singleton1 { //定义对象 private static Singleton1 singleton = null; //提供空参构造 private Singleton1(){} //使用双重校验锁 double check,返回创建对象 public static Singleton1 getSingleton(){ if(singleton==null){ synchronized (Singleton1.class){ if(singleton==null) { singleton = new Singleton1(); } } } return singleton; } }
但是采用双重校验还是会存在指令重排的问题,而解决指令重排的问题,则可以采用内存屏障解决这个问题,此时可以借助volitale来解决这个问题,因为内存屏障是在读和写中加入屏障,从而避免其指令重排,从而解决指令重排的问题。
public class Single { private static volatile Single singleStance = null; private Single(){ System.out.println("Single 的构造方法被执行了!!!"); } //DCL: double check lock 双端检索机制 public static Single getSingleStance() { if (singleStance == null) { synchronized (Single.class) { if (singleStance == null) { singleStance = new Single(); } } } return singleStance; } }
除了上面的,还有一个effective java作者推荐的单例模式,枚举:
public class Singleton{ // 私有构造函数 private Singleton() {} public static Singleton getInstance() { return Singleton.INSTANCE.getInstance(); } private enum Singleton { INSTANCE; private Singleton singleton; // JVM保证这个方法绝对只调用一次 Singleton() { singleton = new Singleton(); } public Singleton getInstance() { return singleton; } } }
单例模式的使用场景:
1.Web应用的配置对象的读取,一般也应用单例模式,这个是由于配置文件是共享的资源。 2.应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。 3.数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源 4.多线程的线程池的设计一般也是采用单例模式,这是由于线程池要方便对池中的线程进行控制 5.spring的bean默认也是单例模式,springMVC是单例模式 6.mysql,redis等的连接对象使用单例模式
当然除了我们看到的上面的获取单例的方法,其实在spring的源码中,我们还可以看到一个增强版的获取单例的方法,这个getSingleton方法除了dubbo check之外,还在其前后做了后置处理的增强:
/** * Return the (raw) singleton object registered under the given name, * creating and registering a new one if none registered yet. * @param beanName the name of the bean * @param singletonFactory the ObjectFactory to lazily create the singleton * with, if necessary * @return the registered singleton object */ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } //单例对象创建前的操作 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } //单例对象创建后的处理 afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
单例模式的使用场景可以在dubbo中可以看到应用:
ServiceClassPostProcessor#resolveBeanNameGenerator
/** * It'd better to use BeanNameGenerator instance that should reference * {@link ConfigurationClassPostProcessor#componentScanBeanNameGenerator}, * thus it maybe a potential problem on bean name generation. * * @param registry {@link BeanDefinitionRegistry} * @return {@link BeanNameGenerator} instance * @see SingletonBeanRegistry * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions * @since 2.5.8 */ private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) { BeanNameGenerator beanNameGenerator = null; if (registry instanceof SingletonBeanRegistry) { SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry); beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); } if (beanNameGenerator == null) { if (logger.isInfoEnabled()) { logger.info("BeanNameGenerator bean can't be found in BeanFactory with name [" + CONFIGURATION_BEAN_NAME_GENERATOR + "]"); logger.info("BeanNameGenerator will be a instance of " + AnnotationBeanNameGenerator.class.getName() + " , it maybe a potential problem on bean name generation."); } beanNameGenerator = new AnnotationBeanNameGenerator(); } return beanNameGenerator; }
对于设计模式中的应用,前面我们看到的观察者模式同样也在dubbo中得到了使用。在之前的dubbo版本中,使用的是自定义标签的方式进行的bean注入。
在dubbo的2.7版本中,我们可以看到dubbo的版本是基于spring的事件进行bean的初始化操作的,采用的观察者模式实现的:applicationEventPublisher.publishEvent(exportEvent)。
/** * ServiceFactoryBean * * @export */ public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, BeanNameAware, ApplicationEventPublisherAware { private static final long serialVersionUID = 213195494150089726L; private final transient Service service; private transient ApplicationContext applicationContext; private transient String beanName; private ApplicationEventPublisher applicationEventPublisher; public ServiceBean() { super(); this.service = null; } public ServiceBean(Service service) { super(service); this.service = service; } @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; SpringExtensionFactory.addApplicationContext(applicationContext); } @Override public void setBeanName(String name) { this.beanName = name; } /** * Gets associated {@link Service} * * @return associated {@link Service} */ public Service getService() { return service; } @Override public void afterPropertiesSet() throws Exception { if (StringUtils.isEmpty(getPath())) { if (StringUtils.isNotEmpty(getInterface())) { setPath(getInterface()); } } } /** * Get the name of {@link ServiceBean} * * @return {@link ServiceBean}'s name * @since 2.6.5 */ @Parameter(excluded = true) public String getBeanName() { return this.beanName; } /** * @since 2.6.5 */ @Override public void exported() { super.exported(); // Publish ServiceBeanExportedEvent publishExportEvent(); } /** * @since 2.6.5 */ private void publishExportEvent() { ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this); applicationEventPublisher.publishEvent(exportEvent); } @Override public void destroy() throws Exception { // no need to call unexport() here, see // org.apache.dubbo.config.spring.extension.SpringExtensionFactory.ShutdownHookListener } // merged from dubbox @Override protected Class getServiceClass(T ref) { if (AopUtils.isAopProxy(ref)) { return AopUtils.getTargetClass(ref); } return super.getServiceClass(ref); } /** * @param applicationEventPublisher * @since 2.6.5 */ @Override public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } }
本文分享自微信公众号 - 后端技术学习(gh_9f5627e6cc61),作者:路行的亚洲
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2020-11-28
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句