什么是SpringBoot项目中@Autowiring的评估顺序

时间:2018-04-24 21:21:14

标签: spring-boot websphere-liberty open-liberty

我正在尝试编写一个简单的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.log中看到以下内容:

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的行出现在日志中这一事实有什么关系?

1 个答案:

答案 0 :(得分:0)

在调用Spring组件的构造函数时,任何@Autowired对象仍将为null。这是因为spring容器需要初始化类的实例才能将值注入@Autowired字段。

我不知道Spring如何实现注入,但大多数Java注入都是这样的:

  1. 构造bean类的新实例,通常是通过调用默认ctor(或初始化动态生成的子类代理)
  2. 获取需要注入bean的对象
  3. 使用反射/代理,设置bean上的字段
  4. 为验证这一点,我在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