Spring中的策略模式简单实现与使用分析

 更新时间:2024年01月05日 08:47:59   作者:it_lihongmin  
这篇文章主要介绍了Spring中的策略模式简单实现与使用分析,去初始化时除了 initMultipartResolver(上传文件)没有获取 Properties defaultStrategies;默认策略,其他的八大件都会使用到策略模式,需要的朋友可以参考下

一、策略模式

策略模式的网上一搜索就会出现很多的说明,并且大多数的例子基本都来自《Head First设计模式》《大话设计模式》等,并且过于文字化的介绍总是让本来简单的事情更加复杂化。

所以还是直接上demo,方便理解。Head First上的策略模式例子稍微复杂一些,代码比较多就不进行展示了

这里可以写一个最简单的策略模式,也可以理解为Java多态。

1、 创建一个策略抽象

public abstract class AbstractStrategy {
 
    /**
     *  抽象的策略接口
     */
    abstract void algorithm();
}

2、策略的N中实现

public class StrategyImplOne extends AbstractStrategy {
    @Override
    void algorithm() {
        System.out.println("我实现了策略(一)的方法!!!");
    }
}
public class StrategyImplTwo extends AbstractStrategy {
 
    @Override
    void algorithm() {
        System.out.println("我实现了策略(二)的方法!!!");
    }
}

3、为策略的调用创建一个触发容器(方法调用触发)

public class Context {
 
    private AbstractStrategy strategy;
 
    public Context(AbstractStrategy strategy) {
        this.strategy = strategy;
    }
 
    /**
     *  触发策略执行
     */
    public void strategyImpl() {
        strategy.algorithm();
    }
}

4、测试简单的策略模式

public class StrategyTest {
    public static void main(String[] args) {
        // 执行策略一
        new Context(new StrategyImplOne()).strategyImpl();
        // 执行策略二
        new Context(new StrategyImplTwo()).strategyImpl();
    }
}

5、查看结果

我实现了策略(一)的方法!!!

我实现了策略(二)的方法!!!

二、Spring中的策略模式

当我们看完上一个策略模式的demo的时候发现并没有什么用,或者我不知道自己在项目里面怎么进行使用,所以可以看看别人的框架是怎么使用的,或者说看看好的源码中是怎么使用的。

1、Spring MVC中 DispatcherServlet 使用策略模式

DispatcherServlet在进行转发前需要进行传说中的九大件的初始化,其中去初始化时除了initMultipartResolver(上传文件)没有获取Properties defaultStrategies;默认策略,其他的八大件都会使用到策略模式。

先看一下defaultStrategies为 java.util.Properties类型,定义如下:

public class Properties extends Hashtable<Object, Object> {
    // ***
}

流程梳理:

1、当Web容器启动时,ServletWebServerApplicationContext初始化会调用其refresh()方法,则会调用 DispatcherServlet的onRefresh方法

2、onRefresh方法 - >initStrategies方法 -> 初始化九大件

3、初始化时则会调用getDefaultStrategy方法。如下:

4、getDefaultStrategy实现,就是去调用了Properties这个Hashtable的key对应的value值,如下:

protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
        List<T> strategies = this.getDefaultStrategies(context, strategyInterface);
        if (strategies.size() != 1) {
            throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
        } else {
            return strategies.get(0);
        }
    }
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        String key = strategyInterface.getName();
        String value = defaultStrategies.getProperty(key);
        if (value == null) {
            return new LinkedList();
        } else {
            String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
            List<T> strategies = new ArrayList(classNames.length);
            String[] var7 = classNames;
            int var8 = classNames.length;
 
            for(int var9 = 0; var9 < var8; ++var9) {
                String className = var7[var9];
 
                try {
                    Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
                    Object strategy = this.createDefaultStrategy(context, clazz);
                    strategies.add(strategy);
                } catch (ClassNotFoundException var13) {
                    throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var13);
                } catch (LinkageError var14) {
                    throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" + className + "] for interface [" + key + "]", var14);
                }
            }
 
            return strategies;
        }
    }

