На каком этапе создается управляемый компонент и какой конструктор используется
-
21-12-2019 - |
Вопрос
Рассмотрим пример веб-приложения на основе JSF. hello1
из официального руководства с дополнительным конструктором в управляемом компоненте.Следующее index.xhtml
фейслет
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
<title>Facelets Hello Greeting</title>
</h:head>
<h:body>
<h:form>
<h:graphicImage url="#{resource['images:duke.waving.gif']}"
alt="Duke waving his hand"/>
<h2>Hello hui, my name is Duke. What's yours?</h2>
<h:inputText id="username"
title="My name is: "
value="#{hello.name}"
required="true"
requiredMessage="Error: A name is required."
maxlength="25" />
<p></p>
<h:commandButton id="submit" value="Submit" action="response">
</h:commandButton>
<h:commandButton id="reset" value="Reset" type="reset">
</h:commandButton>
</h:form>
<div class="messagecolor">
<h:messages showSummary="true"
showDetail="false"
errorStyle="color: #d20005"
infoStyle="color: blue"/>
</div>
</h:body>
</html>
и модифицированный управляемый компонент Hello.java
package javaeetutorial.hello1;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
@Named
@RequestScoped
public class Hello {
private String name;
public Hello() {
}
public Hello(String name){
this.name=name;
}
public String getName() {
return name;
}
public void setName(String user_name) {
this.name = user_name;
}
}
Есть два общественные строители.Давайте развернем это приложение на сервере и отправим первоначальный запрос, введите имя. inputText
и нажмите submit
.После этого есть запрос обратной передачи submit
щелкните.Следовательно, как написано в руководстве, у нас есть следующая подфаза фазы выполнения:
- Представление приложения создается или восстанавливается.
- Значения параметров запроса применяются.
- Преобразования и проверки выполняются для значений компонентов.
- Управляемые bean-компоненты обновляются значениями компонентов.
- Вызывается логика приложения.
На каком этапе будет создан экземпляр управляемого компонента?
Какой конструктор будет вызван для создания этого экземпляра и почему?Я не понимаю, как это можно наблюдать со стороны index.xhtml
код.
Решение
На каком этапе будет создан экземпляр управляемого компонента?
Никого конкретно.Он создается впервые, когда произвольному EL-выражению необходимо впервые ссылаться на управляемый компонент, в то время как экземпляр компонента отсутствует в его области действия.Это не зависит от какого-либо конкретного события с лицами.Это может быть на этапе восстановления представления (первый этап), но это также может быть полезно на этапе ответа на рендеринг (последний этап) или на любом другом промежуточном этапе.
Все зависит от того, как и где на бин ссылаются в контексте EL через #{bean.xxx}
в представлении (или программно в модели).Обычно вам не следует беспокоиться об этом.JSF (в частности, EL), по крайней мере, не будет создавать его раньше, чем это необходимо, чтобы правильно построить, обработать или отобразить представление.
Какой конструктор будет вызван для создания этого экземпляра и почему?
Конструктор по умолчанию, конечно.Потому что так гласит спецификация Javabeans.Все остальные конструкторы никогда не используются объектом управляемых компонентов JSF/CDI.
Даже в этом случае вам не следует беспокоиться о конструкторах.Вам лучше выполнить инициализацию в @PostConstruct
аннотированный метод вместо конструктора.А именно, когда bean-компонент управляется структурой управления bean-компонентами, которая использует прокси-серверы, такие как CDI, конструктор по умолчанию может вызываться чаще, чем хотелось бы.
Я не понимаю, как это можно увидеть из кода index.xhtml.
Просто поставьте точку останова в конструкторе, @PostConstruct
, или любой другой соответствующий метод получения/установки и запустите проект в режиме отладки.Как только точка останова достигнет точки останова, проверьте стек вызовов.Задействованные классы и методы обычно имеют довольно самодокументируемые имена.Вот пример того, как может выглядеть стек вызовов при использовании @Named
:
Daemon Thread [http-bio-8088-exec-6] (Suspended (entry into method <init> in TestBean))
owns: LocalCache$StrongEntry (id=503)
owns: SocketWrapper (id=504)
TestBean$Proxy$_$$_WeldClientProxy.<init>() line: not available [local variables unavailable]
NativeConstructorAccessorImpl.newInstance0(Constructor, Object[]) line: not available [native method]
NativeConstructorAccessorImpl.newInstance(Object[]) line: 57
DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45
Constructor.newInstance(Object...) line: 526
Class.newInstance() line: 374
NewInstanceAction.run() line: 33
AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not available [native method]
ClientProxyFactory(ProxyFactory).create(BeanInstance) line: 271
ClientProxyFactory.create(BeanInstance) line: 111
ClientProxyProvider.createClientProxy(Bean<T>, Set<Type>) line: 181
ClientProxyProvider.createClientProxy(Bean<T>) line: 171
ClientProxyProvider.access$100(ClientProxyProvider, Bean) line: 45
ClientProxyProvider$CreateClientProxy.load(Bean<Object>) line: 56
ClientProxyProvider$CreateClientProxy.load(Object) line: 52
LocalCache$LoadingValueReference.loadFuture(K, CacheLoader<? super K,V>) line: 3589
LocalCache$Segment.loadSync(K, int, LoadingValueReference<K,V>, CacheLoader<? super K,V>) line: 2374
LocalCache$Segment.lockedGetOrLoad(K, int, CacheLoader<? super K,V>) line: 2337
LocalCache$Segment.get(K, int, CacheLoader<? super K,V>) line: 2252
LocalCache.get(K, CacheLoader<? super K,V>) line: 3990
LocalCache.getOrLoad(K) line: 3994
LocalCache$LocalLoadingCache.get(K) line: 4878
LoadingCacheUtils.getCacheValue(LoadingCache<K,V>, K) line: 52
LoadingCacheUtils.getCastCacheValue(LoadingCache<K,V>, Object) line: 80
ClientProxyProvider.getClientProxy(Bean<T>) line: 187
WeldELResolver(AbstractWeldELResolver).lookup(BeanManagerImpl, ELContext, String) line: 110
WeldELResolver(AbstractWeldELResolver).getValue(ELContext, Object, Object) line: 91
WeldApplication$LazyBeanManagerIntegrationELResolver(ForwardingELResolver).getValue(ELContext, Object, Object) line: 49
CompositeELResolver.getValue(ELContext, Object, Object) line: 67
DemuxCompositeELResolver._getValue(int, ELResolver[], ELContext, Object, Object) line: 176
DemuxCompositeELResolver.getValue(ELContext, Object, Object) line: 203
AstIdentifier.getValue(EvaluationContext) line: 72
ValueExpressionImpl.getValue(ELContext) line: 185
WeldValueExpression.getValue(ELContext) line: 50
ELText$ELTextVariable.writeText(ResponseWriter, ELContext) line: 227
ELText$ELTextComposite.writeText(ResponseWriter, ELContext) line: 150
TextInstruction.write(FacesContext) line: 85
UIInstructions.encodeBegin(FacesContext) line: 82
UIInstructions(UILeaf).encodeAll(FacesContext) line: 207
HtmlBody(UIComponent).encodeAll(FacesContext) line: 1899
UIViewRoot(UIComponent).encodeAll(FacesContext) line: 1899
FaceletViewHandlingStrategy.renderView(FacesContext, UIViewRoot) line: 451
MultiViewHandler.renderView(FacesContext, UIViewRoot) line: 131
ConversationAwareViewHandler(ViewHandlerWrapper).renderView(FacesContext, UIViewRoot) line: 337
RenderResponsePhase.execute(FacesContext) line: 120
RenderResponsePhase(Phase).doPhase(FacesContext, Lifecycle, ListIterator<PhaseListener>) line: 101
LifecycleImpl.render(FacesContext) line: 219
FacesServlet.service(ServletRequest, ServletResponse) line: 647
...
Начните снизу (я удалил все строки после FacesServlet.service
поскольку они, как правило, не имеют значения) и читайте снизу вверх.А RenderResponsePhase.execute
сообщает, что он выполняется на этапе ответа на рендеринг.А TextInstruction.write
сообщает, что это произошло во время записи результата EL в текст шаблона, например <p>#{bean.something}</p>
.Остальное — это то, как реализация CDI Weld находит и создает экземпляр прокси-сервера и как он, в свою очередь, создает экземпляр фактической ссылки на компонент.
Если бы это произошло на другом этапе, вы бы вместо RenderResponsePhase.execute
видел, например UpdateModelValuesPhase.execute
и так далее.