@Injected @ManagedBean переинициализируется, несмотря на аннотацию @ApplicationScoped
Я пишу простое приложение JSF для конвертации валют.
E сть Rates
класс, который содержит данные, Currencies
класс для управления запросами и Manage
класс для добавления новых валют. Моя проблема: я хочу, чтобы валюты сохранялись как свойство класса Rates, поэтому я использую @ApplicationScoped
, Однако я вижу, что Rates
продолжает переинициализироваться с каждым запросом. Вот мой код Rates
:
@ManagedBean
@ApplicationScoped
public class Rates {
private Map<String, Double> rates = new HashMap<String, Double>();
private Set<String> currencies = new HashSet<String>(){
{
System.out.println("HashSet initializing");
}
};
private List<String> list = new ArrayList<String>(Arrays.asList("Filip", "Kasia"));
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Rates() {
rates.put("PLN_EUR", 0.25);
rates.put("EUR_PLN", 4.0);
currencies.add("PLN");
currencies.add("EUR");
}
public Map<String, Double> getRates() {
return rates;
}
public void setRates(Map<String, Double> rates) {
this.rates = rates;
}
public Set<String> getCurrencies() {
return currencies;
}
public void setCurrencies(Set<String> currencies) {
this.currencies = currencies;
}
public void addRate(String firstCurrency, String secondCurrency){
if(rates.containsKey(firstCurrency + "_" + secondCurrency))
return;
double rate = (double)(Math.random()*10);
rates.put(firstCurrency + "_" + secondCurrency, rate);
rates.put(secondCurrency + "_" + firstCurrency, 1 / rate);
currencies.add(firstCurrency);
currencies.add(secondCurrency);
System.out.println(currencies);
}
public double getRate(String currencies){
return rates.get(currencies);
}
}
и вот как это впрыскивается:
@ManagedBean
public class Manage {
private String firstCurrency;
private String secondCurrency;
private @Inject Rates rates;
public String getSecondCurrency() {
return secondCurrency;
}
public void setSecondCurrency(String secondCurrency) {
this.secondCurrency = secondCurrency;
}
public String getFirstCurrency() {
return firstCurrency;
}
public void setFirstCurrency(String firstCurrency) {
this.firstCurrency = firstCurrency;
}
public void addCurrencies(){
rates.addRate(firstCurrency, secondCurrency);
}
}
Как видите, я добавил инициализатор экземпляра для свойства Rates, установите currencies
и текст "Инициализация HashSet" распечатывается с каждым запросом.
1 ответ
@Inject
только вводит управляемые компоненты CDI.
@ManagedBean
объявляет управляемый компонент JSF не управляемым компонентом CDI.
Сделать Rates
вместо этого классифицируйте управляемый компонент CDI.
import javax.inject.Named;
import javax.enterprise.context.ApplicationScoped;
@Named
@ApplicationScoped
public class Rates {}
Следует отметить, что общая рекомендация состоит в том, чтобы прекратить использование средства управляемых компонентов JSF и использовать исключительно средство управляемых компонентов CDI. Поэтому было бы лучше, если бы вы делали все остальные управляемые bean-компоненты JSF также управляемыми bean-компонентами CDI. Именно поэтому я бы не рекомендовал заменить @Inject
его эквивалентом JSF @ManagedProperty
(что бы тоже сработало).
Что касается инициализации управляемого компонента, вам не следует делать это на уровне класса / экземпляра, а выполнять задачу в @PostConstruct
аннотированный метод.
private Map<String, Double> rates;
private Set<String> currencies;
private List<String> list;
@PostConstruct
public void init() {
rates = new HashMap<>();
currencies = new HashSet<>();
list = new ArrayList<>(Arrays.asList("Filip", "Kasia"));
}
Это особенно важно в CDI, потому что он создает и внедряет прокси на основе класса, поэтому класс может быть создан в моменты, когда вы этого не ожидаете.