@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, потому что он создает и внедряет прокси на основе класса, поэтому класс может быть создан в моменты, когда вы этого не ожидаете.

Смотрите также:

Другие вопросы по тегам