Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Spring3注释实现一个简单的工厂模式_Java_Spring_Annotations_Factory Pattern - Fatal编程技术网

Java 使用Spring3注释实现一个简单的工厂模式

Java 使用Spring3注释实现一个简单的工厂模式,java,spring,annotations,factory-pattern,Java,Spring,Annotations,Factory Pattern,我想知道如何用Spring3注释实现简单的工厂模式。我在文档中看到,您可以创建调用工厂类并运行工厂方法的bean。我想知道是否可以只使用注释 我有一个控制器,目前正在调用 MyService myService = myServiceFactory.getMyService(test); result = myService.checkStatus(); MyService是一个接口,有一个名为checkStatus()的方法 我的工厂类如下所示: @Component public clas

我想知道如何用Spring3注释实现简单的工厂模式。我在文档中看到,您可以创建调用工厂类并运行工厂方法的bean。我想知道是否可以只使用注释

我有一个控制器,目前正在调用

MyService myService = myServiceFactory.getMyService(test);
result = myService.checkStatus();
MyService是一个接口,有一个名为checkStatus()的方法

我的工厂类如下所示:

@Component
public class MyServiceFactory {

    public static MyService getMyService(String service) {
        MyService myService;

        service = service.toLowerCase();

        if (service.equals("one")) {
            myService = new MyServiceOne();
        } else if (service.equals("two")) {
            myService = new MyServiceTwo();
        } else if (service.equals("three")) {
            myService = new MyServiceThree();
        } else {
            myService = new MyServiceDefault();
        }

        return myService;
    }
}
MyServiceOne类如下所示:

@Autowired
private LocationService locationService;

public boolean checkStatus() {
      //do stuff
}
当我运行此代码时,locationService变量始终为null。我相信这是因为我自己在工厂里创建对象,自动布线没有发生。有没有办法添加注释以使其正确工作


谢谢

您是对的,通过手动创建对象,您不会让Spring执行自动布线。考虑通过Spring管理您的服务:

@Component
public class MyServiceFactory {

    @Autowired
    private MyServiceOne myServiceOne;

    @Autowired
    private MyServiceTwo myServiceTwo;

    @Autowired
    private MyServiceThree myServiceThree;

    @Autowired
    private MyServiceDefault myServiceDefault;

    public static MyService getMyService(String service) {
        service = service.toLowerCase();

        if (service.equals("one")) {
            return myServiceOne;
        } else if (service.equals("two")) {
            return myServiceTwo;
        } else if (service.equals("three")) {
            return myServiceThree;
        } else {
            return myServiceDefault;
        }
    }
}
但是我认为总体设计是相当差的。使用一个通用的
MyService
实现并将
一个
/
两个
/
三个
字符串作为额外参数传递给
checkStatus()
,不是更好吗?你想要实现什么

@Component
public class MyServiceAdapter implements MyService {

    @Autowired
    private MyServiceOne myServiceOne;

    @Autowired
    private MyServiceTwo myServiceTwo;

    @Autowired
    private MyServiceThree myServiceThree;

    @Autowired
    private MyServiceDefault myServiceDefault;

    public boolean checkStatus(String service) {
        service = service.toLowerCase();

        if (service.equals("one")) {
            return myServiceOne.checkStatus();
        } else if (service.equals("two")) {
            return myServiceTwo.checkStatus();
        } else if (service.equals("three")) {
            return myServiceThree.checkStatus();
        } else {
            return myServiceDefault.checkStatus();
        }
    }
}

这仍然是设计得很糟糕,因为添加新的
MyService
实现也需要修改
MyServiceAdapter
(SRP冲突)。但这实际上是一个很好的起点(提示:映射和策略模式)。

为什么不将接口FactoryBean添加到MyServiceFactory(告诉Spring它是一个工厂),添加一个寄存器(字符串服务,MyService实例),然后,让每个服务调用:

@Autowired
MyServiceFactory serviceFactory;

@PostConstruct
public void postConstruct() {
    serviceFactory.register(myName, this);
}

通过这种方式,您可以在必要时将每个服务提供商分离为模块,Spring将自动选择任何已部署和可用的服务提供商。

您可以手动要求Spring自动连接它

让您的工厂实现ApplicationContextAware。然后在工厂中提供以下实施:

@Override
public void setApplicationContext(final ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
}
然后在创建bean后执行以下操作:

YourBean bean = new YourBean();
applicationContext.getAutowireCapableBeanFactory().autowireBean(bean);
bean.init(); //If it has an init() method.

这将非常好地自动连接LocationService。

您还可以声明性地定义一个将充当工厂类的bean类型。它由弹簧3支撑

一种FactoryBean实现,它接受一个接口,该接口必须具有一个或多个带有签名的方法(通常为MyService getService()或MyService getService(String id)),并创建一个实现该接口的动态代理

这是


我想您应该使用org.springframework.beans.factory.config.ServiceLocatorFactoryBean。 它将大大简化您的代码。 除了MyServiceAdapter,您只能使用方法MyService getMyService和alies创建接口MyServiceAdapter来注册类

代码

bean id=“printStrategyFactory”class=“org.springframework.beans.factory.config.ServiceLocatoryFactoryBean”>
您可以通过将所有服务类作为参数传递来实例化“AnnotationConfigApplicationContext”

@Component
public class MyServiceFactory {

    private ApplicationContext applicationContext;

