Разница между получением компонента через метод контроллера и ApplicationContext

#java #spring #autowired

#java #весна #автоматическое подключение

Вопрос:

Возникли проблемы с получением экземпляров компонента из методов контроллера через SpringApplicationContext. То, что мне требуется в моем методе контроллера, — это хорошо заполненный экземпляр класса B . Определение класса B приведено ниже:

 @Component
public class ADep {

}

@Component
public class A {
    @Autowired
    private ADep aDep;

    public void printDep() {
        System.out.println("aDep is "   aDep);
    }
}

@Component
public class B extends A {
    public void printAMethod() {
        super.printDep();
    }
}
  

При вызове следующего метода контроллера:

 @CrossOrigin
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE, path = "/method1")
public MappingJacksonValue method1(HttpServletRequest request, HttpServletResponse response, B b) throws Exception {
    b.printAMethod();
    return null;
}
  

Я вижу следующий ответ:

 aDep is null
  

Вместо получения компонента в методе контроллера, если я получаю его из контекста приложения, ответ будет другим:

 @Autowired
private ApplicationContext applicationContext;

@CrossOrigin
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE, path = "/hardware")
public MappingJacksonValue getHardware(HttpServletRequest request, HttpServletResponse response) throws Exception {
    B b = applicationContext.getBean(B.class);
    b.printAMethod();
    return null;
}
  

Результат:

 aDep is ADep@2e468dfa
  

Что мне требуется, так это экземпляр компонента, как в последнем случае. Как я могу получить это в методе контроллера без использования SpringApplicationContext?

Комментарии:

1. В вашем первом случае b это параметр метода. Не могу сказать, как вы вызываете этот метод, но, скорее всего, вы переходите null в него

2. Аргумент метода никогда не будет автоматически подключен, будут только зависимости на уровне класса. Если только вы не прибегнете к полномасштабному использованию AspectJ (компиляция или переплетение времени загрузки) и не используете @Configured . Итак, зачем вам нужен B как для привязки, так и для автоматической проводки?

3. @M.Deinum, не знал, что экземпляры становятся доступными по-разному в случае вызова метода через автоматически подключаемую переменную экземпляра. Есть ли какой-либо способ получить функциональность типа Autowire для аргумента метода? Пробовал автозапуск в переменной метода, но не получил никакой разницы.

4. Нет. Вы не можете ввести компонент в аргумент метода. Если только вы не напишете свою собственную реализацию a HandlerMethodArgumentResolver , которая это делает. Но зачем вам вообще нужен объект autowired в методе? Вместо того, чтобы вводить его на уровне класса.

5. Я не могу установить область действия класса B для запроса. Следовательно, любое значение, установленное в предыдущих запросах, сохраняется в переменной экземпляра класса B.

Ответ №1:

Вы пытаетесь передать объект b типа B в качестве параметра, поэтому в этом случае вы должны создать и передать объект b и передать его методу, я думаю, вы присваиваете этому аргументу нулевое значение, но если вы хотите, вы можете использовать @Autowired вместо контекста приложения, потому чтоB уже является компонентом, например:

 @Autowired
private B b;

@CrossOrigin
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE, path = "/hardware")
public MappingJacksonValue getHardware(HttpServletRequest request, HttpServletResponse response) throws Exception {
    b.printAMethod();
    return null;
}
  

Редактировать:

Чтобы изменить область действия компонента, другого компонента для другого запроса, вы можете добавить @Scope(value = WebApplicationContext.SCOPE_REQUEST) аннотацию над B классом

Комментарии:

1. Верно, что компонент здесь хорошо вводится. С областью действия по умолчанию один и тот же экземпляр становится общим для всех запросов и, таким образом, сохраняет поля, установленные в предыдущих запросах.

2. Вы можете изменить область действия компонента B, если хотите, для запроса scoped .

Ответ №2:

Параметр в вашем методе предоставляется Spring MVC-распознавателем аргументов. Здесь он не вводит компонент. Я немного удивлен, что в этом случае значение b не равно null, возможно, поведение по умолчанию заключается в создании нового экземпляра этого класса, и в этом случае, конечно, aDep равно null .