ServiceLoader 初级应用

作者: 疯狂小兵 | 2017-04-22 | 阅读
「编辑」 「本文源码」

背景

偶然的机会从牛人博客发现了该ServiceLoader的存在,以前也遇到过通过接口查找实现类的问题,了解到的办法都是遍历指定包下的所有类然后过滤出指定接口的实现类。现发现java原生就对根据接口查找实现类的功能,现特将实践代码记录如下。

实战

编写接口

该接口位于cn.followtry.dubbo.api包下,全限定名为cn.followtry.dubbo.api.UserService

package cn.followtry.dubbo.api;

import cn.followtry.dubbo.bean.User;

public interface UserService {

  User getUserById(String id);
}

定义该接口,下文中会找出实现该接口的实现类。

配置Maven的pom文件

添加如下代码

<dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.8<version>
</dependency>
<build>
      <!-- 指定构建的资源及构建的位置 -->
      <resources>
            <resource>
                  <directory>src/main/java</directory>
                  <targetPath>${project.build.directory}</targetPath>
                  <includes>
                        <include>**/*.java</include>
                  </includes>
            </resource>
            <!--使得所有的resources下的资源都构建在class路径下-->
            <resource>
                  <directory>src/main/resources</directory>
                  <filtering>true</filtering>
            </resource>
      </resources>
</build>

编写实现类

实现cn.followtry.dubbo.api.UserService的类名分别为cn.followtry.dubbo.impl.CustomUserServiceImpl,cn.followtry.dubbo.impl.DefaultUserServiceImpl

实现类如下:

package cn.followtry.dubbo.impl;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;

public class CustomUserServiceImpl implements UserService {
  public CustomUserServiceImpl() {
    System.out.println("cn.followtry.dubbo.api.UserService.CustomUserServiceImpl.CustomUserServiceImpl()");
  }

  @Override
  public User getUserById(String id) {
    return new User() {
      //初始化块,该代码相当于匿名继承类User
      {
        setId(id);
        setName("custom-user-1");
      }
    };
  }
}

package cn.followtry.dubbo.impl;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;

public class DefaultUserServiceImpl implements UserService {
  public DefaultUserServiceImpl() {
    System.out.println("cn.followtry.dubbo.impl.DefaultUserServiceImpl.DefaultUserServiceImpl()");
  }

  @Override
  public User getUserById(String id) {
    return new User() {
      {
        setId(id);
        setName("default-user-1");
      }
    };
  }
}

辅助类

package cn.followtry.dubbo.bean;

import java.io.Serializable;
import lombok.Data;
import lombok.ToString;

@Data
@ToString
public class User implements Serializable {
  private static final long serialVersionUID = 3899555909604815507L;
  private String name;
  private String id;
}

该项目使用了lombok,关于lombok的使用自行百度或Google。

创建资源文件

src/mian/resources下创建META-INF,在其下创建services,在其下创建以接口全限定名命名的文件(如:cn.followtry.dubbo.api.UserService)在该文件内填写实现该接口的类全限定名,每个类名一行。

名为META-INF/services下的cn.followtry.dubbo.api.UserService的文件

cn.followtry.dubbo.impl.DefaultUserServiceImpl
cn.followtry.dubbo.impl.CustomUserServiceImpl

编写测试类


package cn.followtry.dubbo.impl.test;

import cn.followtry.dubbo.api.UserService;
import cn.followtry.dubbo.bean.User;
import java.util.ServiceLoader;
import org.junit.Test;

/**
 * 通过接口,查找实现了接口的类
 * Created by followtry on 2017/4/22 0022.
 */
public class UserServiceTest {

  @Test
  public void getSubClassByInterface() {
    ServiceLoader<UserService> serviceLoader = ServiceLoader.load(UserService.class);
    if (serviceLoader != null) {
      for (UserService userService : serviceLoader) {
        User userById = userService.getUserById("ssssss");
        System.out.println(userById);
      }
    }
  }
}


执行结果

执行测试类会得到以下结果,说明通过配置的资源文件可以找到指定的接口的实现类,但也只能找到资源文件中指定的实现类。

cn.followtry.dubbo.impl.DefaultUserServiceImpl.DefaultUserServiceImpl()
User(name=default-user-1, id=ssssss)
cn.followtry.dubbo.api.UserService.CustomUserServiceImpl.CustomUserServiceImpl()
User(name=custom-user-1, id=ssssss)

总结

该文章只是对ServiceLoader的简单实践,不涉及原理和内部实现以及高级应用,初级接触,慢慢深入。

接下来有时间还会对该工具类进行深入的实践和原理分析。


版权声明:本文由 在 2017年04月22日发表。本文采用CC BY-NC-SA 4.0许可协议,非商业转载请注明出处,不得用于商业目的。
文章题目及链接:《ServiceLoader 初级应用》




  相关文章:

「游客及非Github用户留言」:

「Github登录用户留言」:

TOP