Is there any way to startup a CDI Bean with the application?
I have this bean:
#ApplicationScoped
#Named
public class MyBean implements Serializable {
#Inject
private Helper helper;
#PostConstruct
public void init() {
helper.doThings();
}
}
I would like that this bean to start with the app, on deploy.
I'm using the weld-servlet and tomcat7:
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet</artifactId>
<version>${weld-servlet.version}</version>
<scope>compile</scope>
</dependency>
Try:
public void startup(#Observes #Initialized
(ApplicationScoped.class) Object context){
//your code here
}
That will ensure the method is executed at startup, and start your bean.
Or you can use OmniFaces #Eager annotation.
Ensure that your tomcat7 variant supports CDI (See tomcat version comparison)
Then,
#Startup
#Singleton
public class MyBean {
#PostConstruct
private void init() {
// place your initialization code here
}
}
Related
There is a dropwizard app, which is jersey based.
I rewrote Hk2 bean definitions into Guice and now I can inject Guice beans into Jersey Resources,
but I noticed that Hk2 beans, defined in dropwizard bundles, which I cannot rewrite, are not
visible by Guice and it fails to inject dependencies defined in Hk2.
Guice doesn't see beans defined in Hk2 bundles and Guice creates new uninitialized beans by default.
I disabled this behavior with requireExplicitBindings.
I experimented with HK2IntoGuiceBridge, but its matcher is not invoked for beans I am interested in.
ConfiguredBundleX is located in external artifact.
I tried to copy and translate bean definitions from bundles and stuck with jersey bean Provider<ContainerRequest>, I have no idea where it comes from.
public class ConfiguredBundleX implements ConfiguredBundle<MyAppConf> {
public void run(T configuration, Environment environment) throws Exception {
environment.jersey().register(new AbstractBinder() {
protected void configure() {
this.bind(new MyHk2Bean()).to(MyHk2Bean.class);
}
});
}
}
public class DependsOnHk2Bean { #Inject public DependsOnHk2Bean(MyHk2Bean b) {} }
public class MainModule extends AbstractModule {
private final ServiceLocator locator;
protected void configure() {
binder().requireExplicitBindings();
install(new HK2IntoGuiceBridge(locator));
bind(DependsOnHk2Bean.class);
}
public class GuiceFeature implements Feature {
public boolean configure(FeatureContext context) {
ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
GuiceBridge.getGuiceBridge().initializeGuiceBridge(locator);
Injector injector = Guice.createInjector(
new HK2IntoGuiceBridge(locator),
new MainModule(locator));
GuiceIntoHK2Bridge guiceBridge = locator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(injector);
return true;
}
}
// ...
public void initialize(Bootstrap<X> bootstrap) {
bootstrap.addBundle(new ConfiguredBundleX());
}
public void run(X config, Environment env) {
env.jersey().register(new GuiceFeature());
}
Unfortunately in Guice beans you have to use #HK2Inject rather than #Inject in order to inject hk2 beans into Guice. So in your code above you would do:
public class DependsOnHk2Bean { #HK2Inject public DependsOnHk2Bean(MyHk2Bean b) {} }
This is because of limitation in guice (it may be fixed by now) such that #Inject behavior could not overwritten
I have not tried the above code myself so I'm not sure it'll work, but that was the deal back when the bridge was written...
See HK2Inject and injecting-hk2-services-into-guice-services
After digging Guice and HK2ToGuiceTypeListenerImpl I figured out that there is bindListener to kind of intercept missing bindings and pull them from somewhere. #HKInject code is there, but I noticed that the listener is not called for some bean including the bean I was interested in. Yes HKInject doesn't support constructor injection (4.2.1 version)
So I decided to manually import HK beans and bind them in Guice.
Dropwizard terminology is horrible there are methods get context something, get admin context is totally something different and beans must be get with getService method!
#RequiredArgsConstructor
public class HkModule extends AbstractModule {
private final ServiceLocator locator;
#Override
protected void configure() {
binder().requireExplicitBindings();
Provider<Bar> barProvider = locator.getService(
new TypeLiteral<Provider<Bar>>(){}.getType());
bind(Bar.class).toProvider(barProvider);
bind(Foo.class).toInstance(locator.getService(Foo.class));
}
}
I am trying to autowire a bean inside of a Singleton class, I know that it always a best idea to avoid manual autowiring, but this class is being used in so many places so I do not want to change the caller of this class.
Runner.java
#Component
public class RunnerClass {
#Autowired
public ConfigService configService;
}
ConfigService.java
#Service
public class ConfigService {
private ConfigServiceDAO = ConfigServiceDAO.getInstance();
}
ConfigServiceDAO.java
public class ConfigServiceDAO {
//Bean I want to autowire here....
#Autowired
ConfigServiceDAOBuilder DAOBuilder
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE = new ConfigServiceDAO();
private SingletonHolder() {}
}
}
DAOBuilder inside ConfigServiceDAO is always null, which makes sense because my understanding is when the class is instantiated manually, spring injection doesn't happen.
What could be the solution here if I want to keep ConfigServiceDAO as non spring component?
====EDIT====
I know it is possible to make ConfigServiceDAO as a spring component and autowire all dependencies.
But a lot of classes from different packages already call
ConfigServiceDAO.getInstance().someMethod()
So I guess the the right question is, what would be the best way to autowire a spring component to the class that is instantiated manually.
I don't know your use case but you cannot use #Autowired annotation outside a Spring bean.
However if you really need to access a Spring bean from a non Spring piece of code you can do it like below. However this is a very non Spring way of designing your dependencies.
import org.springframework.context.ApplicationContext;
public enum ApplicationContextHolder {
INSTANCE;
private ApplicationContext applicationContext;
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
Then you have a configuration class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
#Configuration
public class SomeConfig {
#Autowired
private ApplicationContext applicationContext;
#PostConstruct
public void init() {
ApplicationContextHolder.INSTANCE.setApplicationContext(applicationContext);
}
}
Then in your DAO class you get a reference to the builder bean you are interested. Something like this:
public class ConfigServiceDAO {
public static ConfigServiceDAO getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
public static final ConfigServiceDAO INSTANCE =
ApplicationContextHolder.INSTANCE.getApplicationContext().getBean(ConfigServiceDAOBuilder.class).buildConfigServiceDAO()
private SingletonHolder() {}
}
}
Again this is a very non Spring way of doing things.
Spring processed #Autowired only in beans that it manages by itself.
So you have two choices:
Get Rid Of singleton - if you're using spring, its already a singleton in the application context. This is by far the best approach in general (assuming other parts of application that call your singleton are also spring driven). I don't think you should fear to change ConfigServiceDAO.getInstance.method() - refactoring tools in IDE will do the job.
If you can't do 1, Don't use autowired annotation in the singleton - its useless anyway, instead, when you have an application context configured (in listener that spring emits when the application started for example), get the access to the ConfigServiceDAOBuilder bean by calling appCtx.getBean(ConfigServiceDAOBuilder.class) and "inject it" manually by reflection, this is what Spring does with spring managed beans anyway:
#EventListener
public void onApplicationReadyEvent(ApplicationReadyEvent event) {
ConfigServiceDAOBuilder builder =
event.getApplicationContext().getBean(ConfigServiceDAOBuilder.class);
ConfigServiceDao dao = ConfigServiceDAO.getInstance();
dao.setDaoBuilder(builder); // or alternatively by reflection
}
As a side note, consider using method setDaoBuilder to be a package private to protect the singleton from some accidentally calling a setter
As far as I understand what you want: Create by Spring ConfigServiceDAOBuilder. After that inject it into non-managed object of class ConfigServiceDAO. You can do it after the Spring application context is instantiated. For example with CommanLineRunner:
#Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
#Autowired
ConfigServiceDAOBuilder DAOBuilder
#Override
public void run(String...args) throws Exception {
ConfigServiceDAO.getInstance().init(DAOBuilder);
}
}
In ConfigServiceDAO has to be method init that helps to register all needed beans.
I'm confused after reading your comments, hence let me put in this way. What you are referring to manual autowiring is the Spring dependency injection way.
Whenever you are using any of the Spring Stereotype annotations with default scope instance is always Singleton.
Your ConfigService class has the problem.
Your are mixing up things, you should create a separate config class with #configuration and create Bean for the class ConfigServiceDAO, something like below
#Configuration
Class Config{
#Bean
public ConfigServiceDAO configServiceDAO( ){
return ConfigServiceDAO.getInstance();
}
}
then autowire the ConfigServiceDAO in the ConfigService class. With this Spring will resolve all of the dependency in correct order and DAOBuilder shouldn't be null.
I have a Bean, which creates an instance of an object, which i need to inject into other beans. Everything works fine, i can print a property of the injected object in the #PostConstruct method, but if i try to call a method from that injected object inside the #OnOpen method of a ServerEndpoint it gives me a NullPointerException.
Here is my ServerEndpoint
#Named
#ApplicationScoped
#ServerEndpoint(value = "/websocket")
public class BeanThree {
private String message = "test";
#Inject private User user;
#PostConstruct
public void init() { System.out.println(user.getUserName()); } <-- displayed in the console correctly
public String getMessage() { return this.message; }
#OnOpen
public void onOpen(Session session) {
System.out.println("onOpen");
System.out.println(user.getUserName()); <-- causes NullPointerException
}
}
Is it possible to fix this?
Edit1:
Im using cdi 1.2, jetty 9.1, jsf 2.2, java-ee7 and websockets from java-ee7
The problem is that BeanThree is declared both a CDI bean and an endpoint at the same time.
It has to be split into two different beans:
#ServerEndpoint("/endpoint")
public class BeanThree {
#Inject
ApplicationScopedBean bean;
#OnOpen
public String onOpen(Session s) { System.out.println(bean); }
#OnMessage
public String onMessage(String message) { System.out.println(bean); }
}
#ApplicationScoped
public class ApplicationScopedBean { ... }
But there's another issue.
CDI / Websocket integration is very limited: out of the box you can inject #ApplicationScoped and probably #Dependent beans only.
From your snippet it seems you intend to use #SessionScoped User bean withing a Websocket session. That's not going to work because Websocket and HTTP sessions differ.
You'll have to manage Websocket sessions and session-bound data by yourself. Here's an example.
One way to do this is to allow CDI to instantiate it as a CDI bean.
Then subclasses the following classes: ServerEndpointConfig.Configurator
#ServerEndpoint(..., configurator=MyCustomConfigurator.class)
#SessionScoped
#Named("myMessageHandler")
public class MyMessageHandler{
#Inject
private MyInjectable instance;
...
}
public class MyCustomConfigurator extends ServerEndpointConfig.Configurator{
public <T extends Object> getEndpointInstance(Class<T> endpointClass) throws InstantiationException{
//do cdi lookup for endpoint using the simple name.
}
To have a reference to the cdi BeanManager, have a look at this thread:
http://dominikdorn.com/2010/04/cdi-weld-manual-bean-lookup/
In your case, you dont have a reference to FacesContext, so use the ServletContext
I have some ear application which I need to rewrite to spring. War contains one class which run EJB:
/**
* The ear initialization.
*/
public final class Startup extends HttpServlet {
private static final long serialVersionUID = 6465240550145652729L;
#EJB(name="MyStartupBean")
private MyBeanLocal bean;
#Override
public void init(final ServletConfig servletConfiguration) throws ServletException {
bean.start();
}
#Override
public void destroy() {
bean.stop();
}
}
EJB contains some quart scheduler which run job every 30s
I really try to find some example of ear spring application with EJB but with no succes. How should I rewrite it into spring ?
Spring supports #EJB (not widely known but it does). So basically you can simply port your class to spring by removing the extends HttpServlet, add a #Component annotation, simplify the init method and add #PostConstruct and add #PreDestroy to the destroy method.
#Component
public final class Startup {
private static final long serialVersionUID = 6465240550145652729L;
#EJB(name="MyStartupBean")
private MyBeanLocal bean;
#PostConstruct
public void init() {
bean.start();
}
#PreDestroy
public void destroy() {
bean.stop();
}
}
Something like that would be the result. Now either declare this bean in xml
<bean class="Startup" />
Or use component scanning to detect/pickup this bean.
But as mentioned I would probably ditch the EJB altogether and use spring to bootstrap Quartz instead.
I want to create a timer EJB3 when a stateless bean is created in the pool.
But if I use #PostConstruct I get the exception:
java.lang.IllegalStateException: [EJB:010193]Illegal call to EJBContext method. The bean is in "null" state. It cannot perform 'getting the Timer Service' action(s). Refer to the EJB specification for more details.
If container calls #PostConstruct, the bean ins't null. So, why I get this exception?
CLASS
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Override
public void test() {
}
}
INTERFACE
#Local
public interface TesteLocal {
void test();
}
SERVLET
public class TestServlet extends HttpServlet {
#EJB
private TestLocal test;
protected void doGet(....) throws .... {
test.test();
}
}
DETAILS
I'm using weblogic server 11g.
You can NOT use a #PostConstruct to create a timer in a stateless bean EJB 3. See this blog How to use EJB 3 timer in a weblogic 10 cluster environment for the explanation. Even the blog was talking about weblogic, but the explanation should apply to other app servers also.
Container will not allow for timerService in method annotated with #PostConstruct of Stateless Session Bean. If you want to use timerService in method annotated with #PostConstruct the go for Singleton session bean(#Singleton).
I'm not 100% sure but I think that the bean class must implement javax.ejb.TimedObject or have a method annotated with #Timeout to use EJB timers. Example:
#Stateless
public class TestBean implements TestLocal {
#Resource
TimerService timerService;
#PostConstruct
public void startTimer() {
if (timerService.getTimers().size() == 0) {
timerService.createTimer(1 * 1000, 1 * 1000, null);
}
}
#Timeout
#TransactionAttribute(value=REQUIRES_NEW)
public void timeoutCallback(Timer timer) {
...
}
}
Does WebLogic still complain with the above code?
PS: In any case, the error you currently get is very poorly reported, you should probably open a case.