首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring 4请求驱动Bean创建

Spring 4请求驱动Bean创建
EN

Stack Overflow用户
提问于 2015-09-12 15:36:38
回答 3查看 135关注 0票数 2

我正在使用Spring 4 (Spring )实现Rest。

基本思想是,我想使用一个JSON有效负载,指定一个标识符(例如,社保号或其他什么),并在该标识符上运行多个subServices。下面是一个示例有效载荷:

代码语言:javascript
复制
{
    "ssNumber" : "1111111111111111",
    "subServicesDetails" :
    [
        { "subServiceName" : "Foo" , "requestParameters" : {} }, 
        { "subServiceName" : "Dummy", "requestParameters" : {} }
    ]
}

在我的代码中,我有多个“子服务”(FooServiceDummyService)实现SubService接口:

代码语言:javascript
复制
package com.johnarnold.myws.service;

import com.johnarnold.myws.model.SubServiceDetails;

public interface SubService {

    public boolean service(String ssNumber, SubServiceDetails ssd);
}

下面是FooService代码。包装com.johnarnold.myws.service

代码语言:javascript
复制
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.johnarnold.myws.dao.FooDao;
import com.johnarnold.myws.model.Foo;
import com.johnarnold.myws.model.SubServiceDetails;

@Component
public class FooService implements SubService{
    private static Logger log = Logger.getLogger(FooService.class);

    @Autowired
    private FooDao dao;


    public FooService()
    {
        log.debug("FooService ctor");
    }


    public boolean service(String ssNumber, SubServiceDetails ssd)
    {
        log.debug("FooService service");

        Map <String, String> responseParameters = new HashMap<String, String>();
        try
        {
            Foo foo = dao.getFoo(ssNumber);
            if(foo.isCompromised())
            {
                responseParameters.put("listed", "true");
            }
            else
            {
                responseParameters.put("listed", "false");              
            }
            ssd.setResponseParameters(responseParameters);
            return true;
        }
        catch(Throwable ex)
        {
            log.error("Exception in service ", ex);
        }
        return false;
    }
}

现在,我编写了自己的工厂来创建子服务,但是当我这样做的时候,当然是因为我在下面明确地创建我的bean(例如FooService) --我的容器并不是自动注入任何@Autowired成员-- FooDao,例如: package com.johnarnold.myws.service;

代码语言:javascript
复制
public class SubServiceFactory {

    /*
     * Instantiates a SubService for the supplied subServiceName or throws an exception if 
     * no valid SubService exists
     */
    public static SubService createSubService(String subServiceNameStr)
    {
        SubService subService = null;

        System.out.println("subServiceName [" + subServiceNameStr + "]");

        if(subServiceNameStr.equals("Foo"))
        {
            subService = new FooService();
        }
        if(subServiceNameStr.equals("Dummy"))
        {
            subService = new DummyService();
        }
        else
        {
            System.out.println("subServiceName [" + subServiceNameStr + "] is not defined");    
        }
        return subService;
    }
}

为了完整起见,以下是主计长:

代码语言:javascript
复制
package com.johnarnold.myws.controller;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.johnarnold.myws.model.RawsPayload;
import com.johnarnold.myws.model.SubServiceDetails;
import com.johnarnold.myws.service.SubService;
import com.johnarnold.myws.service.SubServiceFactory;
import com.johnarnold.myws.web.ValidMessage;

@RestController
@RequestMapping("/raws/")
public class RawsController {
    private static final Logger logger = Logger.getLogger(RawsController.class);    

    //@Autowired
    //SubService [] subSvcs;

    @RequestMapping(value="/{version}/status", method=RequestMethod.GET)
    public ResponseEntity<ValidMessage> getServiceStatus()
    {
        return new ResponseEntity<>(new ValidMessage() , HttpStatus.OK);
    }

    /*
     * Main entry point - orchestrates all of the WS Sub Services
     */
    @RequestMapping(value="/{version}/raws", method=RequestMethod.PUT)
    public ResponseEntity<String> raws(@Valid @RequestBody RawsPayload rawsPayload, 
            HttpServletRequest request)
    {
        logger.info("Request received");


        System.out.println("payl " + rawsPayload);

        System.out.println("ssNumber=" + rawsPayload.getSsNumber());
        System.out.println("sub svcs details=" + rawsPayload.getSubServicesDetails().length);

        SubServiceDetails[] subServiceDetails = rawsPayload.getSubServicesDetails();

        for(SubServiceDetails ssd : subServiceDetails)
        {

            String subServiceNameStr = ssd.getSubServiceName();

            System.out.println("svcname=" + subServiceNameStr);
            System.out.println("svc req params=" + ssd.getRequestParameters());
            System.out.println("svc resp params=" + ssd.getResponseParameters());

            SubService subService = SubServiceFactory.createSubService(subServiceNameStr);
            // Probably wrap the below with some timings
            subService.service(rawsPayload.getSsNumber(), ssd);
        }


        //System.out.println("svcs are " + subSvcs + "size=" + subSvcs.length);


        return new ResponseEntity<>("foo" , HttpStatus.OK);
    }

}

