2013-09-20 8 views
3

Я пытаюсь использовать образец ChartBean от PrimeFaces. Это мнение:Конструктор управляемого бина CDI дважды запускается при открытии страницы

<h:form> 
    <p:layoutUnit position="center">    
    <p:lineChart id="linear" value="#{chartBean.linearModel}" legendPosition="e" 
     title="Linear Chart" minY="0" maxY="1000" style="height:600px"/>       
    </p:layoutUnit> 
</h:form> 

Это боб:

@Named 
@RequestScoped 
public class ChartBean implements Serializable { 

    private CartesianChartModel categoryModel; 
    private CartesianChartModel linearModel; 

    public ChartBean() { 
     System.out.println("ChartBean constructed"); 
     createCategoryModel(); 
     createLinearModel(); 
    } 

    // ... 
} 

В то время как я бегу, я заметил, что конструктор этого боба вызывается дважды при открытии страницы. Журналы показывает следующее:

INFO: ChartBean построена
INFO: ChartBean построен

Так боб экземпляр дважды. Как это вызвано и как я могу избежать этого? Я взаимодействую с БД, чтобы получить некоторые данные для отображения в пользовательском интерфейсе, и таким образом данные излишне извлекаются дважды.

+0

Спасибо за редактирование. В следующий раз я постараюсь написать более удобочитаемым способом. Я даже не понимаю, как хорошо выглядит вопрос сейчас :) Cheers – Cris

ответ

11

Первое создание - это контейнер, создающий ограниченный прокси-сервер вашего компонента. Прокси-сервер с областью - это объект, который расширяет ваш компонент и получает инъекции, когда какой-либо другой компонент нуждается в вашем компоненте. Однако эти методы не выполняют настоящую логику, а делегируют их выполнение в правильный конфликтный экземпляр вашего компонента. Приведем пример:

Предположим, что 2 запроса, R1, R2. Должно быть 2 экземпляра ChartBean, B1 и B2. Скажем, еще один компонент, C, зависит от ChartBean. Соответствующее поле C должно быть инъецировано экземпляром ChartBean во время запуска приложения и вызвать соответствующий экземпляр компонента во время выполнения. НО в момент запуска приложения нет запроса и, конечно же, нет B1, B2. Что делает контейнер? Он создает доверенный прокси и вводит его тем, кто в нем нуждается. Затем, когда вызывается ChartBean.method(), он вызывается в прокси-сервере, который решает, какой из них является правильным компонентом (B1 для R1, B2 для R2, ​​исключение исключения, если запрос не активен, например, вызванный из MessageDrivenBean).

Сказанное предыдущее: НЕ ЗАПУСКАЙТЕ БИЗНЕС-ЛОГИКУ В КОНСТРУКТОРЕ В КОМПОНЕНТАХ JAVA EE, поскольку конструкторы могут быть вызваны из системы/контейнера. Используйте @PostConstruct метод вместо:

... 
public class ChartBean implements Serializable { 
    public ChartBean() { 
     // only construction logic here 
    } 
    ... 
    @PostConstruct 
    void postConstruct() { 
     createCategoryModel(); 
     createLinearModel(); 
    } 
} 

Кстати, вы можете убедиться в том, что конструктор вызывается из реализации прокси напечатав имя класса в конструкторе:

public ChartBean() { 
     System.out.println("ChartBean as " + this.getClass().getName()); 
    } 

Первый раз он будет вызван, это будет какой-то другой класс, чем ваш собственный.

+0

Действительно ChartBean as ec.europa.eu.sep.statisticsep.ChartBean $ Proxy $ _ $$ _ WeldClientProxy INFO: ChartBean как ec.europa.eu.sep.statisticsep.ChartBean – Cris

Смежные вопросы