天天看点

Spring系列--spring IOC用到的设计模式前言叙述

文章目录

  • 前言
  • 叙述
    • 工厂模式
    • 单例模式
    • 策略模式
    • 装饰者模式

前言

Spring作为一款及其优秀的框架,其代码的编写非常优秀,里面采用了大量的设计模式。

叙述

Spring IOC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。IOC 容器负责创建对象,将对象连接在一起,配置这些对象,并从创建中处理这些对象的整个生命周期,直到它们被完全销毁。

工厂模式

Spring使用工厂模式可以通过 BeanFactory 或 ApplicationContext 创建 bean 对象。

两者对比:

  • BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext 来说会占用更少的内存,程序启动速度更快。
  • ApplicationContext :容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。

Spring 实现单例的方式:

ApplicationContext的三个实现类:

ClassPathXmlApplication:把上下文文件当成类路径资源。

FileSystemXmlApplication:从文件系统中的 XML 文件载入上下文定义信息。

XmlWebApplicationContext:从Web系统中的XML文件载入上下文定义信息。

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
 
public class App {
	public static void main(String[] args) {
		ApplicationContext context = new FileSystemXmlApplicationContext(
				"C:/work/IOC Containers/springframework.applicationcontext/src/main/resources/bean-factory-config.xml");
 
		HelloApplicationContext obj = (HelloApplicationContext) context.getBean("helloApplicationContext");
		obj.getMsg();
	}
}

           

单例模式

Spring 中 bean 的默认作用域就是 singleton(单例)的。

Spring 实现单例的方式:

xml : <bean id="userService" class="top.snailclimb.UserService" scope="singleton"/>
注解:@Scope(value = "singleton")
           

Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。Spring 实现单例的核心代码如下

// 通过 ConcurrentHashMap(线程安全) 实现单例注册表
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
        synchronized (this.singletonObjects) {
            // 检查缓存中是否存在实例  
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                //...省略了很多代码
                try {
                    singletonObject = singletonFactory.getObject();
                }
                //...省略了很多代码
                // 如果实例对象在不存在,我们注册到单例注册表中。
                addSingleton(beanName, singletonObject);
            }
            return (singletonObject != NULL_OBJECT ? singletonObject : null);
        }
    }
    //将对象添加到单例注册表
    protected void addSingleton(String beanName, Object singletonObject) {
            synchronized (this.singletonObjects) {
                this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));

            }
        }
}

           

策略模式

在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。策略模式实际就是一堆算法族的封装。

Spring中策略模式的应用

当bean需要访问资源配置文件时,Spring有两种方式

  • 代码中获取Rescource实例
  • 依赖注入

第一种方式需要获取rescource资源的位置,代码中耦合性太高,而今我们一直使用注解,依赖注入的方式去获取。这样的话就无需修改程序,只改配置文件即可。

<beans> 
   <bean id="test" class="com.example.Test"> 
   <!-- 注入资源 --> 
      <property name="tmp" value="classpath:book.xml"/>
   </bean> 
</beans>
           

在依赖注入的过程中,Spring会调用ApplicationContext 来获取Resource的实例。然而,Resource 接口封装了各种可能的资源类型,包括了:UrlResource,ClassPathResource,FileSystemResource等,Spring需要针对不同的资源采取不同的访问策略。在这里,Spring让ApplicationContext成为了资源访问策略的“决策者”。在资源访问策略的选择上,Spring采用了策略模式。当 Spring 应用需要进行资源访问时,它并不需要直接使用 Resource 实现类,而是调用 ApplicationContext 实例的 getResource() 方法来获得资源,ApplicationContext 将会负责选择 Resource 的实现类,也就是确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来。

ApplicationContext ctx = new Class PathXmlApplicationContext("bean.xml");
Resource res = ctx.getResource("book.xml");
           

上面的代码中,Spring 将采用和 ApplicationContext 相同的策略来访问资源。即: ApplicationContext 是 ClassPathXmlApplicationContext,则res 就是 ClassPathResource 实例。若将代码改为:

ApplicationContext ctx = new Class FileSystemXmlApplicationContext("bean.xml");
           

则再次调用ctx.getResource时,res 就是 ClassPathResource 实例。

装饰者模式

通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。

Spring中装饰器模式的使用

Spring中类中带有Wrapper的都是包装类,如下创建bean就是典型的装饰器模式

BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
    //根据指定的bean使用对应的侧脸创建新的实例,如工厂方法,构造函数自动注入,简单初始化
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
if (beanType != 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;
        }
    }
}

           

参考链接: https://www.jianshu.com/p/139f813fca80

感谢您的阅读~~

继续阅读