Spring Cloud的扩展之道

11 篇文章 0 订阅
5 篇文章 0 订阅

 

框架的扩展方式

作为框架,使用者众多,无法满足所有的需求,那只能提供一些扩展机制,让使用者变成开发者,实现自己的个性化需求。这也是很多开源框架的优势。

那么,作为开发者,如果不能满足要求,如何扩展呢?

最简单的方式肯定是直接修改源代码,如果源码实现的比较好,定义了接口,可以直接基于接口实现。这种做法比较简单,只要读懂源码即可,问题是主干一旦升级,修改起来没有那么方便。就像各个厂商对Android的定制化需求,代码错综复杂,merge是一个巨大无比的工程。

那怎么才能更好的隔离呢?

说这些之前,先让我们了解一下ClassLoader,Java虚拟机会创建三类ClassLoader,分别为BootStrap、Extension、System,先加载谁后加载谁呢?这就是著名的双亲委托模式,但是,双亲委托模式存在着诸多弊端,它是一种字底向上的加载顺序,是单向的,父加载器是拿不到通过子加载器加载的类的,说白了,系统类无法访问应用类,典型的例子是JDBC Driver,通常会用Class.forName("com.mysql.jdbc.Driver")加载数据库相关的驱动,Class.forName的作用是要求JVM查找并加载指定的类,也就是说,系统默认的双亲委托模式没有把需要的类加载进来,需要重新加载一次。虽然双亲委托模式是虚拟机默认加载机制,但不是不可以突破,例如Tomcat就有自己独特的类加载顺序,JDBC4.0也不需要Class.forName了。另外,OSGI和SPI就是为了克服这些弊端而生的。

OSGI案例中比较成功的是eclipse,可以热加载,但是开发调试的复杂度比较大;SPI是Service Provider Interface的缩写,相当于一种规范,是JDK内置的一种服务提供发现机制。只要在指定的目录定义好接口,引入符合规范的jar包就可以工作了,非常符合第三方开发者进行扩展。

当然,SPI也有自身的问题。 JDK自带的SPI实现会一次性实例化所有扩展点,这会导致应用启动的时间变长,并且浪费不必要的资源。

Spring的SPI机制

绕了这么大一个弯儿,回过头来,我们再说一说Spring的扩展方式。Spring就是采用的SPI机制。 Spring如今的大红大紫,绝对和Spring近乎偏执的理念有关,与其他很多框架不同,Spring更多强调的是开放性,或者说是扩展性。在Spring的全家桶中,很多组件都是从外部集成进来的,各种starter就是这些组件的集合。如注册发现,可以使用Consul、Eureka等实现。

我们都知道,Spring Cloud依赖于Spring Boot,Spring Boot又依赖于Spring,Spring Cloud的扩展性来源于Spring Boot中的@EnableAutoConfiguration, 大致的加载步骤如下: step 1、SpringBoot启动的时候,会扫描classpath下所有Jar中META-INF/spring.factories文件; step 2、读取指定的Configuration,根据Configuration上的Conditional条件自动创建bean; step 3、放入Spring Context中,这样就注入了容器,任何地方都可以直接注入使用了。

基于SPI扩展Spring Boot

1、新建工程,分别建立两个moudle,spring-boot-starter-saberj作为我们要扩展Spring Boot的工程,spring-boot-starter-saberj-test会使用spring-boot-starter-saberj。

2、引入Maven依赖。

引入Maven依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-autoconfigure</artifactId>
      <version>2.1.2.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <version>2.1.2.RELEASE</version>
      <optional>true</optional>
    </dependency>

3、定义SaberjProperties,这个类主要是从配置文件中读取出来的属性进行映射,如application.yml中配置了saberj.url,下面这段代码就能读出来。

@Component
@ConfigurationProperties(prefix = "saberj")
public class SaberjProperties {
  private String url;

  public String getUrl() {
    return url;
  }

  public void setUrl(String url) {
    this.url = url;
  }
}

4、定义SaberjAutoConfiguration,此类为核心,EnableConfigurationProperties的作用是从配置文件中加载配置到SaberjProperties,放入容器,也就是让ConfigurationProperties生效。@ConditionalOnClass的作用是当类路径下找到指定的类的条件下,也就是能找到SaberjService的情况下,才去解析对应的配置文件。这里除了使用OnClass,还有很多的触发检查配置,如OnBeanCondition用于检测指定bean实例存在才触发、OnPropertyCondition用于检查指定属性存在才触发等等。@Configuration用于声明SaberjAutoConfiguration为配置类,这也是SPI的扩展实现类,spring.factory会配置出来。

@Configuration
@ConditionalOnClass(SaberjService.class)
@EnableConfigurationProperties(SaberjProperties.class)
public class SaberjAutoConfiguration {
  @Autowired
  private SaberjProperties saberjProperties;

}

5、在META-INF/spring.factories中定义SPI扩展类。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xxx.saberj.SaberjAutoConfiguration

6、在spring-boot-starter-saberj-test中使用上面基于SPI扩展的框架。引入依赖,在application.yml中,根据SaberjProperties定义的映射关系实现yaml配置。

    <dependency>
      <groupId>com.xxx</groupId>
      <artifactId>spring-boot-starter-saberj</artifactId>
      <version>1.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.1.2.RELEASE</version>
      <scope>compile</scope>
    </dependency>
saberj:
  url: 127.0.0.1:9090

7、定义main函数启动,打印相关属性。

@SpringBootApplication
public class SaberjController {
  @Autowired
  SaberjService saberjService;

  public static void main(String[] args) {
    ConfigurableApplicationContext context = SpringApplication
        .run(SaberjController.class, args);
   System.out.printf("saber="+context.getBean(SaberjService.class).getConnection());
  }
}

8、启动工程,会发现,已经打印出来配置文件中定义的信息。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值