• 线上问题:如何在静态方法中使用自动装配的对象(通过@PostConstruct初始化对象)


    1 场景复现

    为了在静态方法中使用自动装配的对象,
    通过新建对象(new Object())的方式调用自动装配的对象,
    但是,执行时使用自动装配的对象时出现空指针,即新建的对象并没有初始化当前类中的自动装配属性。
    异常的样例如下:

    package com.monkey.standalone.modules.user.service.impl;
    
    import com.monkey.standalone.modules.user.dao.UserDAO;
    import com.monkey.standalone.modules.user.service.IUserService;
    import com.monkey.standalone.modules.user.vo.BaseUserVO;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    /**
     * 用户服务实现类.
     *
     * @author xindaqi
     * @date 2021-05-08 16:01
     */
    @Service
    public class UserServiceImpl implements IUserService {
    
        private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    
        @Resource
        UserDAO userDAO;
    
        public static void testNew() {
            try {
                // 只新建了对象,并没有初始化自动装配的属性:userDAO
                UserServiceImpl userService = new UserServiceImpl();
                // 自动装配的属性userDAO没有初始化,所以userDAO为null
                BaseUserVO baseUserVO = userService.userDAO.queryUserById(1);
                logger.info(">>>>>>>>>User:{}", baseUserVO);
            } catch (Exception ex) {
                logger.error(">>>>>>>User error:", ex);
                throw new RuntimeException(ex);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    异常信息如下图所示,由异常信息可知,使用自动装配的属性userDAO时出现空指针。
    在这里插入图片描述

    2022-11-13 21:11:36,654 ERROR [traceId=, spanId=] 2022-11-13 21:11:36 [http-nio-9122-exec-4] [ERROR] - >>>>>>>User error:
    java.lang.NullPointerException: null
    at com.monkey.standalone.modules.user.service.impl.UserServiceImpl.testNew(UserServiceImpl.java:46)
    at com.monkey.standalone.api.UserApi.queryUserById(UserApi.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)

    2 原因

    通过new新建对象后,并没有初始化对应的属性:userDAO,所以userDAO属性为null,
    无法使用该属性对应的其他所有功能。
    @Service初始化相关对象时,会交由Spring容器管理,
    因此,@Resoure会自动获取Spring会初始化相关对象,userDAO才会生效,
    而使用new新建的对象并不会托管给Spring,所以,其他的属性不会自动初始化。

    3 方案

    为解决新建对象后相关属性为null的问题,需要在新建对象后初始化相关属性。
    为了获取已装配的对象,就要在当前类完成依赖注入之后,执行相关的初始化操作,
    而@PostConstructor正是在执行依赖注入之后执行初始化操作的注解,@PostConstruct部分注释如下图所示:
    在这里插入图片描述

    使用@PostConstruct后处理(装配)静态对象。
    在当前类中构建静态的当前类属性,
    使用@PostConstruct初始化静态的当前类属性,并初始化需要使用的已装配的对象,
    完整测试样例如下:

    package com.monkey.standalone.modules.user.service.impl;
    
    import com.monkey.standalone.modules.user.dao.UserDAO;
    import com.monkey.standalone.modules.user.service.IUserService;
    import com.monkey.standalone.modules.user.vo.BaseUserVO;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.Resource;
    
    /**
     * 用户服务实现类.
     *
     * @author xindaqi
     * @date 2021-05-08 16:01
     */
    @Service
    public class UserServiceImpl implements IUserService {
    
        private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
    
        public static UserServiceImpl userServiceImpl;
    
        @Resource
        UserDAO userDAO;
    
        @PostConstruct
        public void init() {
            userServiceImpl = this;
            // 初始化已自动装配的对象
            userServiceImpl.userDAO = this.userDAO;
        }
    
        public static void testAutowired() {
            // 通过静态的当前类属性获取相关方法
            BaseUserVO baseUserVO = userServiceImpl.userDAO.queryUserById(1);
            logger.info(">>>>>>>>>User:{}", baseUserVO);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
  • 相关阅读:
    基于二维小波变换的散斑相位奇异构造算法matlab仿真
    SpringMVC--@RequestMapping注解
    Telnet协议详解
    Redis功能实战篇之Session共享
    vlookup函数踩坑(wps)
    数字IC设计笔试题汇总(四):一些基础知识点
    数据结构与算法之美学习笔记:20 | 散列表(下):为什么散列表和链表经常会一起使用?
    Anaconda中同一个虚拟环境安装pytorch和tensorflow
    SpringBoot跨域设置(CORS)
    驱动——LED灯循环闪烁
  • 原文地址:https://blog.csdn.net/Xin_101/article/details/127825776