Skip to content

Commit 9281f82

Browse files
committed
Expose FactoryBean's raw object on retrieval during post-processing
Issue: SPR-16783
1 parent c8b6233 commit 9281f82

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,21 @@ protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanNam
107107
}
108108
else {
109109
if (shouldPostProcess) {
110+
if (isSingletonCurrentlyInCreation(beanName)) {
111+
// Temporarily return non-post-processed object, not storing it yet..
112+
return object;
113+
}
114+
beforeSingletonCreation(beanName);
110115
try {
111116
object = postProcessObjectFromFactoryBean(object, beanName);
112117
}
113118
catch (Throwable ex) {
114119
throw new BeanCreationException(beanName,
115120
"Post-processing of FactoryBean's singleton object failed", ex);
116121
}
122+
finally {
123+
afterSingletonCreation(beanName);
124+
}
117125
}
118126
if (containsSingleton(beanName)) {
119127
this.factoryBeanObjectCache.put(beanName, object);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.annotation.configuration;
18+
19+
import org.junit.Test;
20+
21+
import org.springframework.beans.BeansException;
22+
import org.springframework.beans.factory.BeanFactory;
23+
import org.springframework.beans.factory.BeanFactoryAware;
24+
import org.springframework.beans.factory.FactoryBean;
25+
import org.springframework.beans.factory.config.BeanPostProcessor;
26+
import org.springframework.context.ApplicationContext;
27+
import org.springframework.context.ApplicationContextAware;
28+
import org.springframework.context.ApplicationEvent;
29+
import org.springframework.context.ApplicationListener;
30+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
31+
import org.springframework.context.annotation.Bean;
32+
33+
/**
34+
* @author Andy Wilkinson
35+
* @author Juergen Hoeller
36+
*/
37+
public class DuplicatePostProcessingTests {
38+
39+
@Test
40+
public void testWithFactoryBeanAndEventListener() {
41+
new AnnotationConfigApplicationContext(Config.class).getBean(ExampleBean.class);
42+
}
43+
44+
45+
46+
static class Config {
47+
48+
@Bean
49+
public ExampleFactoryBean exampleFactory() {
50+
return new ExampleFactoryBean();
51+
}
52+
53+
@Bean
54+
public static ExampleBeanPostProcessor exampleBeanPostProcessor() {
55+
return new ExampleBeanPostProcessor();
56+
}
57+
58+
@Bean
59+
public ExampleApplicationEventListener exampleApplicationEventListener() {
60+
return new ExampleApplicationEventListener();
61+
}
62+
}
63+
64+
65+
static class ExampleFactoryBean implements FactoryBean<ExampleBean> {
66+
67+
private final ExampleBean exampleBean = new ExampleBean();
68+
69+
@Override
70+
public ExampleBean getObject() throws Exception {
71+
return this.exampleBean;
72+
}
73+
74+
@Override
75+
public Class<?> getObjectType() {
76+
return ExampleBean.class;
77+
}
78+
79+
@Override
80+
public boolean isSingleton() {
81+
return true;
82+
}
83+
}
84+
85+
86+
static class ExampleBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
87+
88+
private ApplicationContext applicationContext;
89+
90+
91+
@Override
92+
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
93+
return bean;
94+
}
95+
96+
@Override
97+
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
98+
if (bean instanceof ExampleBean) {
99+
this.applicationContext.publishEvent(new ExampleApplicationEvent(this));
100+
}
101+
return bean;
102+
}
103+
104+
@Override
105+
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
106+
this.applicationContext = applicationContext;
107+
}
108+
}
109+
110+
111+
static class ExampleApplicationEvent extends ApplicationEvent {
112+
113+
public ExampleApplicationEvent(Object source) {
114+
super(source);
115+
}
116+
}
117+
118+
119+
static class ExampleApplicationEventListener implements ApplicationListener<ExampleApplicationEvent>, BeanFactoryAware {
120+
121+
private BeanFactory beanFactory;
122+
123+
@Override
124+
public void onApplicationEvent(ExampleApplicationEvent event) {
125+
this.beanFactory.getBean(ExampleBean.class);
126+
}
127+
128+
@Override
129+
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
130+
this.beanFactory = beanFactory;
131+
}
132+
}
133+
134+
135+
static class ExampleBean {
136+
}
137+
138+
}

0 commit comments

Comments
 (0)