5、那么Properties的值在哪里添加进去的呢,DispatcherServlet 的static静态代码块中会看见,是用Spring的Resource将配置文件中的配置加载,设置到这个Map容器中的,如下:

static {
        try {
            ClassPathResource resource = new ClassPathResource("DispatcherServlet.properties", DispatcherServlet.class);
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException var1) {
            throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + var1.getMessage());
        }
    }

6、在看看 DispatcherServlet.properties 配置就明白了,就是九大件没传时的默认值,其实也可以考虑用SPI机制实现(记得之前好像是不是有版本就是用SPI实现的)。

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

总结

web容器启动,ServletWebServerApplicationContext的refresh方法间接调用到 DispatcherServlet的初始九大件方法, 其中八大件在没有自定义实现的情况下,调用默认的 配置。

而默认配置则是在 DispatcherServlet的静态代码块中,由Spring的ClassPathResource将配置文件DispatcherServlet.properties中的配置加载进一个 Map容器中。

只待初始化九大件时,根据不同的九大件类型作为key,调用相应的实现。

到此这篇关于Spring中的策略模式简单实现与使用分析的文章就介绍到这了,更多相关Spring策略模式简单实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决安装mysqlclient的时候出现Microsoft Visual C++ 14.0 is required报错

    解决安装mysqlclient的时候出现Microsoft Visual C++ 14.0 is required报错

    这篇文章主要介绍了解决安装mysqlclient的时候出现Microsoft Visual C++ 14.0 is required报错问题,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11
  • MyBatisPlus之id生成策略的方法

    MyBatisPlus之id生成策略的方法

    本文主要介绍了MyBatisPlus之id生成策略的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • MyBatis中传入参数parameterType类型详解

    MyBatis中传入参数parameterType类型详解

    这篇文章主要给大家介绍了关于MyBatis中传入参数parameterType类型的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2018-04-04
  • Spring MVC中的拦截器案例演示

    Spring MVC中的拦截器案例演示

    拦截器可以拦截所有的请求,也可以只拦截满足指定的请求, Spring MVC 的拦截器类似于过滤器,用来执行预处理和后处理操作,本文给大家介绍Spring MVC中的拦截器案例演示,感兴趣的朋友跟随小编一起看看吧
    2023-10-10
  • Java向Runnable线程传递参数方法实例解析

    Java向Runnable线程传递参数方法实例解析

    这篇文章主要介绍了Java向Runnable线程传递参数方法实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • mybatis TypeHandler注入spring的依赖方式

    mybatis TypeHandler注入spring的依赖方式

    这篇文章主要介绍了mybatis TypeHandler注入spring的依赖方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java中@DateTimeFormat注解与@JsonFormat注解的使用方式

    Java中@DateTimeFormat注解与@JsonFormat注解的使用方式

    这篇文章主要介绍了Java中@DateTimeFormat注解与@JsonFormat注解的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • Java虚拟机JVM优化实战的过程全记录

    Java虚拟机JVM优化实战的过程全记录

    有人说Java之所以能够崛起,JVM功不可没。Java虚拟机最初服务于让Java语言凌驾于平台之上,实现“编写一次,到处运行”,那么下面这篇文章主要给大家分享了个关于Java虚拟机JVM优化实战的过程全记录,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • Spring BeanFactory容器的构建和使用示例详解

    Spring BeanFactory容器的构建和使用示例详解

    BeanFactory是Spring框架中的一部分,它提供了IoC(控制反转)的实现机制,下面小编就来和大家简单聊聊BeanFactory容器的构建和使用示例吧
    2023-07-07
  • Java如何获取Date的“昨天”与“明天”示例代码

    Java如何获取Date的“昨天”与“明天”示例代码

    最近在做项目的时候用到Date和Calendar比较多,而且用到的方式也比较全,突然想到一个问题,Java如何获取Date的"昨天"与"明天",也就是前一天和后一天呢?思考后写出了方法,想着万一以后用到,就总结出来,也方便有需要的朋友们参考借鉴,下面来一起看看吧。
    2016-12-12

最新评论