'Spring injection not working for FF4J web console
I am try to get the FF4j (ff4j.org) web console to work. According to the documentation on the website, I use the following configuration:
<servlet>
<servlet-name>ff4j-console</servlet-name>
<servlet-class>org.ff4j.web.embedded.ConsoleServlet</servlet-class>
<init-param>
<param-name>ff4jProvider</param-name>
<param-value><path to class>.ConsoleFF4jProvider</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ff4j-console</servlet-name>
<url-pattern>/ff4j-console</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
My implementation of FF4JProvider
is:
import org.ff4j.FF4j;
import org.ff4j.web.api.FF4JProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
/**
* Created by itaykl on 17/06/2015.
*/
@Component
public class ConsoleFF4jProvider implements FF4JProvider{
@Autowired
private FF4j ff4j;
public ConsoleFF4jProvider() {
}
@Override
public FF4j getFF4j() {
return ff4j;
}
}
My problem is that no matter what I do I cannot get the autowiring of ff4j
to work. Whenever the ConsoleServlet
gets to the method call of getFF4J()
, the ff4j
class member is null
.
I have tried using several other servlets together with the FF4J console and tried defining the ff4j
bean in several ways.
Currently it is defined as:
<bean id="ff4j" class="org.ff4j.FF4j" ></bean>
But nothing seems to work.
If anyone found a solution to this problem and can share it, I would really appreciate it.
Solution 1:[1]
As I was saying in my comments, the constructor of FF4j
wasn't invoked yet when you are trying to access to bean in ConsoleFF4jProvider
. It is because Spring loads first ConsoleFF4jProvider
and not beans defined in web.xml
. To solve this problem you can remove:
@Autowired
private FF4j ff4j;
and modify your getFF4j()
function as following:
@Override
public FF4j getFF4j() {
final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(FF4j.class);
context.refresh();
FF4j ff4j= context.getBean(FF4j.class);
return ff4j;
}
Or you can initialize ff4j in constructor as well.
Edit: Otherwise you can add
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
to the constructor of ConsoleFF4jProvider
Hope this will solve your issue.
Solution 2:[2]
Spring 4 injection works with @Configuration class and @Autowired
The problem is the servlet is initialized by Jetty (your servlet container), that's why ConsoleFF4jProvider is not aware of Spring context.
With this example you can still use Spring injection mechanism with @Autowired.
You need to :
- Add a Spring listener in web.xml.
- Create a Java class to handle the bean FF4j.
- Inject the Spring context in ConsoleFF4jProvider.
web.xml :
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>HelloWorld ff4j app</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!-- Configuration using @Configuration classes -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>foo.bar.ApplicationConfig</param-value>
</context-param>
<servlet>
<servlet-name>ff4j-console</servlet-name>
<servlet-class>org.ff4j.web.embedded.ConsoleServlet</servlet-class>
<init-param>
<param-name>ff4jProvider</param-name>
<param-value>foo.bar.ConsoleFF4jProvider</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ff4j-console</servlet-name>
<url-pattern>/ff4j-console</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp </welcome-file>
</welcome-file-list>
</web-app>
ApplicationConfig.java
package foo.bar;
import org.ff4j.FF4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ApplicationConfig {
@Bean
public FF4j getFF4j() {
return new FF4j("ff4j.xml");
}
}
ConsoleFF4jProvider.java updated
package foo.bar;
import org.ff4j.FF4j;
import org.ff4j.web.api.FF4JProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
public class ConsoleFF4jProvider implements FF4JProvider {
@Autowired
private FF4j ff4j;
/**
* Inject the appropriate Spring bean FF4j declared into
* {@link ApplicationConfig}. Property {@code ff4j} marked with @Autowired
* annotation will work.
*/
public ConsoleFF4jProvider() {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
}
@Override
public FF4j getFF4j() {
return ff4j;
}
}
Solution 3:[3]
For me it's working like below in case of referring FF4J in servlet container. Just override configure function and source the FF4jConfig class where your FF4j is defined.
@Configuration
public class FF4jWebConsoleConfiguration extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(FF4JConfig.class); //scan
}
// autowired working here
@Bean
public FF4jDispatcherServlet ff4jDispatcherServlet(@Autowired FF4j ff4j) {
...
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | André Blaszczyk |
Solution 3 | Cip |