Введение
Это очень распространенная и рекомендуемая практика использования финализаторов потока задач, когда нам нужно выполнить какое-то окончательное задание (очистить ресурсы, закрыть соединения и т. Д.), Прежде чем поток задач исчезнет. Как обычно, мы работаем с управляемыми 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 .