Skip to content
This repository was archived by the owner on Dec 15, 2021. It is now read-only.

Commit e6285b5

Browse files
committed
Add repro project for SPR-9176
Project demonstrates that use of @resource for fields within a request-scoped component results in a memory leak, because the injected object (in this case an HttpServletRequest) is proxied, and the bean name is not tracked by the dependent bean map because the name is different for each injection, e.g. $Proxy10@12345 vs $Proxy10@98765. The workaround for this issue is to use @Autowired instead of @resource, but naturally the @resource leak needs to be addressed.
1 parent 9287460 commit e6285b5

File tree

7 files changed

+179
-0
lines changed

7 files changed

+179
-0
lines changed

SPR-9176/pom.xml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<groupId>org.springframework.issues</groupId>
5+
<artifactId>SPR-9176</artifactId>
6+
<packaging>war</packaging>
7+
<version>1.0</version>
8+
<name>demonstration of request memory leak</name>
9+
<dependencies>
10+
<dependency>
11+
<groupId>junit</groupId>
12+
<artifactId>junit</artifactId>
13+
<version>3.8.1</version>
14+
<scope>test</scope>
15+
</dependency>
16+
<dependency>
17+
<groupId>org.springframework</groupId>
18+
<artifactId>spring-context</artifactId>
19+
<version>3.0.5.RELEASE</version>
20+
</dependency>
21+
<dependency>
22+
<groupId>org.springframework</groupId>
23+
<artifactId>spring-webmvc</artifactId>
24+
<version>3.0.5.RELEASE</version>
25+
</dependency>
26+
<dependency>
27+
<groupId>cglib</groupId>
28+
<artifactId>cglib-nodep</artifactId>
29+
<version>2.2</version>
30+
</dependency>
31+
<dependency>
32+
<groupId>javax.servlet</groupId>
33+
<artifactId>servlet-api</artifactId>
34+
<version>2.5</version>
35+
<scope>provided</scope>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.springframework</groupId>
39+
<artifactId>spring-web</artifactId>
40+
<version>3.0.5.RELEASE</version>
41+
</dependency>
42+
</dependencies>
43+
<build>
44+
<finalName>SPR-9176</finalName>
45+
<plugins>
46+
<plugin>
47+
<artifactId>maven-compiler-plugin</artifactId>
48+
<version>2.3.2</version>
49+
<configuration>
50+
<source>1.6</source>
51+
<target>1.6</target>
52+
</configuration>
53+
</plugin>
54+
</plugins>
55+
</build>
56+
</project>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package leak;
2+
3+
import org.springframework.stereotype.Controller;
4+
import org.springframework.web.bind.annotation.RequestMapping;
5+
import org.springframework.web.bind.annotation.RequestMethod;
6+
7+
import javax.annotation.Resource;
8+
import javax.servlet.http.HttpServletResponse;
9+
import java.io.IOException;
10+
11+
@Controller
12+
public class LeakController {
13+
14+
@Resource
15+
private RequestScoped leaker;
16+
17+
@RequestMapping(value = "/leak", method = RequestMethod.GET)
18+
public void handler(HttpServletResponse response) throws IOException {
19+
response.setContentType("text/plain");
20+
21+
response.getWriter().write("The number of dependencies is " + leaker.doSomething());
22+
}
23+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package leak;
2+
3+
import javax.annotation.Resource;
4+
import javax.servlet.http.HttpServletRequest;
5+
6+
import org.springframework.beans.BeansException;
7+
import org.springframework.beans.factory.BeanFactory;
8+
import org.springframework.beans.factory.BeanFactoryAware;
9+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
10+
import org.springframework.context.annotation.Scope;
11+
import org.springframework.context.annotation.ScopedProxyMode;
12+
import org.springframework.stereotype.Component;
13+
14+
@Component
15+
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
16+
public class RequestScoped implements BeanFactoryAware {
17+
18+
@SuppressWarnings("unused")
19+
@Resource // workaround: use @Autowired
20+
private HttpServletRequest request;
21+
22+
private DefaultListableBeanFactory factory;
23+
24+
25+
public int doSomething() {
26+
return factory.getDependenciesForBean("scopedTarget.requestScoped").length;
27+
}
28+
29+
@Override
30+
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
31+
this.factory = (DefaultListableBeanFactory) beanFactory;
32+
}
33+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:context="http://www.springframework.org/schema/context"
5+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
6+
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
7+
8+
<context:component-scan base-package="leak"/>
9+
10+
</beans>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:context="http://www.springframework.org/schema/context"
5+
xmlns:mvc="http://www.springframework.org/schema/mvc"
6+
7+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
8+
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
9+
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
10+
11+
<context:component-scan base-package="leak"/>
12+
13+
<mvc:annotation-driven/>
14+
<mvc:default-servlet-handler/>
15+
16+
</beans>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!DOCTYPE web-app PUBLIC
2+
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
3+
"http://java.sun.com/dtd/web-app_2_3.dtd" >
4+
5+
<web-app>
6+
<display-name>Archetype Created Web Application</display-name>
7+
8+
<context-param>
9+
<param-name>contextConfigLocation</param-name>
10+
<param-value>
11+
classpath:web-application-context.xml
12+
</param-value>
13+
</context-param>
14+
15+
<listener>
16+
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
17+
</listener>
18+
19+
<servlet>
20+
<servlet-name>mantis-servlet</servlet-name>
21+
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
22+
<init-param>
23+
<param-name>useFileMappedBuffer</param-name>
24+
<param-value>false</param-value>
25+
</init-param>
26+
<init-param>
27+
<param-name>contextConfigLocation</param-name>
28+
<param-value>classpath:web-mvc-context.xml</param-value>
29+
</init-param>
30+
<load-on-startup>1</load-on-startup>
31+
</servlet>
32+
<servlet-mapping>
33+
<servlet-name>mantis-servlet</servlet-name>
34+
<url-pattern>/*</url-pattern>
35+
</servlet-mapping>
36+
</web-app>

SPR-9176/src/main/webapp/index.jsp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<html>
2+
<body>
3+
<h2>Hello World!</h2>
4+
</body>
5+
</html>

0 commit comments

Comments
 (0)