15

依赖注入的延续,延迟注入实践。我有主课:

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Scanner;

@Component
public class Main {
    @Autowired
    private StringValidator stringValidator;

    @Autowired
    private StringService stringService;

    @Autowired
    private ValidationService validationService;

    public void main() {
        scanKeyboardCreateLists();

        stringValidator.validate();

        final List<String> validatedList = stringValidator.getValidatedList();
        for (String currentValid : validatedList) {
            System.out.println(currentValid);
        }
    }

    private void scanKeyboardCreateLists() {
        //Let's presume the user interacts with the GUI, dynamically changing the object graph...
        //Needless to say, this is past container initialization...
        Scanner scanner = new Scanner(System.in);
        int choice = scanner.nextInt();

        //Delayed creation, dynamic
        if (choice == 0) {
            stringService.createList();
            validationService.createList();
        } else {
            stringService.createSecondList();
            validationService.createSecondList();
        }
    }

    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");
        container.getBean(Main.class).main();
    }
}

并且对象图是动态创建的,取决于用户交互。我解决了应用程序耦合,让我可以非常简单地测试它。此外,由于列表由容器维护,因此此应用程序(以及其他所有应用程序)的动态特性是无关紧要的,因为可以在应用程序需要它们的任何时候请求它们,维护它们的元素。

其余代码在这里:

package test;

import java.util.List;

public interface Stringable {
    List<String> getStringList();
}

package test;

import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component
public class StringList extends ArrayList<String> {
}

package test;

import org.springframework.stereotype.Component;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

@Component
public class StringService implements Stringable {

    private List<String> stringList;

    @Inject
    public StringService(final ArrayList<String> stringList) {
        this.stringList = stringList;
    }

    //Simplified
    public void createList() {
        stringList.add("FILE1.txt");
        stringList.add("FILE1.dat");
        stringList.add("FILE1.pdf");
        stringList.add("FILE1.rdf");
    }

    public void createSecondList() {
        stringList.add("FILE2.txt");
        stringList.add("FILE2.dat");
        stringList.add("FILE3.pdf");
        stringList.add("FILE3.rdf");
    }

    @Override
    public List<String> getStringList() {
        return stringList;
    }
}

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class StringValidator {
    private List<String> stringList;
    private List<String> validationList;

    private final List<String> validatedList = new ArrayList<String>();

    @Autowired
    public StringValidator(final ArrayList<String> stringList,
                           final ArrayList<String> validationList) {
        this.stringList = stringList;
        this.validationList = validationList;
    }

    public void validate() {
        for (String currentString : stringList) {
            for (String currentValidation : validationList) {
                if (currentString.equalsIgnoreCase(currentValidation)) {
                    validatedList.add(currentString);
                }
            }
        }
    }

    public List<String> getValidatedList() {
        return validatedList;
    }
}

package test;

import java.util.List;

public interface Validateable {
    List<String> getValidationList();
}

package test;

import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component
public class ValidationList extends ArrayList<String> {
}

package test;

import org.springframework.stereotype.Component;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

@Component
public class ValidationService implements Validateable {

    private List<String> validationList;

    @Inject
    public ValidationService(final ArrayList<String> validationList) {
        this.validationList = validationList;
    }

    //Simplified...
    public void createList() {
        validationList.add("FILE1.txt");
        validationList.add("FILE2.txt");
        validationList.add("FILE3.txt");
        validationList.add("FILE4.txt");
    }

    public void createSecondList() {
        validationList.add("FILE5.txt");
        validationList.add("FILE6.txt");
        validationList.add("FILE7.txt");
        validationList.add("FILE8.txt");
    }

    @Override
    public List<String> getValidationList() {
        return validationList;
    }
}

有谁知道我将如何解决方法调用 createList() 或 createSecondList() - 不使用几乎强制设计的构造函数。我在想一个工厂,但是一个更大的项目中每个班级的工厂似乎不是一个好主意。

就像是:

<bean ... factory-method="..." depends-on="..." lazy-init="..."/>

并在工厂方法中实例化该类并调用方法 createList()。或者像这样从某个方法调用它——这又看起来很糟糕,迫使该方法有责任实例化对象图。

我想在运行时解决的运行时依赖关系的图片如下:

在此处输入图像描述

是否有其他方法可以根据用户交互使用容器来实现动态延迟初始化?

谢谢你。

4

3 回答 3

10

如果您希望类的某些成员在每次调用相应的 getter 时动态初始化\填充,您可以尝试查找方法注入。在此处阅读第 3.3.4.1 页

因此即使scope=singletone每次访问分配了查找方法的字段时(spring bean容器的默认值)中创建了包含动态成员的类,您也会根据查找方法内部实现的业务逻辑获得适当的对象. 在您的情况下,列表是一个接口,因此您可以轻松地在查找方法中实现验证并返回经过验证的列表。

编辑:

我在 Spring 文档中找到了更好的例子——我认为这很清楚。看看《3.4.6.1 Lookup 方法注入》

当您配置Main类时,为其成员分配一个查找方法- 只要您需要beanList的新实例,就会调用它。List

祝你好运!

于 2012-05-07T14:35:11.103 回答
3

Spring 是为可重用的组件注入而设计的,而不是为业务数据操作和注入而设计的。

事实上,一些数据用于依赖注入,但仅用于配置组件行为,而不是创建业务数据持有者。

顺便说一句,在您的情况下可以使用以下选项:感谢BeanFactory带有BeanFactoryAware 接口getBean()和使用 scope="prototype",您可以通过在该示例中或从其他问题中调用来生成 bean :按需创建 bean .

如果要准备的 bean 数量有限,另一种选择是使用通用 bean 创建,就像模拟缺少 bean 一样

现在考虑 Spring 从不会在其 Context 中垃圾收集 bean。所以创建Spring bean来保存业务数据是有内存消耗的风险的。

如果您的目标不同(我希望如此),也许您正在尝试自己实现多租户支持。如果您有不同的业务上下文要使用特定的组件或行为来实现, Spring 会提供租户

于 2012-05-11T19:37:31.463 回答
2

听起来用户可以选择 1..N 个对象图,而您只想加载用户在运行时选择的那个。如果图表在设计时是已知的,但用户只是选择了他们想要的那个,那么在我看来,你拥有的是一堆 ApplicationContext,而你只想加载用户在运行时选择的一个 ApplicationContext。那么为什么不直接定义一组 ApplicationContexts,然后在运行时实例化正确的一个。由于 Spring 支持 Java Config,因此将这些配置定义为 Java 类可能是有意义的,这样您就可以获得继承并避免剪切/粘贴任何代码。

于 2012-05-10T00:53:58.150 回答