I have a class which implements ContainerRequestFilter, i want to inject some spring dependencies into it so i need to make Spring aware of the Jersey filter. The filter itself is configured in my web.xml with the Jersey servlet
<servlet>
<servlet-name>Jersey Spring Web Application</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.MyFilter</param-value>
</init-param>
</servlet>
The filter class then attempts to inject the Manager bean. In order to make spring aware of the Filter bean i have defined the bean in my applicationContext.xml and included.
#Component
public class MyFilter implements ContainerRequestFilter {
#Autowired
private Manager manager;
I've attempted to make the filter bean visible by forcing Spring to use proxy generated classes however this is not working
<mvc:annotation-driven />
<aop:aspect-autoproxy />
<bean id="filter" class="com.MyFilter">
<property name="manager" ref="Manager" />
</bean>
Any suggestions on how i can edit existing code to allow the filter see spring beans?
Since you are using Jersey's Spring Servlet, spring dependencies can be injected into the filter using the annotation #InjectParam
//#Component -> This is not required.
public class MyFilter implements ContainerRequestFilter {
#InjectParam
private Manager manager;
I feel this is the idiomatic way of using Jersey and Spring together.
This is something that is quite common for Spring Security applications. You should utilize the DelegatingFilterProxy for this.
You will add this filter to your web.xml via the <filter> tag, and you then configure it as a bean in your application container. You can then use it to delegate to a Spring configured filter that you have in your application context.
I am unfamiliar with how Jersey's SpringServlet work, but that is how I would delegate to a Spring configured filter.
Related
I have a legacy product's JAR that contain Spring (4.3.8) managed classes. I need to integrate it with CDI (JavaEE 7).
I have an interface from the legacy JAR, that is implemented by a CDI bean. The CDI bean is requested from the CDI BeanManager and returned from a factory method. The factory method is registered inside Spring XML and works as expected.
The problem occurs, when a Spring bean of the legacy JAR depends on the implemented interface. Spring than injects the CDI implementation instance and scans the class it for known annotations, namingly #Inject. It then tries to resolve the dependency, which doesn't work since the dependency is not available to Spring.
I already tweaked context:property-placeholder excludes, but that changes nothing.
So how can I tell Spring to stop trying to inject something in my factory produced bean instance?
I finally was able to solve (work around) the problem. I had to remove all CDI-Annotations in the legacy JAR (by replacining them with their Spring counterparts), so spring would any longer work.
Then I added the following XML block to the applicationContext.xml of my CDI WAR:
<context:component-scan annotation-config="false" base-package="com.example">
</context:component-scan>
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="autowiredAnnotationTypes">
<set>
<value>org.springframework.beans.factory.annotation.Autowired</value>
<value>org.springframework.beans.factory.annotation.Value</value>
</set>
</property>
</bean>
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
<property name="customQualifierTypes">
<set>
<value>org.springframework.beans.factory.annotation.Qualifier</value>
</set>
</property>
</bean>
Basically that drops the support for #Inject, etc. from Spring and leaves it where it belongs: CDI.
It's a bit easier.
AutowiredAnnotationBeanPostProcessor is already a bean, so you can configure it before Spring starts to scan with a ServletContextListener to exclude #Inject annotations. At least from Spring 4.1+, AutowiredAnnotationBeanPostProcessor has a method setAutowiredAnnotationTypes, e.g.:
#WebListener
public class ApplicationConfigListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
ApplicationContext appCtx = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<Class<? extends Annotation>>();
AutowiredAnnotationBeanPostProcessor bean = appCtx.getBean(AutowiredAnnotationBeanPostProcessor.class);
autowiredAnnotationTypes.add(Autowired.class);
autowiredAnnotationTypes.add(Value.class);
bean.setAutowiredAnnotationTypes(autowiredAnnotationTypes);
}
}
You could use a SpringBeanAutowiringInterceptor too.
This is explained here.
I have an existing Spring MVC Application with a DispatcherServlet and an XML based configuration.
Now I would like to integrate Spring Data REST but I dont know how to do this in a clean way. I added
<context:component-scan>...</context:component-scan>
so my RestControllers are found but I fail in adding a RepositoryRestMvcConfiguration config. I tried the annotation driven approach which doesnt work
#Configuration
public class RestConfiguration extends RepositoryRestMvcConfiguration {
...
}
and the
<bean class="com.mypackage.rest.RestConfiguration" />
approach is not working either.
I also tried the follwing in the web.xml
<servlet>
<servlet-name>myservlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.mypackage.rest.RestConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Strange thing is, a method annotated with #PostConstruct is called, but non of the configure* methods.
In the docs for Spring Data REST is a chapter where it is explained how to add a Spring Data REST to a Spring MVC application in code. It also says
The equivalent of the above in a standard web.xml will also work identically to this configuration if you are still in a servlet 2.5 environment.
How do you do this?
Fortunately, in Section 11.2 it is explained. Would have been nice to have a reference in Section 2.5 that points to Section 11.2 :-/
In Java, this would look like:
import org.springframework.context.annotation.Import;
import org.springframework.data.rest.webmvc.RepositoryRestMvcConfiguration;
#Configuration
#Import(RepositoryRestMvConfiguration.class)
public class MyApplicationConfiguration {
…
}
In XML this would look like:
<bean class="org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration"/>
I have a Spring based WebApp. In my application context, I have this bean defined:
<bean id="someSingleton" class="com.fake.SomeSingleton" scope="singleton"/>
I have the one Spring dispatch servlet definition and one class that has the #Controller annotation to which I auto-wired this bean, expecting Spring to only ever instantiating this class once. However, according to the following debug code, Spring is instantiating this class more than once:
private static final Semaphore SANITY_CHECK = new Semaphore(1);
public FakeSingleton(){
if(!SANITY_CHECK.tryAcquire()){
log.error("why?");
System.exit(-1);
else{
log.error("OK");
}
}
What can be the cause?
Note: I use spring 3.1.2.RELEASE
EDIT:
Thanks to the hints I was given, I found the culprit.
Apart from the DispatcherServlet, I also had a ContextLoaderListener in my web.xml. After removing it, SomeSingleton only got instantiated once.
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>FakeService</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
There are few possible reasons:
Your class is wrapped by some CGLIB proxy which causes the constructor to run twice (as opposed to #PostConstruct callback which always runs once per bean) - once for your class and once for inheriting proxy
more likely, your bean is being picked up by two contexts: main one and Spring MVC one. This is a poor practice and you should avoid it. Check out if your SomeSingleton class is not picked up by MVC dispatcher servlet context via some CLASSPATH scanning.
BTW in such a code it's safe to use simple AtomicInteger instead of Semaphore.
A singleton is once per context, not once-per-heat-death-of-the-universe.
Turn on logging and see why/if the entire app context is being created more than once.
so in spring xml config, i define the following pointcut:
<aop:config>
<aop:aspect ref="metricsAdviceInterceptor">
<aop:around method="invoke" pointcut="#annotation(com.mycom.MetricsAdvice)"/>
</aop:aspect>
</aop:config>
The idea is to collect metrics on methods that have the "MetricsAdvice" annotation:
class SomeClass {
#MetricsAdvice
public void someMethod(...) { ... }
}
So this all works fine when i explicitly declare the beans in my spring config:
<bean id="someBean" class="com.mycom.SomeClass" />
But i want to be able to use this annotation on jersey code, and it doesn't work. Now, in the jersey config, one adds the below to web.xml. The idea is that you're telling jersey in which packages to find various rest services. Ie, it looks for classes in the packages: com.mycom.restservices.* and instantiates them. Presumably the instantiation of these beans is being done "differently", and thus aren't getting proxied:
<servlet>
<servlet-name>JerseyWebApplication</servlet-name>
<servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
<display-name>Jersey Servlet</display-name>
<init-param>
<param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
<param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>
com.mycom.restservices.billing;
com.mycom.restservices.account;
org.codehaus.jackson.jaxrs
</param-value>
</init-param>
....
So what's "best practice" for trying to get these annotations to work on jersey beans?
Thx.
If all you need is to get rid of explicit bean declarations, you can use Spring classpath scanning feature instead of the Jersey one.
Just annotate your Jersey resources with #Component (or other similar annotations), and use <context:component-scan> to specify packages with these resources.
This way beans will be instantiated by Spring, and Spring AOP will work fine.
See also:
3.10 Classpath scanning and managed components
I have a very simple method scheduled to run every 10 seconds like this:
#Component
public class SimpleTask {
#Scheduled(fixedRate=10000)
public void first() {
System.out.println("Simple Task " + new Date());
}
}
Config:
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" />
<task:executor id="myExecutor" pool-size="5" />
<task:scheduler id="myScheduler" pool-size="10" />
My problem is that my method is being invoked 3 times every 10 seconds. It should be invoked just once. What am I doing wrong?
I use Spring Source ToolSuite with SpringSource tc Server 6.
I had this same problem. One of the causes is a bug in Spring 3.0.0. I upgraded to 3.0.5 and the repetition went down to only two.
The other cause was because my class that had the #Scheduled method was getting instantiated twice. This happened because the context config was getting loaded twice. In web.xml I was pointing my ContextLoaderListener and DispatcherServlet at the same context config file:
...
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
...
WEB-INF/applicationContext.xml is the default context config for the ContextLoaderListener. So make sure that your ContextLoaderListener and your ServletDispatcher are using different context files. I ended up creating a /WEB-INF/spring-servlet.xml without any bean definitions and it worked flawlessly.
you are mixing annotations with configuration and I dont believe you need both
http://static.springsource.org/spring/docs/current/spring-framework-reference/html/scheduling.html#scheduling-task-namespace
From Documentation
Note
Make sure that you are not initializing multiple instances of the same #Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use #Configurable on bean classes which are annotated with #Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the #Configurable aspect, with the consequence of each #Scheduled method being invoked twice.
may be you load applicationContext multiple times ?