CDI

时间:2016-07-16 14:46:10

标签: jsf java-ee cdi managed-bean eager-loading

众所周知,建议使用javax.enterprise.context而不是javax.faces.bean的注释,因为它们已被弃用。

我们都发现ManagedBeans eager="true"注释了来自@ApplicationScoped的{​​{1}},并且使用javax.faces.bean方法对于Web应用程序初始化非常有用,例如:从文件中读取属性系统,初始化数据库连接等...

示例:

@PostConstruct

我想知道的是,如果我使用import javax.faces.bean.ApplicationScoped; import javax.faces.bean.ManagedBean; import javax.annotation.PostConstruct; @ApplicationScoped @ManagedBean(eager=true) public class someBean{ @PostConstruct public void init(){ //Do all needed application initialization. } ... } 中的注释,我怎么能得到相同的行为。

注意: 来自javax.enterprise.context的{​​{1}}注释将有助于运行该代码,但仅在应用服务器 启动 时部署webapp时。

4 个答案:

答案 0 :(得分:11)

CDI或JSF不提供此功能。你可以使用自定义CDI限定符和ServletContextListener来创建自己的webg,以挂钩webapp启动。

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Eager {
    //
}

@WebListener
public class EagerListener implements ServletContextListener{

    private static final AnnotationLiteral<Eager> EAGER_ANNOTATION = new AnnotationLiteral<Eager>() {
        private static final long serialVersionUID = 1L;
    };

    @Override
    public void contextInitialized(ServletContextEvent event) {
        CDI.current().select(EAGER_ANNOTATION).forEach(bean -> bean.toString());
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // NOOP.
    }

}

(注意:toString()触发延迟实例化)

import com.example.Eager;
import javax.enterprise.context.ApplicationScoped;

@Eager
@ApplicationScoped
public class YourEagerApplicationScopedBean {

    @PostConstruct
    public void init() {
        System.out.println("Application scoped init!");
    }
}

对于现有的库,只有JSF实用程序库OmniFaces提供@Eager框。

import org.omnifaces.cdi.Eager;
import javax.enterprise.context.ApplicationScoped;

@Eager
@ApplicationScoped
public class YourEagerApplicationScopedBean {

    @PostConstruct
    public void init() {
        System.out.println("Application scoped init!");
    }
}

@SessionScoped@ViewScoped@RequestScoped也是supported

无论采用何种方法,唯一的缺点是在构造bean时FacesContext不可用。但这不应该是一个大问题,使用CDI,您可以直接@Inject感兴趣的工件,例如ServletContextHttpSession

答案 1 :(得分:2)

CDI 1.1还提供了一种观察范围生命周期事件的标准方法,例如:

public void processApplicationScopedInit(@Observes @Initialized(ApplicationScoped.class) ServletContext payload) {}
public void processApplicationScopedDestroyed(@Observes @Destroyed(ApplicationScoped.class) ServletContext payload) {}

有关详细信息:http://www.next-presso.com/2014/06/you-think-you-know-everything-about-cdi-events-think-again/

答案 2 :(得分:1)

作为替代方案,您可以使用EJB而不是CDI。然后你就可以拥有一个带@Startup的@Singleton

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;

@Singleton
@Startup
public class SomeBean {

    @PostConstruct
    public void init(){
        //Do all needed application initialization.
    }
    ...
}

答案 3 :(得分:0)

这是我使用的一种方法:

import javax.annotation.PostConstruct;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.util.AnnotationLiteral;
import javax.inject.Inject;

@Startup
@Singleton
public class AppStartup
{
    @Inject
    private BeanManager beanManager;

    @PostConstruct
    public void init()
    {       
        // enforce initializing eager CDI beans
        var beans = beanManager.getBeans(Object.class, new AnnotationLiteral<Any>(){});
        for(var bean : beans)
        {
            if(bean.getBeanClass().getAnnotation(Eager.class) != null && bean.getBeanClass().getAnnotation(ApplicationScoped.class) != null)
            {
                var beanProxyInstance = beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));

                // invoking toString() on the proxy object will invoke the method annotated with @PostConstruct, if has not been invoked yet
                beanProxyInstance.toString();
            }
        }
    }
}
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Retention(RUNTIME)
@Target({TYPE})
public @interface Eager {}
import javax.enterprise.context.ApplicationScoped;

@Eager
@ApplicationScoped
public class SomeCdiBean {}

现在,您可以在没有任何其他限定符的情况下注入此CDI bean:

@Inject
private SomeCdiBean someCdiBean;