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
.
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.
}
...
}
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/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With