Введение
Это очень распространенная и рекомендуемая практика использования финализаторов потока задач, когда нам нужно выполнить какое-то окончательное задание (очистить ресурсы, закрыть соединения и т. Д.), Прежде чем поток задач исчезнет. Как обычно, мы работаем с управляемыми bean-компонентами, объявленными внутри потока задач. Управляемые bean-компоненты могут иметь различные области действия — запрос, поток страниц, представление, вспомогательный bean-компонент и т. Д. Область действия зависит от того, для чего фактически используется bean-компонент. Существует небольшая проблема, когда мы получаем доступ к управляемому компоненту области backingBean в финализаторе. Давайте посмотрим на пример ниже.
У нас ограниченный поток задач с фрагментами страницы:
И мы управляли bean-компонентами в потоке задач трех разных областей действия — page page, view и backingBean:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<managed-bean id="__3"> <managed-bean-name id="__5">FlowBean</managed-bean-name> <managed-bean-class id="__4">view.BackBean</managed-bean-class> <managed-bean-scope id="__2">pageFlow</managed-bean-scope></managed-bean><managed-bean id="__9"> <managed-bean-name id="__6">ViewBean</managed-bean-name> <managed-bean-class id="__7">view.BackBean</managed-bean-class> <managed-bean-scope id="__8">view</managed-bean-scope></managed-bean><managed-bean id="__10"> <managed-bean-name id="__11">BackBean</managed-bean-name> <managed-bean-class id="__12">view.BackBean</managed-bean-class> <managed-bean-scope id="__13">backingBean</managed-bean-scope></managed-bean> |
На странице у нас есть три кнопки, связанные с управляемыми bean-компонентами каждой области:
|
1
2
3
4
5
6
7
8
9
|
<af:commandButton text="commandButton 1" id="cb1" action="go" binding="#{backingBeanScope.BackBean.button}"></af:commandButton><af:commandButton text="commandButton 1" id="cb2" binding="#{viewScope.ViewBean.button}"/><af:commandButton text="commandButton 1" id="cb3" binding="#{pageFlowScope.FlowBean.button}"/> |
Класс EJB имеет атрибут button и атрибут testString, который указывает, назначена ли кнопка:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
private RichCommandButton button;public void setButton(RichCommandButton button){ this.button = button;}public RichCommandButton getButton(){ return button;}public String getTestString(){ if (this.button == null) return "The button is not assigned"; else return "The button is assigned";} |
Когда мы нажимаем cb1, мы переходим к операции возврата и выполняем финализатор:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public static String resolveExpression(String expression) { FacesContext fc = FacesContext.getCurrentInstance(); return (String) fc.getApplication().evaluateExpressionGet(fc, expression, String.class); }public void theFinalizer() { //Just to have test access to the managed beans //and to be sure we work with the same instances System.out.println(resolveExpression("#{pageFlowScope.FlowBean.testString}")+ " " + resolveExpression("#{pageFlowScope.FlowBean.button}")); System.out.println(resolveExpression("#{viewScope.ViewBean.testString}")+ " " + resolveExpression("#{viewScope.ViewBean.button}")); System.out.println(resolveExpression("#{backingBeanScope.BackBean.testString}")+ " " + resolveExpression("#{backingBeanScope.BackBean.button}"));} |
Запустите приложение, нажмите кнопку cb1 и увидите следующее в системном журнале:
Кнопке назначается RichCommandButton [UIXFacesBeanImpl, id = cb3]
Кнопке назначается RichCommandButton [UIXFacesBeanImpl, id = cb2]
Кнопке назначается RichCommandButton [UIXFacesBeanImpl, id = cb1]
Кажется, все в порядке. Поток задач завершен, и в финализаторе мы работаем с правильными экземплярами управляемого компонента. В этом тесте поток задач завершается корректно с использованием действия Возврат.
А теперь давайте оставим наш поток задач — просто отойдите от страницы, на которой установлен поток задач. Финализатор также выполняется, и посмотрите на систему:
Кнопке назначается RichCommandButton [UIXFacesBeanImpl, id = cb3]
Кнопке назначается RichCommandButton [UIXFacesBeanImpl, id = cb2]
Кнопка не назначена
Это означает, что мы работаем с другим экземпляром backingBeanScope.BackBean! В случае изобилующего потока задач контроллер не видит корректный backingBeanScope в финализаторе, он пуст, и контроллер создает новый экземпляр BackBean. В то же время pageFlowScope и viewScope работают отлично. Поэтому будьте осторожны при использовании управляемых bean-компонентов области backingBean в потоках задач, особенно при обращении к ним в финализаторах. Но в любом случае вы можете использовать тот же трюк, описанный в предыдущем посте .
Это оно!
Ссылка: Поддержка области действия bean-компонента в финализаторе потока задач ADF от нашего партнера по JCG Евгения Федоренко в блоге ADF Practice .
