如何将BeanFactory转换为ApplicationContext以获取配置属性?
先纠正你代码里的错误
你直接把ConfigurableListableBeanFactory强转为ApplicationContext是行不通的,这两个接口属于不同层级——ApplicationContext是包含BeanFactory的上层容器,ConfigurableListableBeanFactory的实例本身并不是ApplicationContext,强转必然会抛出ClassCastException。
最优方案:直接从BeanFactory获取Environment(无需ApplicationContext)
其实你根本不需要绕到ApplicationContext,ConfigurableListableBeanFactory的父接口ConfigurableBeanFactory已经提供了getEnvironment()方法,直接用它就能读取配置文件里的值:
@Slf4j @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { // 直接从factory获取Environment ConfigurableEnvironment environment = factory.getEnvironment(); String dependsOnValue = environment.getProperty("business.bean.dependsOn"); // 在这里使用配置值 log.info("获取到配置business.bean.dependsOn:{}", dependsOnValue); } @Override public int getOrder() { return PriorityOrdered.HIGHEST_PRECEDENCE; } }
如果确实需要获取ApplicationContext
如果你有其他场景必须拿到ApplicationContext,可以用以下两种方式,但都有局限性:
反射方式(依赖Spring内部实现,不推荐):
Spring的AbstractAutowireCapableBeanFactory(DefaultListableBeanFactory的父类)持有applicationContext引用,可以通过反射获取:@Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { try { Field ctxField = AbstractAutowireCapableBeanFactory.class.getDeclaredField("applicationContext"); ctxField.setAccessible(true); ApplicationContext applicationContext = (ApplicationContext) ctxField.get(factory); // 拿到ApplicationContext后操作 ConfigurableEnvironment environment = applicationContext.getEnvironment(); String dependsOnValue = environment.getProperty("business.bean.dependsOn"); } catch (NoSuchFieldException | IllegalAccessException e) { log.error("获取ApplicationContext失败", e); } }注意:这种方法依赖Spring的内部字段,版本升级可能导致失效。
实现ApplicationContextAware接口(仅适用于postProcessBeanFactory之后的阶段):
让你的类同时实现ApplicationContextAware,但要注意这个接口的setApplicationContext回调是在Bean实例化、属性注入之后执行的,也就是说在postProcessBeanFactory方法执行时,ApplicationContext还没被注入,只能在后续的bean生命周期方法(比如@PostConstruct)中使用:@Slf4j @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered, ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { // 这里applicationContext还没赋值,无法使用 } @PostConstruct public void doSomethingAfterInit() { // 初始化完成后可以使用ApplicationContext ConfigurableEnvironment environment = applicationContext.getEnvironment(); String dependsOnValue = environment.getProperty("business.bean.dependsOn"); log.info("初始化后获取配置:{}", dependsOnValue); } @Override public int getOrder() { return PriorityOrdered.HIGHEST_PRECEDENCE; } }
内容的提问来源于stack exchange,提问作者jianhua Lee

