炫技?No? only 策略模式

简介: Autowire作用于方法时Spring会先实例化所有Bean,然后根据配置进行扫描,当检测到@Autowired后进行注入,注入时调用这个方法,也就是当启动完容器,map已经存放了实体类映射关系。

欢迎点击头像进入主页查看更多内容....

当业务场景中出现类似支付的不同支付方式,登录的不同策略等场景时,业务代码根据选项的不同选择不同的实现类实例进行调用,即动态绑定。

SpringFactoriesLoader
SpringFactoriesLoader类的主要作用是通过类路径下的META-INF/spring.factories文件获取工厂类接口的实现类。

源码:

public final class SpringFactoriesLoader {

  /**
   * The location to look for factories.
   * <p>Can be present in multiple JAR files.
   */
  public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";


  private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);

  private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap<>();


  private SpringFactoriesLoader() {
  }
  private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
      return result;
    }

    try {
      Enumeration<URL> urls = (classLoader != null ?
          classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
          ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      result = new LinkedMultiValueMap<>();
      while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        UrlResource resource = new UrlResource(url);
        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
        for (Map.Entry<?, ?> entry : properties.entrySet()) {
          String factoryTypeName = ((String) entry.getKey()).trim();
          for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
            result.add(factoryTypeName, factoryImplementationName.trim());
          }
        }
      }
      cache.put(classLoader, result);
      return result;
    }
    catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
          FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
  }

书写接口:

public interface DynamicBind {
        void  sayHello();
}

书写不同实现类:

public class Iroman implements DynamicBind {
    @Override
    public void sayHello() {
        System.out.println("I i'm  Iroman");
    }
}
public class SpiderMan implements DynamicBind {
    @Override
    public void sayHello() {
        System.out.println("I i'm  SpiderMan");
    }
}

在spring.factories配置实现类,k是接口的全限定类名,v是实现类

com.springcloud.service.DynamicBind=com.springcloud.service.impl.Iroman,com.atguigu.springcloud.service.impl.SpiderMan

测试类:

public static void main(String[] args) {
        List<DynamicBind> dynamicBinds = SpringFactoriesLoader.loadFactories(DynamicBind.class, ClassUtils.getDefaultClassLoader());
        for (DynamicBind dynamicBind : dynamicBinds) {
            dynamicBind.sayHello();
        }
    }

输出:

I i'm  Iroman
I i'm  SpiderMan

Dubbo SPI

SPI即service provider interface,是在运行动态替换发现的机制,标识接口为@SPI

@SPI
public interface DynamicBindService {
    void  sayHello();
}

public class SpiderMan implements DynamicBindService {
    @Override
    public void sayHello() {
        System.out.println("Dubbo I I'm SpiderMan");
    }
}
public class Iroman implements DynamicBindService {
    @Override
    public void sayHello() {
        System.out.println("Dubbo I I'm Iroman");
    }
}

仍要在配置文件中指定:

Iroman=org.apache.dubbo.demo.provider.Service.Impl.Iroman
SpiderMan=org.apache.dubbo.demo.provider.Service.Impl.SpiderMan

测试类:

 public static void main(String[] args) {
        ExtensionLoader<DynamicBindService> extensionLoader =
                ExtensionLoader.getExtensionLoader(DynamicBindService.class);
        DynamicBindService iroman = extensionLoader.getExtension("Iroman");
        DynamicBindService spiderMan = extensionLoader.getExtension("SpiderMan");
        iroman.sayHello();
        spiderMan.sayHello();
    }

以上两种方法全部需要在配置文件中配置,如果需要添加新的还要改动配置文件,且SPI局限于Dubbo框架。

枚举动态绑定

根据参数或者URL提前绑定与实现类的关系,从而决定不同参数调用不同实现类。

@Getter
@AllArgsConstructor
public enum DynamicStrategyEnum {

    蜘蛛侠(DynamicEnum.蜘蛛侠.getCode(), Iroman.class),

    钢铁侠(DynamicEnum.钢铁侠.getCode(), SpiderMan.class),

    美队(DynamicEnum.美队.getCode(), CaptainAmerica.class);

    private String whoImI;

