如何使用CDI将http会话属性注入bean

Jos*_*eta 5 session jsf cdi managed-bean

我有一些遗留代码,使用如下代码将对象作为http会话属性:

MyObject object = new MyObject();
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
sessionMap.put("attrname", object);
Run Code Online (Sandbox Code Playgroud)

旧的facelets使用了访问代码

 @ManagedProperty("#{attrname}")
 private MyObject object;
Run Code Online (Sandbox Code Playgroud)

有没有办法使用CDI(@Inject)将此会话属性注入Bean?

在使用CDI的新代码中,创建和注入需要以受控方式创建的对象的更好方法是什么.

Bal*_*usC 7

使用getter上的a 在会话范围内的托管bean中获取它.@Produces@Named

@SessionScoped
public class MyObjectProducer implements Serializable {

    private MyObject myObject;

    @Produces
    @Named("attrname")
    public MyObject getMyObject() {
        return myObject;
    }

    public void setMyObject(MyObject myObject) {
        this.myObject = myObject;
    }

}
Run Code Online (Sandbox Code Playgroud)

当您以某种方式通过myObjectProducer.setMyObject(myObject)其他地方(或者可能是CDI @Observes事件)进行设置时,您可以将其注入任何地方使用@Inject @Named.

@Inject
@Named("attrname")
private MyObject myObject;
Run Code Online (Sandbox Code Playgroud)

是的,它仍然可以通过#{attrname}EL通常的方式获得.不,它不会在未设置时自动创建,它将保留,null直到您实际将其设置为生产者类的属性.


或者,如果您真的打算保留通过设置实例的传统方式ExternalContext#getSessionMap()(例如因为它是第三方而您不能更改它),那么您也可以让生产者直接从会话映射返回它:

@SessionScoped
public class MyObjectProducer implements Serializable {

    @Produces
    @Named("attrname")
    public MyObject getMyObject() {
        return (MyObject) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("attrname");
    }

}
Run Code Online (Sandbox Code Playgroud)

但是,当注入非JSF工件(例如任意工件)时,这并不能保证工作@WebServlet,因为FacesContext#getCurrentInstance()显然会返回null.

  • 也许答案可能更完整,说从非托管代码访问生产者,可以使用此代码`CDI.current().select(MyObjectProducer.class).get()`. (2认同)