Каков порядок оценки @Autowiring в проекте SpringBoot

Я пытаюсь написать простой контроллер SprintBoot REST для работы в Websphere Liberty, и у меня проблема с @Autowire. Вот соответствующие (как мне кажется) фрагменты кода:

@CrossOrigin
@RestController
@RequestMapping(path = "userSetting")
public class RESTInterface {

    @Autowired
    private UserSettingDAO userSettingDAO;

    @RequestMapping(path = "/getUserSetting", method = { RequestMethod.GET }, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String getUserSetting(
            @RequestParam(value = "user_id", required=true ) String user_id, 
            @RequestParam(value = "app_id", required=true )  String app_id,
            @RequestParam(value = "dashboard_name", required=true ) String dashboard_name 
            ) {
        if ( userSettingDAO == null ) {
            System.out.println( "userSettingDAO is null" );
    ...

////////////////////////////////////////////////////////////////////////////////

@Component
 public class UserSettingDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private DataSource dataSource;

     public UserSettingDAO() {
        System.out.println( "dataSource is " + dataSource );
        System.out.println( "jdbcTemplate is " + jdbcTemplate );

Когда я развертываю приложение в Liberty, оно запускается нормально. Когда я попадаю в соответствующую конечную точку, я вижу в console.info следующее:

UserSettingDAO.jdbcTemplate = null
dataSource is null
jdbcTemplate is null
2018-04-24 16:54:19.887  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/userSetting/getUserSetting],methods=[GET],produces=[application/json;charset=UTF-8]}" onto public java.lang.String com.ui.usersetting.restinterface.RESTInterface.getUserSetting(java.lang.String,java.lang.String,java.lang.String)
2018-04-24 16:54:19.890  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/userSetting/upsertUserSetting],methods=[POST],produces=[application/json;charset=UTF-8]}" onto public void com.ui.usersetting.restinterface.RESTInterface.upsertUserSetting(java.lang.String,java.lang.String,java.lang.String,java.lang.String)
2018-04-24 16:54:19.891  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/userSetting/deleteUserSetting],methods=[DELETE],produces=[application/json;charset=UTF-8]}" onto public void com.ui.usersetting.restinterface.RESTInterface.deleteUserSetting(java.lang.String,java.lang.String,java.lang.String)
2018-04-24 16:54:19.893  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/userSetting/hello],methods=[GET],produces=[application/json;charset=UTF-8]}" onto public java.lang.String com.ui.usersetting.restinterface.RESTInterface.hello()
2018-04-24 16:54:19.924  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-04-24 16:54:19.925  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-04-24 16:54:20.166  INFO 8807 --- [cutor-thread-11] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6a5997f7: startup date [Tue Apr 24 16:54:15 EDT 2018]; root of context hierarchy
2018-04-24 16:54:21.386  INFO 8807 --- [cutor-thread-11] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-04-24 16:54:21.389  INFO 8807 --- [cutor-thread-11] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-04-24 16:54:21.396  INFO 8807 --- [cutor-thread-11] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]

Мой вопрос: почему два оператора println говорят, что их соответствующие переменные равны нулю? Связано ли это с тем, что в журнале появляется конструктор UserSettingDAO для выполнения перед, в журнале появляются строки о dataSource?

Что я делаю должен, чтобы эти переменные правильно инициализировались?

у вас есть spring.datasource.url, сконфигурированный в вашем application.properties? Проверьте docs.spring.io/spring-boot/docs/current/reference/html/… для справки

Andy Guibert 25.04.2018 00:24

Да, вместе с spring.datasource.driver-class-name, spring.datasource.username и spring.datasource.password.

Mark Lavin 25.04.2018 02:32

Я бы действительно предложил использовать Java EE API, такие как JAX-RS, CDI, JPA на Liberty вместо Spring Boot. Он лучше интегрирован и поддерживается, в том числе с помощью инструментов.

Gas 25.04.2018 17:16
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
1
3
66
1

Ответы 1

Во время вызова конструктора компонента Spring все объекты @Autowired по-прежнему будут иметь значение NULL. Это связано с тем, что контейнер Spring должен инициализировать экземпляр класса, прежде чем он сможет вводить значения в поля @Autowired.

Я не знаю, как Spring реализует инъекцию, но большинство инъекций Java работает примерно так:

  1. Создайте новый экземпляр класса bean-компонента, обычно вызывая ctor по умолчанию (или инициализируя динамически сгенерированный прокси подкласса)
  2. Получите объекты, которые нужно ввести в bean-компонент
  3. Используя отражение / прокси, установите поля на bean-компоненте

Чтобы проверить это, я создал на UserSettingsDAO метод, который использует поля @AutoWired:

@Component
public class UserSettingDAO {

   @Autowired
   private JdbcTemplate jdbcTemplate;

   @Autowired
   private DataSource ds;

   public UserSettingDAO() {
       System.out.println("ctor/jdbcTemplate is " + jdbcTemplate );
       System.out.println("ctor/datasource is: " + ds);
   }

   public void doStuff() {
       System.out.println("doStuff/jdbcTemplate is " + jdbcTemplate );
       System.out.println("doStuff/datasource is: " + ds);
   }
}

Если мы внедрим этот DAO в другой класс и будем использовать его, мы увидим, что поля инициализируются после создания UserSettingDAO:

@CrossOrigin
@RestController
public class RESTInterface {

    @Autowired
    private UserSettingDAO dao;

    @RequestMapping(path = "/jdbc", method = { RequestMethod.GET }, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String jdbc() {
        return dao.doStuff();
    }
}

При проверке журналов будет получен следующий результат:

ctor/jdbcTemplate is null
ctor/datasource is: null
doStuff/jdbcTemplate is org.springframework.jdbc.core.JdbcTemplate@4eb46bed
doStuff/datasource is: com.ibm.ws.rsadapter.jdbc.WSJdbcDataSource@727d23c5

Другие вопросы по теме