V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhongpingjing
V2EX  ›  Java

实现 ApplicationContextAware 接口, ApplicationContext 为 null 问题

  •  
  •   zhongpingjing · 2022-06-15 18:08:59 +08:00 · 2346 次点击
    这是一个创建于 891 天前的主题,其中的信息可能已经有所发展或是发生改变。

    主要封装一些获取 bean 的方法,代码如下:

    @Component
    public class SpringUtils implements ApplicationContextAware {
    
        /**
         * 上下文对象实例
         */
        private static ApplicationContext context = null;
    
        @Override
        @Autowired
        public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
            context = applicationContext;
            log.info("Inject applicationContext succeeded");
        }
        
        public static ApplicationContext getApplicationContext() {
            if (context == null) {
                throw new IllegalArgumentException("ApplicationContext wasn't injected");
            }
            return context;
        }
    }
    
    

    在其他 bean 的构造方法里面调用SpringUtils.getApplicationContext。 奇怪的是,在 idea 启动正常,打包部署的时候就会抛错IllegalArgumentException

    网上一推解法都试过了,都没用。 请求大佬支援。

    17 条回复    2022-06-16 10:48:05 +08:00
    agzou
        1
    agzou  
       2022-06-15 18:19:57 +08:00
    目测,@Autowired 问题,有试过把 @Autworied 去掉吗,实现了 ApplicationContextAware 接口,不需要再用 @Autowired
    fzdwx
        2
    fzdwx  
       2022-06-15 18:20:58 +08:00
    没问题
    justRua
        3
    justRua  
       2022-06-15 19:53:28 +08:00
    本地 debug 可以但是打包后不行,可能是打的包有问题,可以远程 debug 看看启动时会不会进 setApplicationContext
    Red998
        4
    Red998  
       2022-06-15 20:04:56 +08:00
    SpringUtils. context= applicationContext; 需要指向
    不需要 @Autowired 这个 spring 生命周期会回调接口
    fmumu
        5
    fmumu  
       2022-06-15 20:15:50 +08:00
    1 是 ApplicationContextAware 的的调用和 bean 的初始化先后问题
    2 是在其他 bean 的初始化为什么要用这个 utils,依赖其他 bean 的话用构造器注入不就好了
    BBCCBB
        6
    BBCCBB  
       2022-06-15 20:24:00 +08:00
    你是不是在这个 setApplicationContext 方法完成之前就调用了 getApplicationContext? 还有就是实现接口的方法上不需要加 @Autowired
    zhongpingjing
        7
    zhongpingjing  
    OP
       2022-06-16 09:27:57 +08:00
    @agzou
    @redorblacck886
    @fmumu
    @BBCCBB 没加 @Autowired 也不行啊
    zhongpingjing
        8
    zhongpingjing  
    OP
       2022-06-16 09:28:54 +08:00
    @BBCCBB 我在其他 bean 的构造方法调了,可能这个 bean 比 SpringUtils 先加载?
    agzou
        9
    agzou  
       2022-06-16 09:34:59 +08:00
    @zhongpingjing #8 调用的 bean 应该在初始完之后调用,实现 InitializingBean 接口 afterPropertiesSet 方法,或者使用 @PostConstruct ,在构造方法里面不能保证其他 bean 给初始化了
    zhongpingjing
        10
    zhongpingjing  
    OP
       2022-06-16 09:49:52 +08:00
    @fmumu
    1.我也感觉是顺序问题,但是我用了 @Order ,指定了高优先级也一样的错误,想知道怎么能让 utils 最先加载
    2.构造器注入不准确,因为被注入的 bean ,有两个泛型<T ,确定类型>,会注入不需要的 bean ,所以要使用了 getBeanProvider 来手动注入
    zhongpingjing
        11
    zhongpingjing  
    OP
       2022-06-16 09:53:28 +08:00
    @agzou 目前是打算按你这样说改造了,如果这个问题找不到原因的话
    zhongpingjing
        12
    zhongpingjing  
    OP
       2022-06-16 09:56:16 +08:00
    @justRua 会进的,不在其他 bean 里面调用 getApplicationContext ,最后能打印 Inject applicationContext succeeded 。感觉是调用顺序问题,就是 idea 启动 utils 能在其他 bean 先加载,打包后就反了
    BBCCBB
        13
    BBCCBB  
       2022-06-16 09:58:38 +08:00
    > 我在其他 bean 的构造方法调了

    你在构造方法里调用这个? bean 加载的顺序不固定. 你可以试试 @DependsOn

    或者在其他 bean 里监听 @ApplicationReadyEvent 来做初始化.

    @Order 对 bean 的加载没用, 只对 interceptor 这些 aop 有用.
    cppc
        14
    cppc  
       2022-06-16 10:30:30 +08:00
    @zhongpingjing order 不是这样用的哦。你要想"要求" SpringUtils 在初始化(构造方法)时必须可用,最简单的方法就是在构造方法中添加一个 SpringUtils 类型参数,这样 Spring 就知道依赖关系了。

    ```java

    @Service
    public class MyService {

    // 如果要确保在 bean 初始化期间用到另一个 bean
    public MyService (SpringUtils utils){
    assert utils != null;
    }

    // 你自己能确认 SpringUtils 已经初始化的情况下,才能直接使用,比如应用已经启动了
    @EventListener
    public void doIt(ApplicationStartedEvent evt){
    assert SpringUtils.getApplicationContext() != null;
    }

    }

    ```

    总之,要么你自己确保依赖关系正确,要么给 Spring 足够的提示,让他帮你管理。
    zhongpingjing
        15
    zhongpingjing  
    OP
       2022-06-16 10:32:50 +08:00
    @BBCCBB 看来确实是顺序问题,加上 @DependsOn 就好了
    zhongpingjing
        16
    zhongpingjing  
    OP
       2022-06-16 10:34:54 +08:00
    @cppc 嗯嗯,确实是顺序问题,把依赖顺序明确了后就行了,神奇的地方就是 idea 启动正常,打包启动就不正常
    BBCCBB
        17
    BBCCBB  
       2022-06-16 10:48:05 +08:00
    不建议这样用哈, 启动阶段依赖 applicationContext 的地方, 采用注入 ApplicationContext 字段, 在 afterPropertiesSet 里执行初始化, 启动完成后可以用你这个工具类.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2790 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 13:46 · PVG 21:46 · LAX 05:46 · JFK 08:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.