    public MyServiceFactory() {
        applicationContext = new AnnotationConfigApplicationContext(
                MyServiceOne.class,
                MyServiceTwo.class,
                MyServiceThree.class,
                MyServiceDefault.class,
                LocationService.class 
        );
        /* I have added LocationService.class because this component is also autowired */
    }

    public MyService getMyService(String service) {

        if ("one".equalsIgnoreCase(service)) {
            return applicationContext.getBean(MyServiceOne.class);
        } 

        if ("two".equalsIgnoreCase(service)) {
            return applicationContext.getBean(MyServiceTwo.class);
        } 

        if ("three".equalsIgnoreCase(service)) {
            return applicationContext.getBean(MyServiceThree.class);
        } 

        return applicationContext.getBean(MyServiceDefault.class);
    }
}

以下几点对我很有用:

接口由逻辑方法和附加标识方法组成:

public interface MyService {
    String getType();
    void checkStatus();
}
一些实现:

@Component
public class MyServiceOne implements MyService {
    @Override
    public String getType() {
        return "one";
    }

    @Override
    public void checkStatus() {
      // Your code
    }
}

@Component
public class MyServiceTwo implements MyService {
    @Override
    public String getType() {
        return "two";
    }

    @Override
    public void checkStatus() {
      // Your code
    }
}

@Component
public class MyServiceThree implements MyService {
    @Override
    public String getType() {
        return "three";
    }

    @Override
    public void checkStatus() {
      // Your code
    }
}
工厂本身如下:

@Service
public class MyServiceFactory {

    @Autowired
    private List<MyService> services;

    private static final Map<String, MyService> myServiceCache = new HashMap<>();

    @PostConstruct
    public void initMyServiceCache() {
        for(MyService service : services) {
            myServiceCache.put(service.getType(), service);
        }
    }

    public static MyService getService(String type) {
        MyService service = myServiceCache.get(type);
        if(service == null) throw new RuntimeException("Unknown service type: " + type);
        return service;
    }
}
@服务
公共类MyServiceFactory{
@自动连线
私人名单服务;
私有静态最终映射myServiceCache=newhashmap();
@施工后
public void initMyServiceCache(){
for(MyService服务:服务){
myServiceCache.put(service.getType(),service);
}
}
公共静态MyService getService(字符串类型){
MyService=myServiceCache.get(类型);
if(service==null)抛出新的RuntimeException(“未知服务类型:”+type);
回程服务;
}
}
我发现这样的实现更容易、更干净、更具可扩展性。添加新的MyService就像创建另一个Springbean实现相同的接口一样简单,无需在其他地方进行任何更改

使用自动连线构造器重构工厂的Litte:

@服务
公共类MyServiceFactory{
私有静态最终映射myServiceCache=newhashmap();
@自动连线
私人MyServiceFactory(列表服务){
for(MyService服务:服务){
myServiceCache.put(service.getType(),service);
}
}
公共静态MyService getService(字符串类型){
MyService=myServiceCache.get(类型);
if(service==null)抛出新的RuntimeException(“未知服务类型:”+type);
回程服务;
}
}
试试这个:

public interface MyService {
 //Code
}

@Component("One")
public class MyServiceOne implements MyService {
 //Code
}

@Component("Two")
public class MyServiceTwo implements MyService {
 //Code
}

基于PavelČerný的解决方案 我们可以为这个模式创建一个通用类型的实现。 为此,我们需要引入NamedService接口:

    public interface NamedService {
       String name();
    }
并添加抽象类:

public abstract class AbstractFactory<T extends NamedService> {

    private final Map<String, T> map;

    protected AbstractFactory(List<T> list) {
        this.map = list
                .stream()
                .collect(Collectors.toMap(NamedService::name, Function.identity()));
    }

    /**
     * Factory method for getting an appropriate implementation of a service
     * @param name name of service impl.
     * @return concrete service impl.

     */
    public T getInstance(@NonNull final String name) {
        T t = map.get(name);
        if(t == null)
            throw new RuntimeException("Unknown service name: " + name);
        return t;
    }
}
公共抽象类AbstractFactory{
私人最终地图;
受保护的抽象工厂(列表){
this.map=列表
.stream()
.collect(Collectors.toMap(NamedService::name,Function.identity());
}
/**
*获取服务的适当实现的工厂方法
*@param name服务impl的名称。
*@return-concrete-service-impl。
*/
public T getInstance(@NonNull final String name){
T=map.get(名称);
如果(t==null)
抛出新的RuntimeException(“未知服务名称:“+name”);
返回t;
}
}
然后,我们创建一个特定对象的具体工厂,如MyService:

 public interface MyService extends NamedService {
           String name();
           void doJob();
 }

@Component
public class MyServiceFactory extends AbstractFactory<MyService> {

    @Autowired
    protected MyServiceFactory(List<MyService> list) {
        super(list);
    }
}
公共接口MyService扩展NamedService{
字符串名();
void doJob();
}
@组成部分
公共类MyServiceFactory扩展了AbstractFactory{
@自动连线
受保护的MyServiceFactory(列表){
超级(名单);
}
}
其中列出了MyService接口在编译时的实现列表

如果
 public interface MyService extends NamedService {
           String name();
           void doJob();
 }

@Component
public class MyServiceFactory extends AbstractFactory<MyService> {

    @Autowired
    protected MyServiceFactory(List<MyService> list) {
        super(list);
    }
}
 public static MyService getService(String type) {
        return Optional.ofNullable(myServiceCache.get(type))
                .orElseThrow(() -> new RuntimeException("Unknown service type: " + type));
 }