Java 依赖注入,延迟注入实践

Java 依赖注入,延迟注入实践,java,spring,dependency-injection,Java,Spring,Dependency Injection,一个简单(冗长)的问题,而不是简单的答案。通过使用一些DI框架(Spring、Guice),我得出了一个结论,即其他人提出的一些实践并不是那么容易实现。我似乎真的被困在这个层次上了 我将尽可能简单地介绍这一点,尽管一些细节可能会丢失。我希望问题会清楚 假设我有一个StringValidator,一个负责验证字符串的简单类 package test; import java.util.ArrayList; import java.util.List; public class StringVa

一个简单(冗长)的问题,而不是简单的答案。通过使用一些DI框架(Spring、Guice),我得出了一个结论,即其他人提出的一些实践并不是那么容易实现。我似乎真的被困在这个层次上了

我将尽可能简单地介绍这一点,尽管一些细节可能会丢失。我希望问题会清楚

假设我有一个StringValidator,一个负责验证字符串的简单类

package test;

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

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

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

    public StringValidator(final List<String> stringList, final List<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;
    }
}
封装测试;
导入java.util.ArrayList;
导入java.util.List;
公共类字符串验证器{
私人最终名单;
私人最终清单验证清单;
private final List validatedList=new ArrayList();
公共StringValidator(最终列表stringList,最终列表validationList){
this.stringList=stringList;
this.validationList=validationList;
}
public void validate(){
用于(字符串currentString:stringList){
用于(字符串currentValidation:validationList){
if(currentString.equalsIgnoreCase(currentValidation)){
validatedList.add(当前字符串);
}
}
}
}
公共列表getValidatedList(){
返回validatedList;
}
}
依赖性尽可能低,允许进行以下简单测试:

package test;

import org.junit.Assert;
import org.junit.Test;

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

public class StringValidatorTest {
    @Test
    public void testValidate() throws Exception {
        //Before
        List<String> stringList = new ArrayList<String>();
        stringList.add("FILE1.txt");
        stringList.add("FILE2.txt");

        final List<String> validationList = new ArrayList<String>();
        validationList.add("FILE1.txt");
        validationList.add("FILE20.txt");

        final StringValidator stringValidator = new StringValidator(stringList, validationList);

        //When
        stringValidator.validate();

        //Then
        Assert.assertEquals(1, stringValidator.getValidatedList().size());
        Assert.assertEquals("FILE1.txt", stringValidator.getValidatedList().get(0));
    }
}
封装测试;
导入org.junit.Assert;
导入org.junit.Test;
导入java.util.ArrayList;
导入java.util.List;
公共类StringValidator测试{
@试验
public void testValidate()引发异常{
//以前
List stringList=新建ArrayList();
添加(“FILE1.txt”);
添加(“FILE2.txt”);
最终列表验证列表=新的ArrayList();
add(“FILE1.txt”);
添加(“FILE20.txt”);
最终StringValidator StringValidator=新的StringValidator(stringList,validationList);
//什么时候
stringValidator.validate();
//然后
Assert.assertEquals(1,stringValidator.getValidatedList().size());
Assert.assertEquals(“FILE1.txt”,stringValidator.getValidatedList().get(0));
}
}
如果我们想增加更多的灵活性,我们可以使用集合而不是列表,但我们假设这是不必要的

创建列表的类如下(使用任何其他接口标准):

封装测试;
导入java.util.List;
可串接的公共接口{
List getStringList();
}
包装试验;
导入java.util.ArrayList;
导入java.util.List;
公共类StringService实现了Stringable{
private List stringList=new ArrayList();
公共服务(){
createList();
}
//简化
私有void createList(){
添加(“FILE1.txt”);
stringList.add(“FILE1.dat”);
stringList.add(“FILE1.pdf”);
stringList.add(“FILE1.rdf”);
}
@凌驾
公共列表getStringList(){
返回字符串列表;
}
}
以及:

封装测试;
导入java.util.List;
可验证的公共接口{
List getValidationList();
}
包装试验;
导入java.util.ArrayList;
导入java.util.List;
公共类ValidationService实现可验证的{
private final List validationList=new ArrayList();
公共验证服务(){
createList();
}
//简化的。。。
私有void createList(){
add(“FILE1.txt”);
add(“FILE2.txt”);
add(“FILE3.txt”);
add(“FILE4.txt”);
}
@凌驾
公共列表getValidationList(){
返回验证列表;
}
}
我们有一个主类和一个主方法:

