|
16 | 16 |
|
17 | 17 | package org.springframework.context.annotation;
|
18 | 18 |
|
| 19 | +import java.util.concurrent.Executors; |
| 20 | +import java.util.concurrent.TimeUnit; |
| 21 | +import java.util.concurrent.atomic.AtomicBoolean; |
19 | 22 | import javax.annotation.Resource;
|
20 | 23 |
|
21 | 24 | import org.apache.commons.logging.Log;
|
22 | 25 | import org.apache.commons.logging.LogFactory;
|
| 26 | +import org.awaitility.Awaitility; |
23 | 27 | import org.junit.BeforeClass;
|
24 | 28 | import org.junit.Test;
|
25 | 29 |
|
|
32 | 36 | import org.springframework.tests.TestGroup;
|
33 | 37 | import org.springframework.tests.sample.beans.ITestBean;
|
34 | 38 | import org.springframework.tests.sample.beans.TestBean;
|
35 |
| -import org.springframework.util.StopWatch; |
36 | 39 |
|
37 | 40 | import static org.assertj.core.api.Assertions.assertThat;
|
38 | 41 |
|
39 | 42 | /**
|
40 | 43 | * @author Juergen Hoeller
|
41 | 44 | * @author Chris Beams
|
| 45 | + * @author Sam Brannen |
42 | 46 | * @since 2.5
|
43 | 47 | */
|
44 | 48 | public class AnnotationProcessorPerformanceTests {
|
45 | 49 |
|
46 | 50 | private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class);
|
47 | 51 |
|
| 52 | + |
48 | 53 | @BeforeClass
|
49 | 54 | public static void commonAssumptions() {
|
50 | 55 | Assume.group(TestGroup.PERFORMANCE);
|
51 | 56 | Assume.notLogging(factoryLog);
|
52 | 57 | }
|
53 | 58 |
|
54 | 59 | @Test
|
55 |
| - public void testPrototypeCreationWithResourcePropertiesIsFastEnough() { |
56 |
| - GenericApplicationContext ctx = new GenericApplicationContext(); |
57 |
| - AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); |
58 |
| - ctx.refresh(); |
| 60 | + public void prototypeCreationWithResourcePropertiesIsFastEnough() { |
| 61 | + GenericApplicationContext ctx = createContext(); |
59 | 62 |
|
60 | 63 | RootBeanDefinition rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class);
|
61 | 64 | rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
62 | 65 | ctx.registerBeanDefinition("test", rbd);
|
63 | 66 | ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
|
64 |
| - TestBean spouse = (TestBean) ctx.getBean("spouse"); |
65 |
| - StopWatch sw = new StopWatch(); |
66 |
| - sw.start("prototype"); |
67 |
| - for (int i = 0; i < 100000; i++) { |
68 |
| - TestBean tb = (TestBean) ctx.getBean("test"); |
69 |
| - assertThat(tb.getSpouse()).isSameAs(spouse); |
70 |
| - } |
71 |
| - sw.stop(); |
72 |
| - assertThat(sw.getTotalTimeMillis() < 4000).as("Prototype creation took too long: " + sw.getTotalTimeMillis()).isTrue(); |
| 67 | + |
| 68 | + assertFastEnough(ctx); |
73 | 69 | }
|
74 | 70 |
|
75 | 71 | @Test
|
76 |
| - public void testPrototypeCreationWithOverriddenResourcePropertiesIsFastEnough() { |
77 |
| - GenericApplicationContext ctx = new GenericApplicationContext(); |
78 |
| - AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); |
79 |
| - ctx.refresh(); |
| 72 | + public void prototypeCreationWithOverriddenResourcePropertiesIsFastEnough() { |
| 73 | + GenericApplicationContext ctx = createContext(); |
80 | 74 |
|
81 | 75 | RootBeanDefinition rbd = new RootBeanDefinition(ResourceAnnotatedTestBean.class);
|
82 | 76 | rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
83 | 77 | rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse"));
|
84 | 78 | ctx.registerBeanDefinition("test", rbd);
|
85 | 79 | ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
|
86 |
| - TestBean spouse = (TestBean) ctx.getBean("spouse"); |
87 |
| - StopWatch sw = new StopWatch(); |
88 |
| - sw.start("prototype"); |
89 |
| - for (int i = 0; i < 100000; i++) { |
90 |
| - TestBean tb = (TestBean) ctx.getBean("test"); |
91 |
| - assertThat(tb.getSpouse()).isSameAs(spouse); |
92 |
| - } |
93 |
| - sw.stop(); |
94 |
| - assertThat(sw.getTotalTimeMillis() < 4000).as("Prototype creation took too long: " + sw.getTotalTimeMillis()).isTrue(); |
| 80 | + |
| 81 | + assertFastEnough(ctx); |
95 | 82 | }
|
96 | 83 |
|
97 | 84 | @Test
|
98 |
| - public void testPrototypeCreationWithAutowiredPropertiesIsFastEnough() { |
99 |
| - GenericApplicationContext ctx = new GenericApplicationContext(); |
100 |
| - AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); |
101 |
| - ctx.refresh(); |
| 85 | + public void prototypeCreationWithAutowiredPropertiesIsFastEnough() { |
| 86 | + GenericApplicationContext ctx = createContext(); |
102 | 87 |
|
103 | 88 | RootBeanDefinition rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class);
|
104 | 89 | rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
105 | 90 | ctx.registerBeanDefinition("test", rbd);
|
106 | 91 | ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
|
107 |
| - TestBean spouse = (TestBean) ctx.getBean("spouse"); |
108 |
| - StopWatch sw = new StopWatch(); |
109 |
| - sw.start("prototype"); |
110 |
| - for (int i = 0; i < 100000; i++) { |
111 |
| - TestBean tb = (TestBean) ctx.getBean("test"); |
112 |
| - assertThat(tb.getSpouse()).isSameAs(spouse); |
113 |
| - } |
114 |
| - sw.stop(); |
115 |
| - assertThat(sw.getTotalTimeMillis() < 4000).as("Prototype creation took too long: " + sw.getTotalTimeMillis()).isTrue(); |
| 92 | + |
| 93 | + assertFastEnough(ctx); |
116 | 94 | }
|
117 | 95 |
|
118 | 96 | @Test
|
119 |
| - public void testPrototypeCreationWithOverriddenAutowiredPropertiesIsFastEnough() { |
120 |
| - GenericApplicationContext ctx = new GenericApplicationContext(); |
121 |
| - AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); |
122 |
| - ctx.refresh(); |
| 97 | + public void prototypeCreationWithOverriddenAutowiredPropertiesIsFastEnough() { |
| 98 | + GenericApplicationContext ctx = createContext(); |
123 | 99 |
|
124 | 100 | RootBeanDefinition rbd = new RootBeanDefinition(AutowiredAnnotatedTestBean.class);
|
125 | 101 | rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
126 | 102 | rbd.getPropertyValues().add("spouse", new RuntimeBeanReference("spouse"));
|
127 | 103 | ctx.registerBeanDefinition("test", rbd);
|
128 | 104 | ctx.registerBeanDefinition("spouse", new RootBeanDefinition(TestBean.class));
|
129 |
| - TestBean spouse = (TestBean) ctx.getBean("spouse"); |
130 |
| - StopWatch sw = new StopWatch(); |
131 |
| - sw.start("prototype"); |
132 |
| - for (int i = 0; i < 100000; i++) { |
133 |
| - TestBean tb = (TestBean) ctx.getBean("test"); |
134 |
| - assertThat(tb.getSpouse()).isSameAs(spouse); |
135 |
| - } |
136 |
| - sw.stop(); |
137 |
| - assertThat(sw.getTotalTimeMillis() < 6000).as("Prototype creation took too long: " + sw.getTotalTimeMillis()).isTrue(); |
| 105 | + |
| 106 | + assertFastEnough(ctx); |
| 107 | + } |
| 108 | + |
| 109 | + private GenericApplicationContext createContext() { |
| 110 | + GenericApplicationContext ctx = new GenericApplicationContext(); |
| 111 | + AnnotationConfigUtils.registerAnnotationConfigProcessors(ctx); |
| 112 | + ctx.refresh(); |
| 113 | + return ctx; |
| 114 | + } |
| 115 | + |
| 116 | + private void assertFastEnough(GenericApplicationContext ctx) { |
| 117 | + AtomicBoolean done = new AtomicBoolean(); |
| 118 | + TestBean spouse = ctx.getBean("spouse", TestBean.class); |
| 119 | + Executors.newSingleThreadExecutor().submit(() -> { |
| 120 | + for (int i = 0; i < 100_000; i++) { |
| 121 | + TestBean tb = ctx.getBean("test", TestBean.class); |
| 122 | + assertThat(tb.getSpouse()).isSameAs(spouse); |
| 123 | + } |
| 124 | + done.set(true); |
| 125 | + }); |
| 126 | + |
| 127 | + // "fast enough" is of course relative, but we're using 6 seconds with the hope |
| 128 | + // that these tests typically pass on the CI server. |
| 129 | + Awaitility.await() |
| 130 | + .atMost(6, TimeUnit.SECONDS) |
| 131 | + .pollInterval(100, TimeUnit.MILLISECONDS) |
| 132 | + .untilTrue(done); |
138 | 133 | }
|
139 | 134 |
|
140 | 135 |
|
|
0 commit comments