Spring中的策略模式简单实现与使用分析
作者:it_lihongmin
一、策略模式
策略模式的网上一搜索就会出现很多的说明,并且大多数的例子基本都来自《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策略模式简单实现内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
