简体   繁体   English

bean,@ Inject和params的CDI生命周期

[英]CDI lifecycle of bean, @Inject and params

The view and bean were working until I tried to fix non-standard names, and I've now broken the connection between the two. 在尝试修复非标准名称之前,视图和bean一直有效,现在我断开了两者之间的连接。 Oddly, the "back" button has the correct link, but content just doesn't show, nor log. 奇怪的是,“后退”按钮具有正确的链接,但是内容既不显示也不记录。 Why doesn't Detail.getComments() execute? 为什么Detail.getComments()不执行?

I've been going through the weld docs and trying to better understand @Inject. 我一直在阅读焊接文档,并试图更好地了解@Inject。 There seems to be a lifecycle problem which I don't understand, either. 似乎也存在一个我不了解的生命周期问题。 If it's not lifecycle, then I cannot even speculate as to why Detail.getComments() never shows in the glassfish logs: 如果不是生命周期,那么我什至无法推测为何Detail.getComments()永远不会显示在glassfish日志中:

INFO: MessageBean.getModel..
INFO: SingletonNNTP.returning messages..
INFO: MessageBean.getModel..
INFO: SingletonNNTP.returning messages..
INFO: MessageBean.getModel..
INFO: SingletonNNTP.returning messages..
INFO: Detail..
INFO: Detail.getId..null
INFO: Detail.getId..SETTING DEFAULT ID
INFO: Detail.onLoad..2000
INFO: Detail.getId..2000
INFO: Detail.getId..2000
INFO: Detail.setId..2000
INFO: Detail.getId..2019
INFO: ..Detail.setId 2019
INFO: Detail.back..
INFO: Detail.getId..2019
INFO: ..Detail.back 2,018
INFO: Detail.getId..2019

The value 2000 is a default, which only happens when id==null, which it never should. 值2000是默认值,仅在id == null时才会发生,而从不应该。 It should pull in that attribute right away. 它应该立即加入该属性。 So, I'm not sure whether that's a problem with the scope (I only just now found out that CDI doesn't support @SessionScoped), the lifecycle, or something else. 因此,我不确定范围是否存在问题(我才刚刚发现CDI不支持@SessionScoped),生命周期或其他问题。 Perhaps I need to use @Inject on that variable? 也许我需要在该变量上使用@Inject?

The view, detail.xhtml: 视图detail.xhtml:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <body>
        <f:metadata>
            <f:viewParam name="id" id="id" value="#{detail.id}" />
        </f:metadata>
        <ui:composition template="./complexTemplate.xhtml">
            <ui:define name="top">
                <h:link value="back" outcome="detail" includeViewParams="true">
                    <f:param name="id" value="#{detail.back}"/>
                </h:link>
            <ui:define name="content">
                <h:outputText value="#{detail.content}" rendered="false"/>
            </ui:define>
            <ui:define name="bottom">
                bottom
            </ui:define>
        </ui:composition>
    </body>
</html>

and the backing bean: 和后备豆:

package net.bounceme.dur.nntp;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Named;
import javax.mail.Message;

@Named
@ConversationScoped
public class Detail  implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger(Detail.class.getName());
    private static final Level level = Level.INFO;
    private String id = null;       //should never get default value in getter
    private Message message = null;
    private SingletonNNTP nntp = SingletonNNTP.INSTANCE;
    private String forward = null;  //id + 1
    private String back = null;     //id - 1
    private String content = null;  //message.content

    public Detail() {
        logger.log(level, "Detail..");
    }

    @PostConstruct
    private void onLoad() {
        logger.log(level, "Detail.onLoad..{0}", getId());
    }

    public Message getMessage() {
        logger.log(level, "Detail.getMessage..");
        return message;
    }

    public void setMessage(Message message) {
        logger.log(level, "Detail.setMessage..");
        this.message = message;
    }

    public String getId() {
        logger.log(level, "Detail.getId..{0}", id);
        if (id == null) {
            logger.log(level, "Detail.getId..SETTING DEFAULT ID");
            id = String.valueOf(2000);
        }
        return id;
    }

    public void setId(String id) throws Exception {
        logger.log(level, "Detail.setId..{0}", getId());
        this.id = id;
        logger.log(level, "..Detail.setId {0}", getId());
    }

    public String getForward() {
        logger.log(level, "Detail.forward..");
        int f = Integer.parseInt(getId());
        f = f + 1;
        logger.log(level, "..Detail.forward {0}", f);
        forward = String.valueOf(f);
        return forward;
    }

    public void setForward(String forward) {
        this.forward = forward;
    }

    public String getBack() {
        logger.log(level, "Detail.back..");
        int b = Integer.parseInt(getId());
        b = b - 1;
        logger.log(level, "..Detail.back {0}", b);
        back = String.valueOf(b);
        return back;
    }

    public void setBack(String back) {
        this.back = back;
    }

    public String getContent() throws Exception {
        logger.log(level, "Detail.getContent..{0}", getId());
        message = nntp.getMessage(Integer.parseInt(getId()));
        content = message.getContent().toString();
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

which never seems to have, according to the above logs, Detail.getContent() invoked, despite that being part of the view: <h:outputText value="#{detail.content}" rendered="false"/> 根据上面的日志,它似乎从未调用过Detail.getContent(),尽管它是视图的一部分: <h:outputText value="#{detail.content}" rendered="false"/>

It's odd in that Detail.content() was getting invoked prior to my changing this class to better follow naming conventions. 奇怪的是,在我更改此类以更好地遵循命名约定之前,调用了Detail.content()。 I'm going through some Weld and Oracle Java EE 6 docs, but don't at all mind being directed to a fine manual. 我正在阅读一些WeldOracle Java EE 6文档,但是完全不介意使用精美的手册。 The docs I find describing this are invariably using @ManagedBeans, however, which I am not. 我发现描述此文档的文档总是使用@ManagedBeans,但我不是。 There seem many gotchas, as described in this answer by @Kawu. 好像有很多陷阱,如@Kawu在答案中所述。

Adding @Inject to the id field causes a deploy error: 将@Inject添加到id字段会导致部署错误:

init:
deps-module-jar:
deps-ear-jar:
deps-jar:
library-inclusion-in-archive:
library-inclusion-in-manifest:
compile:
compile-jsps:
In-place deployment at /home/thufir/NetBeansProjects/NNTPjsf/build/web
Initializing...
deploy?DEFAULT=/home/thufir/NetBeansProjects/NNTPjsf/build/web&name=NNTPjsf&contextroot=/NNTPjsf&force=true failed on GlassFish Server 3.1.2 
 Error occurred during deployment: Exception while loading the app : WELD-001408 Unsatisfied dependencies for type [String] with qualifiers [@Default] at injection point [[field] @Inject private net.bounceme.dur.nntp.Detail.id]. Please see server.log for more details.
/home/thufir/NetBeansProjects/NNTPjsf/nbproject/build-impl.xml:749: The module has not been deployed.
See the server log for details.
BUILD FAILED (total time: 9 seconds)

Surely, injecting a String isn't the problem, perhaps it's a bug . 当然,注入String并不是问题,也许是一个bug

I understand your frustration, and I see that the problem is more your setup / understanding in general. 我了解您的无奈,并且我发现问题更多是您的设置/了解。 But still, it's pretty hard to find any real questions to answer, maybe you can try to split your problems next time. 但是,仍然很难找到任何真正的问题要回答,也许您下次可以尝试拆分问题。

Here are some answers: 以下是一些答案:

Why doesn't Detail.getComments() execute? 为什么Detail.getComments()不执行?

Hm, maybe because it's not in the bean? 嗯,也许是因为它不在bean中? I guess that you are refrerring to detail.getContent instead? 我猜您是改用detail.getContent吗?

which never seems to have, according to the above logs, Detail.getContent() invoked, despite that being part of the view: 根据上面的日志,它似乎从未调用过Detail.getContent(),尽管它是视图的一部分:

Try rendered = true :-) 尝试rendered = true :-)

