在哪个阶段构造托管bean,使用哪个构造函数 [英] At which phase is managed bean constructed and which constructor is used

查看:100
本文介绍了在哪个阶段构造托管bean,使用哪个构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑官方教程中基于JSF的Web应用程序hello1的示例,并在托管Bean中添加构造函数.跟随index.xhtml小面

Consider example of JSF based web-app hello1 from official tutorial with addition constructor in managed bean. The follow index.xhtml facelet

<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>

和修改后的托管bean Hello.java

and modidfied managed bean 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后,存在回发请求.因此,正如教程所写,我们具有执行阶段的以下子阶段:

There are two public constructors. Let we deploy this app on server and sent initial request, type the name in inputText and click submit. There is postback request after submit click. Hence, as written in tutroial, we have the following subphase of execute phase:

  1. 已构建或还原了应用程序视图.
  2. 应用请求参数值.
  3. 对组件值进行转换和验证.
  4. 托管的Bean将使用组件值进行更新.
  5. 应用程序逻辑被调用.

将在哪个阶段创建托管bean实例?

At what phase instance of managed bean will be created?

此实例创建将调用什么构造函数,为什么?我不明白如何从index.xhtml代码中观察到它.

What constructor will be invoked for this instance creation and why? I dont understand how it can be observe from the index.xhtml code.

推荐答案

将在哪个阶段创建托管bean实例?

没有人专门.当bean实例不在其范围内时,当任意EL表达式需要首次引用托管bean时,将首次构造它.这不依赖于任何特定的面孔事件.这可以在还原视图阶段(第一个阶段)中进行,但是在渲染响应阶段(最后一个阶段)中或在此之间的任何其他阶段中也可以进行.

No one specifically. It's constructed for the first time when an arbitrary EL expression needs to reference the managed bean for the first time while the bean instance isn't present in its scope. This is not dependent on any particular faces event. This can be during restore view phase (the first phase), but this can also be as good during render response phase (the last phase), or any other phase in between.

这全部取决于在视图(或在模型中以编程方式)中通过#{bean.xxx}在EL上下文中引用bean的方式和位置.您通常不必为此担心.为了正确地构建,处理或渲染视图,JSF(特别是EL)至少不会比必要的时间早构建它.

This all depends on how and where the bean is referenced in EL context via #{bean.xxx} in the view (or programmatically in the model). You should generally not worry about this. JSF (specifically EL) will at least not construct it sooner than necessary in order to properly build or process or render the view.

此实例创建将调用什么构造函数,为什么?

当然是默认构造函数.因为Javabeans规范是这样说的. JSF/CDI管理的bean设施永远不会使用所有其他构造函数.

The default constructor, of course. Because the Javabeans specification says so. All other constructors are never used by JSF/CDI managed bean facility.

即使那样,您也不必担心构造函数.您最好在@PostConstruct带注释的方法中而不是在构造函数中执行初始化.即,当由使用代理(例如CDI)的Bean管理框架管理Bean时,默认构造函数的调用频率可能会比期望的高.

Even then, you should not be worrying about constructors. You'd better perform initialization in a @PostConstruct annotated method instead of in a constructor. Namely, when the bean is managed by a bean management framework which uses proxies, such as CDI, the default constructor may be called more often than desired.

我不明白如何从index.xhtml代码中观察到它.

只需在构造函数@PostConstruct或任何相关的getter/setter方法中放置一个断点,然后以调试模式运行项目.一旦断点命中,请检查调用堆栈.所涉及的类和方法通常具有相当可自我记录的名称.这是一个使用@Named

Just put a breakpoint in constructor, @PostConstruct, or whatever relevant getter/setter method and run the project in debug mode. Once the breakpoint hits, examine the call stack. The involved classes and methods have generally rather self-documenting names. Here's an example how the call stack can look like when you're using @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表示它是在像<p>#{bean.something}</p>这样的模板文本中写入EL结果时发生的.剩下的就是CDI实现Weld如何查找和实例化代理,以及如何实例化实际的bean引用.

Start at the bottom (I've stripped all lines after FacesServlet.service as those are generally irrelevant) and read from bottom to top. The RenderResponsePhase.execute tells that it's executed during render response phase. The TextInstruction.write tells that it occurred during writing the outcome of EL in template text like so <p>#{bean.something}</p>. The remainder is just how the CDI implementation Weld is finding and instantiating the proxy and how it is in turn instantiating the actual bean reference.

如果它发生在另一个阶段,那么您会看到例如UpdateModelValuesPhase.execute而不是RenderResponsePhase.execute等等.

If it happened during a different phase, you'd instead of RenderResponsePhase.execute have seen for example UpdateModelValuesPhase.execute and so on.

这篇关于在哪个阶段构造托管bean,使用哪个构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