以下是主要的有效载荷类:

代码语言:javascript
复制
package com.johnarnold.myws.model;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.log4j.Logger;
import org.hibernate.validator.constraints.Length;

public class RawsPayload {
    static Logger log = Logger.getLogger(RawsPayload.class);

    @NotNull
    @Length(min=16, max=19)
    private String ssNumber;

    @Valid
    @NotNull
    @Size(min=1, max=3)
    private SubServiceDetails [] subServicesDetails;


    public String getSsNumber() {
        return ssNumber;
    }

    public void setSsNumber(String ssNumber) {
        log.info("setSsNumber()");
        this.ssNumber = ssNumber;
    }

    public SubServiceDetails[] getSubServicesDetails() {
        return subServicesDetails;
    }

    public void setSubServicesDetails(SubServiceDetails[] subServicesDetails) {
        this.subServicesDetails = subServicesDetails;
    }

}

我在StackOverflow上读过许多关于Spring4ConditionBeans的答案,但是这个功能似乎是针对上下文/配置类型信息,而不是请求消息内容(如本例中所示)。谁能给我指明正确的方向。如果有必要,我可以提供进一步的上下文KRgds John

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-09-12 21:48:07

你不需要任何花哨的东西。只需实现实现服务接口的所有服务,用@Component@Service对它们进行注释,并像往常一样扫描它们。

然后,在您必须选择具体服务实现的地方,将您的服务的所有实现自动化如下:

代码语言:javascript
复制
@Autowired
Map<String, SubService> subServices;

映射的键是每个子服务实现的@Component注释中指定的服务名称,值将是实例。

因此,当您接收到JSON时,只需获取子服务的名称(即Foo),并获取映射的特定服务:

代码语言:javascript
复制
SubService fooSubService = subServices.get(subServiceName + "Service");

其中,subServiceName是您在JSON中接收的子服务的非大写名称(也就是说,如果您正在接收Foo,这将是foo)。

约定是使用实现接口的类的非大写名称作为bean名,即对于FooService类,bean名称将是fooService,这是您必须在映射中查找的键。

票数 0
EN

Stack Overflow用户

发布于 2015-09-12 17:02:42

解决这一问题的两种可能方法:

  • 将所有的subService bean添加到Spring中,然后使用ServiceLocatorFactoryBean从它们中进行选择。这是一个更好的方法(从体系结构的角度来看),但是如果您以前从未使用过这个概念,那么它可能需要更多的时间来实现。

如果您想坚持使用基本的Spring解决方案,下面有一个更简单的选择:

  • 将子服务bean作为列表注入到主服务中,然后从中进行选择。看起来会是这样的: @Bean public List<SubService> subServices(){ List<SubService> list = new SubService<>(); list.add(new AService()); list.add(new BService()); return list; }

然后

代码语言:javascript
复制
public SubService selectServiceByName() {
    //iterate through the list, pick the service with the right name and return - this solution will require you to bind by beannames
}
票数 1
EN

Stack Overflow用户

发布于 2015-09-12 18:51:51

@john首先将所有服务打包,或者用@Service/@Component注释它们,其显式名称如下所示:名称以subServiceName param的值开头,并包含一个常见的后缀“服务”,这很重要。

代码语言:javascript
复制
@Bean("FooService")
public SubService fooService() {
    return new FooService();
}

@Bean("DummyService")
public SubService dummyService() {
    return new DummyService();
}

然后像这样改变你的工厂:

代码语言:javascript
复制
@Component
public class SubServiceFactory implements BeanFactoryAware{

private BeanFactory beanFactory;
private static final String MY_SERVICE_SUFFIX = "Service";

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    this.beanFactory = beanFactory;
}

public <T> T getServiceImplementation(String name, Class<T> requiredType) {
    return beanFactory.getBean(name + MY_SERVICE_SUFFIX, requiredType);
}
}

现在我们有一个BeanFactoryAware类,您可以将它插入到Rest端点,而不是if语句,尝试如下:

代码语言:javascript
复制
subServiceFactory.getServiceImplementation(subServiceNameStr, SubService.class);

这将返回您的bean或异常,如果它找不到。如果不需要异常,可以捕获它并返回null,或者可以创建Service。只是为了这些,然后返回那个实例。你自己选吧。

编辑:

作为一种快捷方式,您可以定义您的imp。,而不是将其添加到rest端点

代码语言:javascript
复制
@Autowired
private Map<String, SubService> mySubServices;

弹簧会自动注入你所有的能量。参考所以您可以使用map的get()方法。但我更喜欢第一个..。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32540596

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档