0

我们在@PostConstruct基类层次结构上遇到重复调用的问题。

首先是基类:

public abstract class AbstractManager<T> implements Serializable
{
    private List<T> entities;

    @PostConstruct // when annotated with @PostConstruct this method is called even if overridden in sub class
    public void init()
    {
        System.out.println( AbstractManager.class.getSimpleName() + " @PostConstruct on " + this.getClass().getSimpleName() + "!" );
    }

    protected abstract List<T> getDbEntities();

    public List<T> getEntities()
    {
        if ( this.entities == null )
        {
            this.entities = this.getDbEntities();
        }

        return this.entities;
    }

    public void setEntities( List<T> entities )
    {
        this.entities = entities;
    }

    public void clearEntities()
    {
        this.entities = null;
    }
}

这是具体的子类(注意如何重写 init() 以调用 super.init()):

@Named
@ViewScoped
public class PseudoEntityManager extends AbstractManager<PseudoEntity>
{
    private static final long serialVersionUID = 1L;

    @Override
    @PostConstruct
    public void init()
    {
        super.init();
    }

    ...
}

当呈现一些(未显示的)页面时,pseudoEntityManagerbean 被实例化,但是@PostConstruct被调用了两次。这是输出:

INFO: AbstractManager @PostConstruct on PseudoEntityManager!
INFO: AbstractManager @PostConstruct on PseudoEntityManager!
INFO: New list of pseudo DB entities!

当在具体子类中注释覆盖init()方法以使超类中只有一个方法时,将生成以下输出:@PostConstruct

INFO: AbstractManager @PostConstruct on PseudoEntityManager!
INFO: New list of pseudo DB entities!

现在根据 CDI 规范的正确行为是什么?(参考任何人?)

笔记:

我在研究时还发现了这个邮件列表对话:

http://list-archives.org/2012/10/11/cdi-dev-lists-jboss-org/postconstruct-on-inherited-class/f/4426568582

在谈话中,一些大师倾向于说“应该只调用子类上的@PostConstruct 方法”。如果您仔细阅读,有一个 Weld 错误的链接,据说该错误自 Weld 1.1.5 起已解决:

https://issues.jboss.org/browse/WELD-1225

这个问题真的解决了吗?根据我得到的输出,它不是。

环境:焊接 1.1.8 和 Seam 3 以使 CDI @ViewScoped 正常工作(在 GlassFish 3.1.2 上)。

4

2 回答 2

1

这是一个解决方法的答案。

对于提到的错误,@PostConstruct 注释都被考虑在内,并且它们的逻辑代码被执行。

  1. 使用@Override 将在被子类覆盖的超类上执行帖子
  2. 那么子类上的帖子也将被执行。

要解决此问题,可以执行以下操作:

  • 定义一个新签名并将其标记为@PostConstruct
  • 覆盖标记为@PostConstruct 的超类方法,但不要放@PostConstruct 注解,只放@Override,并将其实现为空。

结果,您将只在子类上执行标记为 @PostConstruct 的代码:

@Specializes
@ViewAccessScoped
public class BaseBean extends SubBean {

@PostConstruct
public void postConstructExtension() {
    LOGGER.info("POST CALLED ON SPECIALIZED CLASS" + this.getClass().getSimpleName());
}

@Override
public void postConstruct() {
    LOGGER.info("OVERRIDDEN POST CALLED ON SPECIALIZED CLASS" + this.getClass().getSimpleName());
}

}

于 2014-10-09T13:43:01.300 回答
1

是的,它已被修复。不幸的是,它仅在 Weld 2.0 发布行中得到修复。有时这些错误会被重新移植,但不幸的是,我怀疑这个错误最终会在维护版本中得到解决。

于 2013-07-16T19:59:50.033 回答