有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

避免全局状态的REST服务器java存储和加载配置(即单例与上下文、依赖注入)

我正在使用tomcat开发Java体系结构,我遇到了一种我认为非常普遍的情况,但在阅读StackOverflow中的几个问题/答案后,我找不到一个明确的答案。我的体系结构有一个REST API(在tomcat上运行),它接收一个或多个文件及其相关元数据,并将它们写入存储器。存储层的配置与REST API服务器有1-1关系,因此直观的方法是编写一个单例来保存该配置

显然,我知道,由于全球状况和嘲笑单身汉的困难,单身汉带来了可测试性问题。我也想过使用上下文模式,但我不相信上下文模式适用于这种情况,我担心我最终会使用“上下文反模式”进行编码

让我给你们介绍一下我写作的背景。该体系结构由以下组件组成:

  • 向REST API发送请求的客户端上载或检索“保存对象”,或者简单地说,是JSON或XML格式的POs(文件+元数据)

  • 高级REST API,用于接收来自客户端的请求并将数据存储在存储层中

  • 存储层,可能包含OpenStack Swift容器、磁带库和文件系统的组合。在我的体系结构中,每一个“存储容器”(为了简单起见,我称之为文件系统容器)都被称为端点。存储层显然与REST API所在的服务器不同

端点的配置通过REST API(例如POST/configEndpoint)完成,以便管理用户可以通过HTTP调用注册新端点、编辑或删除现有端点。虽然我只使用OpenStack Swift端点实现了该架构,但我预计每个端点的信息至少包含一个IP地址、某种形式的身份验证信息和一个驱动程序名,例如“Swift驱动程序”、“LTFS驱动程序”,等等(这样,当新的存储技术出现时,只要有人为我的体系结构编写驱动程序,它们就可以轻松集成到我的体系结构中)

我的问题是:如何以可测试、可重用和优雅的方式存储和加载配置?我甚至不考虑将配置对象传递给实现REST API调用的所有各种方法。

REST API调用的几个示例以及配置的作用:

// Retrieve a preservation object metadata (PO)
@GET
@Path("container/{containername}/{po}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public PreservationObjectInformation getPOMetadata(@PathParam("containername") String containerName, @PathParam("po") String poUUID) {

    // STEP 1 - LOAD THE CONFIGURATION
    // One of the following options:
    // StorageContext.loadContext(containerName);
    // Configuration.getInstance(containerName);
    // Pass a configuration object as an argument of the getPOMetadata() method?
    // Some sort of dependency injection

    // STEP 2 - RETRIEVE THE METADATA FROM THE STORAGE
    // Call the driver depending on the endpoint (JClouds if Swift, Java IO stream if file system, etc.)
    // Pass poUUID as parameter

    // STEP 3 - CONVERT JSON/XML TO OBJECT
    // Unmarshall the file in JSON format
    PreservationObjectInformation poi = unmarshall(data);

    return poi;
}


// Delete a PO
@DELETE
@Path("container/{containername}/{po}")
public Response deletePO(@PathParam("containername") String containerName, @PathParam("po") String poName) throws IOException, URISyntaxException {

    // STEP 1 - LOAD THE CONFIGURATION
    // One of the following options:
    // StorageContext.loadContext(containerName); // Context
    // Configuration.getInstance(containerName); // Singleton
    // Pass a configuration object as an argument of the getPOMetadata() method?
    // Some sort of dependency injection

    // STEP 2 - CONNECT TO THE STORAGE ENDPOINT
    // Call the driver depending on the endpoint (JClouds if Swift, Java IO stream if file system, etc.)

    // STEP 3 - DELETE THE FILE

    return Response.ok().build();
}


// Submit a PO and its metadata
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("container/{containername}/{po}")
public Response submitPO(@PathParam("containername") String container, @PathParam("po") String poName, @FormDataParam("objectName") String objectName,
        @FormDataParam("inputstream") InputStream inputStream) throws IOException, URISyntaxException {

    // STEP 1 - LOAD THE CONFIGURATION
    // One of the following options:
    // StorageContext.loadContext(containerName);
    // Configuration.getInstance(containerName);
    // Pass a configuration object as an argument of the getPOMetadata() method?
    // Some sort of dependency injection

    // STEP 2 - WRITE THE DATA AND METADATA TO STORAGE
    // Call the driver depending on the endpoint (JClouds if Swift, Java IO stream if file system, etc.)

    return Response.created(new URI("container/" + container + "/" + poName))
            .build();
}

**更新#1-我的实现基于@mawalker的评论**

下面是我使用建议答案的实现。工厂创建具体的策略对象,以实现较低级别的存储操作。上下文对象(由中间件来回传递)包含抽象类型的对象(在本例中为接口)StorageContainerStrategy(其实现将取决于运行时每个特定情况下的存储类型)

public interface StorageContainerStrategy {
    public void write();
    public void read();

    // other methods here
}

public class Context {
    public StorageContainerStrategy strategy;

    // other context information here...
}

public class StrategyFactory {
    public static StorageContainerStrategy createStorageContainerStrategy(Container c) {
        if(c.getEndpoint().isSwift())
            return new SwiftStrategy();
        else if(c.getEndpoint().isLtfs())
            return new LtfsStrategy();
        // etc.
        return null;
    }
}

public class SwiftStrategy implements StorageContainerStrategy {
    @Override
    public void write() {
        // OpenStack Swift specific code
    }

    @Override
    public void read() {
        // OpenStack Swift specific code
    }
}

public class LtfsStrategy implements StorageContainerStrategy {
    @Override
    public void write() {
        // LTFS specific code
    }

    @Override
    public void read() {
        // LTFS specific code
    }
}

共 (0) 个答案