问题
As we all know that it is recommended to use annotations from javax.enterprise.context
instead of javax.faces.bean
as they are getting deprecated.
And we all found ManagedBeans with eager="true"
annotated with @ApplicationScoped
from javax.faces.bean
and having a @PostConstruct
method are very useful to do web application initialization e.g: read properties from file system, initialize database connections, etc...
Example :
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.
}
...
}
What I want to know is how can I get the same behavior if I used annotations from javax.enterprise.context
.
Note:
@Startup
annotation from javax.ejb
will help to run that code but only at the moment of deployment of the webapp when the application server Starts.
回答1:
This is not provided by CDI or JSF. You could homegrow your own with a custom CDI qualifier and a ServletContextListener to hook on webapp start.
@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.
}
}
(note: toString()
triggers lazy instantiation)
import com.example.Eager;
import javax.enterprise.context.ApplicationScoped;
@Eager
@ApplicationScoped
public class YourEagerApplicationScopedBean {
@PostConstruct
public void init() {
System.out.println("Application scoped init!");
}
}
As to existing libraries, only JSF utility library OmniFaces offers @Eager out the box.
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!");
}
}
It's also supported on @SessionScoped
, @ViewScoped
and @RequestScoped
.
Regardless of the approach, the only disadvantage is that FacesContext
isn't available at the moment the bean is constructed. But that shouldn't be a big problem, with CDI you can simply directly @Inject
artifacts of interest such as ServletContext
or HttpSession
.
回答2:
CDI 1.1 also offers a standard way to observe scope lifecycle events, for instance:
public void processApplicationScopedInit(@Observes @Initialized(ApplicationScoped.class) ServletContext payload) {}
public void processApplicationScopedDestroyed(@Observes @Destroyed(ApplicationScoped.class) ServletContext payload) {}
For more information: http://www.next-presso.com/2014/06/you-think-you-know-everything-about-cdi-events-think-again/
回答3:
As an alternative, you could use EJB instead of CDI. Then you can have a @Singleton with @Startup
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.
}
...
}
来源:https://stackoverflow.com/questions/38412301/what-is-the-equivalent-of-managedbeaneager-true-in-cdi