尝试获取已定义的Component时NoSuchBeanDefinitionException

时间:2018-02-25 14:02:49

标签: java spring inversion-of-control preferences

使用Spring IoC时,我遇到了从应用程序上下文中获取bean的问题。

我的电话簿应用程序有‘Security Definer’界面,此界面有3个实现。所有实现都是Spring @Components。我还有一个ContactProvider,它存储了用户使用的实现。当用户尝试更改实现时,应用程序将抛出NoSuchBeanDefinitionException。为了找出用户想要根据其输入使用哪个实现,我创建了实用程序枚举,其中包含为所有实现提供Preferences个对象的所有实现。这个类有Class方法,它根据给定的字符串(用户输入)返回实现类型。

设置新联系人提供者的方法:

fromString()

ContactProviders枚举,我从中获取了一类实现:

private void handleSetProviderCommand(String param) {

        ContactProviders providerType = ContactProviders.fromString(param);
        Class<? extends ContactProvider> providerClass = providerType.getProviderClass();

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        ContactProvider contactProvider = context.getBean(providerClass); // I get NoSuchBeanDefinitionException here
        phoneBook.setContactProvider(contactProvider);

        Preferences preferences = Preferences.userNodeForPackage(PhoneBook.class);
        preferences.put(PreferenceKeys.CONTACT_PROVIDER.getKey(), param);
    }

其中一个实现(所有这些实现都使用@Component注释):

    public enum ContactProviders {
        FILE(FileContactProvider.SHORT_NAME, FileContactProvider.class),
        ELASTIC(ElasticContactProvider.SHORT_NAME, ElasticContactProvider.class),
        NO_SQL(NoSqlContactProvider.SHORT_NAME, NoSqlContactProvider.class);

        private final Class<? extends ContactProvider> providerClass;
        private final String shortName;

        ContactProviders(String shortName, Class<? extends ContactProvider> providerClass) {
            this.shortName = shortName;
            this.providerClass = providerClass;
        }

        public static ContactProviders fromString(String param) {
            Optional<ContactProviders> providerType = Arrays.stream(ContactProviders.values())
                    .filter(cp -> cp.getShortName().equals(param)).findFirst();
            if (providerType.isPresent()) {
                return providerType.get();
            } else {
                throw new IllegalArgumentException("Contact provider not recognized: " + param);
            }
        }
    }

我的@Configuration类中还定义了一个bean,用于根据系统中已设置的首选项提供联系提供程序。它接受首选项字符串并创建实现类的实例以返回:

public class FileContactProvider implements ContactProvider {

    public static final String SHORT_NAME = "file";

    private static final String SEPARATOR = "|";

    private List<Contact> contacts;
    private Path file;
    private Logger logger = LoggerFactory.getLogger(FileContactProvider.class);

    public FileContactProvider() {
        file = openFile();
        contacts = loadContacts();
    }

    private Path openFile() {
        Preferences preferences = Preferences.userNodeForPackage(FileContactProvider.class);
        Path file = Paths.get(
                preferences.get(
                        PreferenceKeys.FILE_FILE_NAME.getKey(),
                        PreferenceKeys.FILE_FILE_NAME.getDefaultValue()
                )
        );
        if (Files.exists(file)) {
            try {
                if (Files.isReadable(file) && Files.isWritable(file)) {
                    return file;
                } else {
                    throw new IOException("The file is not readable or writable.");
                }
            } catch (IOException e) {
                logger.error("Error while opening the file: " + e.getMessage());
            }
        } else {
            try {
                Files.createFile(file);
            } catch (IOException e) {
                logger.error("Error while creating a file: " + e.getMessage());
            }
        }
        return file;
    }

    private void saveFile() {
        List<String> contactStrings = new ArrayList<>();
        contacts.stream()
                .sorted()
                .forEach(contact -> contactStrings.add(contact.getName() + SEPARATOR + contact.getNumber()));
        try {
            Files.write(file, contactStrings);
        } catch (IOException e) {
            logger.error("Error while saving to the file: " + e.getMessage());
        }
    }

    private List<Contact> loadContacts() {
        List<Contact> loaded = new ArrayList<>();

        try {
            Files.readAllLines(file)
                    .forEach(line -> {
                        String[] contactString = StringUtils.split(line, SEPARATOR);
                        Contact contact = new Contact(contactString[0], contactString[1]);
                        loaded.add(contact);
                    });
        } catch (IOException e) {
            logger.error("Error while reading file content: " + e.getMessage());
        }

        return loaded;
    }

    @Override
    public Contact save(Contact contact) {
        if (contacts.contains(contact)) {
            System.out.println("Contact is already in the phone book.");
        } else {
            contacts.add(contact);
            saveFile();
        }
        return contact;
    }

    @Override
    public List<Contact> find(String name) throws ContactNotFoundException {
        List<Contact> found = contacts.stream()
                .filter(contact -> StringUtils.indexOf(contact.getName().toLowerCase(), name.toLowerCase()) != -1)
                .collect(Collectors.toList());

        if (found.isEmpty()) {
            throw new ContactNotFoundException(name);
        }

        return found;
    }

    @Override
    public List<Contact> getAll() {
        return contacts;
    }

    @Override
    public void delete(Contact contact) {
        contacts.remove(contact);
        saveFile();
    }

    @Override
    public void configure() {
        System.out.print("Enter file name: ");
        String filename = ConsoleUtils.getInput("^[^<>:;,?\"*|/]+$");

        Preferences preferences = Preferences.userNodeForPackage(FileContactProvider.class);
        preferences.put(PreferenceKeys.FILE_FILE_NAME.getKey(), filename);

        file = openFile();
        contacts = loadContacts();
    }

    @Override
    public void showConfiguration() {
        Preferences preferences = Preferences.userNodeForPackage(FileContactProvider.class);
        System.out.println("File name: " +
                preferences.get(
                        PreferenceKeys.FILE_FILE_NAME.getKey(),
                        PreferenceKeys.FILE_FILE_NAME.getDefaultValue()
                )
        );
    }
}

0 个答案:

没有答案