【问题标题】:How to get an instance of @Component in Spring?如何在 Spring 中获取 @Component 的实例?
【发布时间】:2015-03-23 16:22:13
【问题描述】:

我有一个名为 RegistrationValidator 的 @Container 类,它依赖于 spring @Repository。通过自动装配在服务或另一个容器中获取它的实例很好,但我需要在常规 POJO 中访问它。如何在不将所有 POJO 转换为 @Container 或 @Service 对象的情况下获取此验证器的实例。有没有办法在返回实例的 RegistrationValidator 中添加静态 getInstance 方法。

package core.dao.validator;

import core.dao.Registration;
import core.repository.RegistrationRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

/**
 * Validates the Registration DAO.
 *
 * @author Srini Katragadda
 */
@Component
public class RegistrationValidator implements Validator {
    private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationValidator.class);
    private static final int MAX_SIZE = 255;

    private final RegistrationRepository repository;

    @Autowired
    RegistrationValidator(RegistrationRepository repository) {
        this.repository = repository;
    }

    @Override
    public boolean supports(Class clazz) {
        return Registration.class.equals(clazz);
    }

    @Override
    public void validate(Object obj, Errors errors) {
        Registration registration = (Registration) obj;

        // Validate Message Id
        ValidationUtils.rejectIfEmpty(errors, "messageId", "messageId.empty");
        if (registration.getMessageId() != null &&
                registration.getMessageId().length() > MAX_SIZE) 
            errors.rejectValue("messageId", "Size greater than " + MAX_SIZE);

        // Validate for duplicate messageId information
        if (hasDuplicateMessageIdInDatabase(registration)) {
            errors.rejectValue("callouts", "Database has duplicate registration with messageId.");
        }

    }

    /**
     * Check if there is duplicate messageId in database.
     */
    private boolean hasDuplicateMessageIdInDatabase(Registration adsRegistration) {
        return (repository.findByMessageId(adsRegistration.getMessageId()) != null);
    }
}

这里是我需要该验证器实例的地方。检查 Builder.build() 方法,该方法将验证器实例传递给实用程序方法。这工作得很好,直到我需要在 RegistrationValidator 中自动装配一个 @Repository。现在我需要传递存储库的实例才能构造验证器,并且想知道如何不使 DAO 本身成为另一个组件并使用 RegistrationValidator 自动装配它。

package core.dao;

import core.dao.validator.RegistrationValidator;
import core.util.ValidatorUtil;
import core.util.ToString;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/**
 * The data access object that holds the information of an Registration.
 */
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Registration {

    private String id;
    private String messageId;
    private String version;

    public Registration() {
    }

    private Registration(Builder builder) {
        this.id = builder.id;
        this.messageId = builder.messageId;
        this.version = builder.version;
    }

    public static Builder getBuilder() {
        return new Builder();
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getMessageId() {
        return messageId;
    }

    public void setMessageId(String messageId) {
        this.messageId = messageId;
    }

    public String getVersion() {
        return version;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    /**
     * Builder pattern makes the object easier to construct in one line.
     */
    public static class Builder {

        private String id;

        private String messageId;

        private String version;

        private Builder() {}

        public Builder id(String id) {
            this.id = id;
            return this;
        }

        public Builder messageId(String messageId) {
            this.messageId = messageId;
            return this;
        }


        public Builder version(String version) {
            this.version = version;
            return this;
        }

        public Registration build() {
            Registration entry = new Registration(this);
            return (Registration) ValidatorUtil.validate(entry, new RegistrationValidator());
        }
    }
}

为了完整性,这里是 ValidatorUtil.validate 代码。

public static Object validate(Object entry, org.springframework.validation.Validator customValidator) {
    Errors errors = new BeanPropertyBindingResult(entry, entry.getClass().getName());
    customValidator.validate(entry, errors);
    if (errors == null || errors.getAllErrors().isEmpty())
        return entry;
    else {
        LOGGER.error(errors.toString());
        throw new InvalidDataException(errors.getAllErrors().toString(), errors);
    }
}

【问题讨论】:

  • 为什么要在 POJO 中使用它的实例?你能展示用例吗?可能是可以移动到服务类。
  • 更新了更多信息的问题。请看一下。谢谢。
  • 理想情况下,我不会让 validate() 方法与 DB 对话以验证重复项。它应该简单地验证对象的状态(无论它是否处于有效状态)。而已。之后,服务层的工作就是验证完全构造和验证的对象是否重复。
  • 是的,也许这就是我要保持清洁的方式。在一个地方进行所有验证有一些优点,但不会以污染代码为代价。感谢您的帮助。

标签: java spring spring-boot


【解决方案1】:

您可以通过以下方式使用 SpringBeanAutowiringSupport 将 spring bean 自动装配到 pojo 中:

public class Pojo {

@Autowired
private RegistrationRepository repository

    public void methodWhichRequiresBean() {

        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

        repository.doStuff()

     }

希望对你有帮助

【讨论】:

  • repository.doStuff() 返回 NullPointerException,因此存储库未初始化。
  • Pojo 是不是在 spring 初始化这个 bean 之前创建的?
  • 我在这个问题中遇到了类似的问题:stackoverflow.com/questions/28656947/… 我的问题是我在构造函数中使用了 SpringBeanAutowiringSupport 而 bean 仍未创建。我的 pojos 是在注入另一个 spring 服务的一些 Spring 托管工厂中创建的 - 无论如何问题是 Pojos/bean 创建时间。
猜你喜欢
  • 2023-03-19
  • 2016-06-24
  • 2015-07-28
  • 2015-06-12
  • 2020-12-09
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多