Я обнаружил, что два Spring-интерфейса могут быть использованы для реализации того, что мне нужно. Интерфейс BeanNameAware позволяет Spring сообщать объекту его имя в контексте приложения, вызывая метод setBeanName (String) . Интерфейс FactoryBean указывает Spring не использовать сам объект, а объект, возвращаемый при вызове метода getObject () . Соедините их вместе, и вы получите:
public class PlaceholderBean implements BeanNameAware, FactoryBean {
public static Map<String, Object> beansByName = new HashMap<String, Object>();
private String beanName;
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public Object getObject() {
return beansByName.get(beanName);
}
@Override
public Class<?> getObjectType() {
return beansByName.get(beanName).getClass();
}
@Override
public boolean isSingleton() {
return true;
}
}
Определение бина теперь уменьшено до:
<bean id="dataSource" class="PlaceholderBean" />
Заполнитель получает свое значение до создания контекста приложения.
public void run(DataSource externalDataSource) {
PlaceholderBean.beansByName.put("dataSource", externalDataSource);
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
assert externalDataSource == context.getBean("dataSource");
}
Кажется, все работает успешно!