package test;

import java.util.List;

public class Main {
    public static void main(String[] args) {
        Validateable validateable = new ValidationService();
        final List<String> validationList = validateable.getValidationList();

        Stringable stringable = new StringService();
        final List<String> stringList = stringable.getStringList();

        //DI
        StringValidator stringValidator = new StringValidator(stringList, validationList);
        stringValidator.validate();

        //Result list
        final List<String> validatedList = stringValidator.getValidatedList();
    }
}
封装测试;
导入java.util.List;
公共班机{
公共静态void main(字符串[]args){
Validateable Validateable=新的ValidationService();
最终列表validationList=validatable.getValidationList();
Stringable Stringable=新的StringService();
最终列表stringList=stringable.getStringList();
//DI
StringValidator StringValidator=新的StringValidator(stringList,validationList);
stringValidator.validate();
//结果表
最终列表validatedList=stringValidator.getValidatedList();
}
}
假设这些类在运行时(当用户需要时)生成列表。 “直接”(静态)绑定是不可能的

如果我们希望提供尽可能低的耦合,我们将使用列表为我们提供运行验证(StringValidator)所需的数据

但是,如果我们想使用容器来帮助我们处理“粘合代码”,我们可以将这两个“服务”注入到StringValidator中。这将为我们提供正确的数据,但代价是耦合。另外,StringValidator将承担实际调用依赖项的额外责任

如果我以这种方式使用委托,我的代码就会被不需要的职责(不是我想要的东西)弄得乱七八糟

如果我不这样做,我就看不出有什么办法可以做到这一点(提供商可以向我提供正确的列表,但依赖性仍然存在)

更一般的问题是-是否有一种方法可以使用DI框架实际创建完全解耦的应用程序,或者这是一种理想的方法? 在哪种情况下你会使用DI框架,而在哪种情况下你不会? DI框架真的是“新”吗?


谢谢。

我有点困惑,但您的意思是希望在不依赖任何类的情况下使用DI吗?使用注释或自定义类加载器可能实现这一点,但这将非常缓慢,而且非常困难。也许你可以澄清一下你想要什么?

我有点困惑,但你的意思是你想要在不依赖任何类的情况下使用DI吗?这可以通过注释或自定义
package test;

import java.util.List;

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

package test;

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

public class ValidationService implements Validateable {

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

    public ValidationService() {
        createList();
    }

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

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

import java.util.List;

public class Main {
    public static void main(String[] args) {
        Validateable validateable = new ValidationService();
        final List<String> validationList = validateable.getValidationList();

        Stringable stringable = new StringService();
        final List<String> stringList = stringable.getStringList();

        //DI
        StringValidator stringValidator = new StringValidator(stringList, validationList);
        stringValidator.validate();

        //Result list
        final List<String> validatedList = stringValidator.getValidatedList();
    }
}
public class Main {
    @Autowired
    private Validateable validateable;
    @Autowired
    private Stringable stringable;

    public void main() {
        final List<String> validationList = validateable.getValidationList();
        final List<String> stringList = stringable.getStringList();
        StringValidator stringValidator = new StringValidator(stringList, validationList);
        stringValidator.validate();
        final List<String> validatedList = stringValidator.getValidatedList();
    }

    public static void main(String[] args) {
        Container container = new ...;
        container.get(Main.class).main();
    }
}
public class StringValidator {
    private SourceOfStrings stringSource;
    private SourceOfStrings validationStringSource;

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

    ...

    public void validate() {
        for (String currentString : stringSource.getStrings()) {
            for (String currentValidation : validationStringSource.getStrings()) {
                if (currentString.equalsIgnoreCase(currentValidation)) {
                    validatedList.add(currentString);
                }
            }
        }
    }

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

interface SourceOfStrings {
    List<String> getStrings();
}
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 java.util.ArrayList;

@Component
public class ValidationList extends ArrayList<String> {
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd         http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <context:component-scan base-package="test"/>

    <!--<bean id="validationList" class="java.util.ArrayList" scope="singleton"/>-->
    <!--<bean id="stringList" class="java.util.ArrayList" scope="singleton"/>-->
</beans>
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;
        createList();
    }

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

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

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;
        createList();
    }

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

    @Override
    public List<String> getValidationList() {
        return validationList;
    }
}
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 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;

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

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

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