Spring中用到过的设计模式

  看源码过程中记录一下Spring中用到过的设计模式,当然同样的模式使用的地方会很多,本文只记录自己遇到的代码。

一、模板方法模式

    protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                // We cannot use Profiles.of(...) since profile expressions are not supported
                // in XML config. See SPR-12458 for details.
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                                "] not matching: " + getReaderContext().getResource());
                    }
                    return;
                }
            }
        }

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

  这里是通过XmlBeanFactory加载解析Xml配置文件的核心代码,其中 preProcessXml 和  postProcessXml 方法都是没有任何实现的,就面向对象设计方法学中的一句话:

一个类要么是面向继承的,要么就用final修饰

 这里类 DefaultBeanDefinitionDocumentReader 并不是final的,所以一定是可以继承的,这两个方式正式为了子类而设计的,如果子类需要在Bean解析前后做一些处理的话,直接重写这两个方法即可。

  模板方法模式主要用途在于将不变的行为从子类搬到超类中,去除了子类中重复的代码。定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。

  此模式在平时的项目开发中经常会用到,可能大家并没有注意。在我们想要抽象一些业务逻辑的时候,作为顶层的抽象对象一定要定义一些可供子类来实现的方法,方便子类拓展。在子类中只需要实现个性化的操作,将通用的业务处理逻辑都封装到超类中。

二、工厂模式

  在我们从容器中获取一个Bean的时候通过bean name来获取,在实际获取前会对name进行一次预处理

String beanName = transformedBeanName(name);

  这里是因为在容器中直接存储的对象可能是bean对象本身,也可能是FactoryBean对象,那么这里想要区分一下FactoryBean 和 BeanFatory的区别。

  BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

  FactoryBean以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取。

    /**
     * Return the actual bean name, stripping out the factory dereference
     * prefix (if any, also stripping repeated factory prefixes if found).
     * @param name the name of the bean
     * @return the transformed name
     * @see BeanFactory#FACTORY_BEAN_PREFIX
     */
    public static String transformedBeanName(String name) {
        Assert.notNull(name, "'name' must not be null");
        if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
            return name;
        }
        return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
            do {
                beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
            }
            while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
            return beanName;
        });
    }

  所以可以看到这里会先判断一个name是否为&前缀开头的,同时这里的name还有可能为alias,所以这里的目的就是为了提取到实际存储在容器中的bean name 。

  在单例容器获取对象的时候还会遇到一个对象 : ObjectFactory , 与FactoryBean一样也存在一个getObject() 方法,但是实际上两者之间没有什么必然的联系,FactoryBean接口是我们用来自定义对象实例化的,ObjectFactory只是定义了一个工厂对象,用于获取实际对象的,他们唯一的共同点就是都采用了工厂模式,通过工厂模式返回一个对象。

 

posted @ 2021-09-16 15:07  SyrupzZ  阅读(40)  评论(0)    收藏  举报