弹簧动态注射,出厂样式 [英] Spring dynamic injection, factory-like pattern

查看:332
本文介绍了弹簧动态注射,出厂样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从。



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



编辑: / p>

我发现更好的示例在Spring文档中 - 我觉得很清楚。
查看3.4.6.1查找方法注入



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



祝你好运!


A continuation from Dependency injection, delayed injection praxis. I have the Main class:

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

And the object graph is dynamically created, depending on the user interaction. I solved the application coupling, allowing me to test this very simply. Also, since the lists are maintained by the container, the dynamic nature of this application(and every other) is irrelevant, since they can be requested any time the application needs them, maintaining their elements.

The rest of the code is here:

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;
    }
}

Does anyone know how would I solve the method call createList() or createSecondList() - without using the constructor which pretty much forces the design. I was thinking of a factory, but a factory for every class in a project of a bigger magnitude doesn't seem like a good idea.

Something like:

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

And in the factory method instantiate the class and call the method createList(). Or call it like this, from some method - which again looks bad, forcing the method to have the responsibility to instantiate the object graph.

The picture of the runtime dependencies that I want to resolve in runtime is bellow:

Is there some other way I could use the container to achive dynamic lazy initalization depending on the user interaction?

Thank you.

解决方案

If you want some member of your class to be dynamically initialized\populated on every call to the corresponding getter, you can try the Lookup Method Injection. Read pp. 3.3.4.1 here.

So even if the class that contains the dynamic member was created in scope=singletone (the default for spring bean container) every time you will accessthe field that has a lookup method assigned, you will get an appropriate object according to the business logic implemented inside the lookup method. In your case the list is an interface so you can easily implement the validation inside your lookup method and return a validated list.

Edit:

I found better example in Spring documentation - I think it is very clear. Take a look at "3.4.6.1 Lookup method injection"

When you configure the Main class assign a lookup method to its List member - it will be called whenever you need a new instance of the List bean.

Good luck!

这篇关于弹簧动态注射,出厂样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