@PostConstruct
private void onLoad() {
    logger.log(level, "Detail.onLoad..{0}", getId());
}

You've put an awful lot of logic into the getter. 您已经在吸气器中添加了很多逻辑。 Try debugging with the field, not with the getter... 尝试用现场调试,而不用吸气剂...

The value 2000 is a default, which only happens when id==null, which it never should. 值2000是默认值,仅在id == null时才会发生,而从不应该。

It looks like private String id = null; 看起来像private String id = null; is a perfect explanation why id will be null. 是一个完美的解释,为什么id 将为 null。

Try to keep in mind that modern frameworks like JSF, CDI and Java EE do a lot of stuff behind the scenes, using reflection, proxies and interceptors. 尝试记住,诸如JSF,CDI和Java EE之类的现代框架在后台使用反射,代理和拦截器做了很多工作。 Don't rely on classical understanding of when (and how often) a constructor is called, for example. 例如,不要依赖于何时(以及多久)调用一次构造函数的经典理解。

Again, consider moving your initialisation logic away from the getter. 同样,请考虑将初始化逻辑从吸气剂上移开。 @PostConstruct would be the place that the fathers of the Java EE-spec had chosen for it. @PostConstruct将是Java EE规范之父为之选择的地方。

To be honest: Nothing looks extremely wrong, but your code is kind of messy, and extremely hard to understand and to follow. 老实说:看起来没有什么错,但是您的代码有点混乱,并且很难理解和遵循。

Try removing all indirections like this one... 尝试删除所有这样的间接方式...

int b = Integer.parseInt(getId());

... and everything will look much better. ...一切都会好起来的。

Oh, and is there a specific reason why you declare a fixed log-level for the whole class? 哦,您为整个类声明一个固定的日志级别有特定的原因吗? Try something like this 试试这个

private static final Logger LOG = Logger.getLogger(Some.class);
...
LOG.info("...");

Hope that gives you a start. 希望能给您一个开始。 Feel free to post further questions, preferably a bit shorter and with single, isolated aspects to answer. 随时发布其他问题,最好简短一些,并回答一个孤立的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM