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.
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
.