    private Class<? extends DynamicBind> clazz;

    public static Class<? extends DynamicBind> getClazz(String param) {
        if (StringUtils.isEmpty(param)) {
            throw new NullPointerException("param is null");
        } else {
            for (DynamicStrategyEnum strategyEnum : DynamicStrategyEnum.values()) {
                if (strategyEnum.getWhoImI().equals(param)) {
                    return strategyEnum.getClazz();
                }
            }
            throw new NullPointerException(String.format("param is null is %s", param));
        }
    }

}

接口实现类:

public interface DynamicBind {

        void  sayHello();
}
public class CaptainAmerica implements DynamicBind {
    @Override
    public void sayHello() {
        System.out.println("美国翘臀");
    }
}
public class Iroman implements DynamicBind {
    @Override
    public void sayHello() {
        System.out.println("I i'm  Iroman");
    }
}
public class SpiderMan implements DynamicBind {
    @Override
    public void sayHello() {
        System.out.println("I i'm  SpiderMan");
    }
}

调用时:

   DynamicBind bind = ctx.getBean(DynamicStrategyEnum.getClazz(DynamicEnum.蜘蛛侠.getCode()));
   bind.sayHello();

Autowire+枚举+注解

此时的实体关系类是由枚举维护的,如果新加实现需要增加枚举维护,将实现类由注解维护,新实现类通过注解即可标识。

自定义注解与枚举维护:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoHandlerDynamicType {

    DynamicStrategyEnum  handlerModel();

}

实现类标识不同注解:

@AutoHandlerDynamicType (handlerModel = DynamicStrategyEnum.钢铁侠)
public class IronMan implements DynamicBind {
    @Override
    public void sayHello() {
        System.out.println("I   i'm  Iron man");
    }
}

仍然由枚举维护获取哪个实现类的:

private Map<DynamicStrategyEnum, DynamicBind> autoDynamiceHandlerMap;
    @Autowired
    public void setAutoDynamicHandlerMap(List<DynamicBind> autoDynamicHandlerList) {
        autoDynamiceHandlerMap = autoDynamiceHandlerList.stream()
                .collect(Collectors.toMap(
                        autoDynamicHandler -> AnnotationUtils.findAnnotation(DynamicBind.getClass(), DynamicStrategyEnum.class).handlerModel(),
                        autoDynamicHandler -> autoDynamicHandler));
    }

Autowire作用于方法时Spring会先实例化所有Bean,然后根据配置进行扫描,当检测到@Autowired后进行注入,注入时调用这个方法,也就是当启动完容器,map已经存放了实体类映射关系。

目录
相关文章
|
6月前
|
设计模式 算法 Java
小谈设计模式(3)—策略模式
小谈设计模式(3)—策略模式
|
6月前
|
设计模式 算法
【设计模式】阿里终面:你觉得这个例子是策略模式吗?
【设计模式】阿里终面:你觉得这个例子是策略模式吗?
57 1
|
6月前
|
设计模式
小谈设计模式(5)—开放封闭原则
小谈设计模式(5)—开放封闭原则
|
6月前
|
算法
犯错总结--工厂模式和策略模式傻傻没分清
犯错总结--工厂模式和策略模式傻傻没分清
61 0
犯错总结--工厂模式和策略模式傻傻没分清
|
6月前
|
设计模式 算法
|
6月前
|
设计模式 算法
设计模式再探——模板方法模式
设计模式再探——模板方法模式
|
设计模式 安全 关系型数据库
常见的23种设计模式和七大设计模式原则,一篇文章就搞定了!
常见的23种设计模式和七大设计模式原则,一篇文章就搞定了!
139 1
|
设计模式 数据库
几张图带你手拿把掐设计模式六大原则
几张图带你手拿把掐设计模式六大原则
77 0
设计模式再探——状态模式
最近产品中有这样的业务需求,不同时间(这里不是活动的执行时间,而是活动的执行时刻)展示不同的活动;
|
设计模式 存储 JSON
设计模式再探-备忘录模式
最近在做一学期的语文课,每一节课结束的时候,需要将这节课上到哪儿了给记录下来;以便于下次再上课的时候接着上,这样一个需求。