Skip to content

Commit f475ab5

Browse files
committed
Add to AbstractDependsOnBeanFactoryPostProcessor new constructors
to specify that bean and factory bean depends on particular types. Prior to this commit, the `AbstractDependsOnBeanFactoryPostProcessor` can be used only with bean names.
1 parent d306b31 commit f475ab5

File tree

2 files changed

+239
-13
lines changed

2 files changed

+239
-13
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AbstractDependsOnBeanFactoryPostProcessor.java

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,8 +17,9 @@
1717
package org.springframework.boot.autoconfigure;
1818

1919
import java.util.Arrays;
20-
import java.util.HashSet;
20+
import java.util.LinkedHashSet;
2121
import java.util.Set;
22+
import java.util.stream.Collectors;
2223

2324
import org.springframework.beans.factory.BeanFactory;
2425
import org.springframework.beans.factory.BeanFactoryUtils;
@@ -39,6 +40,7 @@
3940
* @author Dave Syer
4041
* @author Phillip Webb
4142
* @author Andy Wilkinson
43+
* @author Dmytro Nosan
4244
* @since 1.3.0
4345
* @see BeanDefinition#setDependsOn(String[])
4446
*/
@@ -49,7 +51,7 @@ public abstract class AbstractDependsOnBeanFactoryPostProcessor
4951

5052
private final Class<? extends FactoryBean<?>> factoryBeanClass;
5153

52-
private final String[] dependsOn;
54+
private final Object[] dependsOn;
5355

5456
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
5557
Class<? extends FactoryBean<?>> factoryBeanClass, String... dependsOn) {
@@ -58,6 +60,20 @@ protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
5860
this.dependsOn = dependsOn;
5961
}
6062

63+
/**
64+
* Create an instance with target bean and factory bean classes and dependency types.
65+
* @param beanClass target bean class
66+
* @param factoryBeanClass target factory bean class
67+
* @param dependsOn dependency types
68+
* @since 2.2.0
69+
*/
70+
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
71+
Class<? extends FactoryBean<?>> factoryBeanClass, Class<?>... dependsOn) {
72+
this.beanClass = beanClass;
73+
this.factoryBeanClass = factoryBeanClass;
74+
this.dependsOn = dependsOn;
75+
}
76+
6177
/**
6278
* Create an instance with target bean class and dependencies.
6379
* @param beanClass target bean class
@@ -69,32 +85,55 @@ protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
6985
this(beanClass, null, dependsOn);
7086
}
7187

88+
/**
89+
* Create an instance with target bean class and dependency types.
90+
* @param beanClass target bean class
91+
* @param dependsOn dependency types
92+
* @since 2.2.0
93+
*/
94+
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
95+
Class<?>... dependsOn) {
96+
this(beanClass, null, dependsOn);
97+
}
98+
7299
@Override
73100
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
74101
for (String beanName : getBeanNames(beanFactory)) {
75102
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
76103
String[] dependencies = definition.getDependsOn();
77-
for (String bean : this.dependsOn) {
104+
for (String bean : getDependsOn(beanFactory)) {
78105
dependencies = StringUtils.addStringToArray(dependencies, bean);
79106
}
80107
definition.setDependsOn(dependencies);
81108
}
82109
}
83110

84-
private Iterable<String> getBeanNames(ListableBeanFactory beanFactory) {
85-
Set<String> names = new HashSet<>();
86-
names.addAll(Arrays.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
87-
beanFactory, this.beanClass, true, false)));
111+
private Set<String> getDependsOn(ListableBeanFactory beanFactory) {
112+
if (this.dependsOn instanceof Class[]) {
113+
return Arrays.stream(((Class[]) this.dependsOn))
114+
.flatMap((beanClass) -> getBeanNames(beanFactory, beanClass).stream())
115+
.collect(Collectors.toCollection(LinkedHashSet::new));
116+
}
117+
return Arrays.stream(this.dependsOn).map(String::valueOf)
118+
.collect(Collectors.toCollection(LinkedHashSet::new));
119+
}
120+
121+
private Set<String> getBeanNames(ListableBeanFactory beanFactory) {
122+
Set<String> names = getBeanNames(beanFactory, this.beanClass);
88123
if (this.factoryBeanClass != null) {
89-
for (String factoryBeanName : BeanFactoryUtils
90-
.beanNamesForTypeIncludingAncestors(beanFactory,
91-
this.factoryBeanClass, true, false)) {
92-
names.add(BeanFactoryUtils.transformedBeanName(factoryBeanName));
93-
}
124+
names.addAll(getBeanNames(beanFactory, this.factoryBeanClass));
94125
}
95126
return names;
96127
}
97128

129+
private static Set<String> getBeanNames(ListableBeanFactory beanFactory,
130+
Class<?> beanClass) {
131+
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
132+
beanClass, true, false);
133+
return Arrays.stream(names).map(BeanFactoryUtils::transformedBeanName)
134+
.collect(Collectors.toCollection(LinkedHashSet::new));
135+
}
136+
98137
private static BeanDefinition getBeanDefinition(String beanName,
99138
ConfigurableListableBeanFactory beanFactory) {
100139
try {
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
* Copyright 2012-2019 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+
* https://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.boot.autoconfigure;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.beans.factory.BeanFactory;
22+
import org.springframework.beans.factory.FactoryBean;
23+
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
24+
import org.springframework.beans.factory.config.BeanDefinition;
25+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
26+
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
27+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
28+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Configuration;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* Tests for {@link AbstractDependsOnBeanFactoryPostProcessor}.
36+
*
37+
* @author Dmytro Nosan
38+
*/
39+
class AbstractDependsOnBeanFactoryPostProcessorTests {
40+
41+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
42+
.withUserConfiguration(FooBarConfiguration.class);
43+
44+
@Test
45+
void fooBeansShouldDependOnBarBeanNames() {
46+
this.contextRunner
47+
.withUserConfiguration(FooDependsOnBarNamePostProcessor.class,
48+
FooBarFactoryBeanConfiguration.class)
49+
.run(this::assertThatFooDependsOnBar);
50+
}
51+
52+
@Test
53+
void fooBeansShouldDependOnBarBeanTypes() {
54+
this.contextRunner
55+
.withUserConfiguration(FooDependsOnBarTypePostProcessor.class,
56+
FooBarFactoryBeanConfiguration.class)
57+
.run(this::assertThatFooDependsOnBar);
58+
}
59+
60+
@Test
61+
void fooBeansShouldDependOnBarBeanNamesParentContext() {
62+
try (AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(
63+
FooBarFactoryBeanConfiguration.class)) {
64+
this.contextRunner
65+
.withUserConfiguration(FooDependsOnBarNamePostProcessor.class)
66+
.withParent(parentContext).run(this::assertThatFooDependsOnBar);
67+
}
68+
}
69+
70+
@Test
71+
void fooBeansShouldDependOnBarBeanTypesParentContext() {
72+
try (AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(
73+
FooBarFactoryBeanConfiguration.class)) {
74+
this.contextRunner
75+
.withUserConfiguration(FooDependsOnBarTypePostProcessor.class)
76+
.withParent(parentContext).run(this::assertThatFooDependsOnBar);
77+
}
78+
}
79+
80+
private void assertThatFooDependsOnBar(AssertableApplicationContext context) {
81+
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
82+
assertThat(getBeanDefinition("foo", beanFactory).getDependsOn())
83+
.containsExactly("bar", "barFactoryBean");
84+
assertThat(getBeanDefinition("fooFactoryBean", beanFactory).getDependsOn())
85+
.containsExactly("bar", "barFactoryBean");
86+
}
87+
88+
private BeanDefinition getBeanDefinition(String beanName,
89+
ConfigurableListableBeanFactory beanFactory) {
90+
try {
91+
return beanFactory.getBeanDefinition(beanName);
92+
}
93+
catch (NoSuchBeanDefinitionException ex) {
94+
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
95+
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
96+
return getBeanDefinition(beanName,
97+
(ConfigurableListableBeanFactory) parentBeanFactory);
98+
}
99+
throw ex;
100+
}
101+
}
102+
103+
static class Foo {
104+
105+
}
106+
107+
static class Bar {
108+
109+
}
110+
111+
@Configuration(proxyBeanMethods = false)
112+
static class FooBarFactoryBeanConfiguration {
113+
114+
@Bean
115+
public FooFactoryBean fooFactoryBean() {
116+
return new FooFactoryBean();
117+
}
118+
119+
@Bean
120+
public BarFactoryBean barFactoryBean() {
121+
return new BarFactoryBean();
122+
}
123+
124+
}
125+
126+
@Configuration(proxyBeanMethods = false)
127+
static class FooBarConfiguration {
128+
129+
@Bean
130+
public Bar bar() {
131+
return new Bar();
132+
}
133+
134+
@Bean
135+
public Foo foo() {
136+
return new Foo();
137+
}
138+
139+
}
140+
141+
static class FooDependsOnBarTypePostProcessor
142+
extends AbstractDependsOnBeanFactoryPostProcessor {
143+
144+
protected FooDependsOnBarTypePostProcessor() {
145+
super(Foo.class, FooFactoryBean.class, Bar.class, BarFactoryBean.class);
146+
}
147+
148+
}
149+
150+
static class FooDependsOnBarNamePostProcessor
151+
extends AbstractDependsOnBeanFactoryPostProcessor {
152+
153+
protected FooDependsOnBarNamePostProcessor() {
154+
super(Foo.class, FooFactoryBean.class, "bar", "barFactoryBean");
155+
}
156+
157+
}
158+
159+
static class FooFactoryBean implements FactoryBean<Foo> {
160+
161+
@Override
162+
public Foo getObject() {
163+
return new Foo();
164+
}
165+
166+
@Override
167+
public Class<?> getObjectType() {
168+
return Foo.class;
169+
}
170+
171+
}
172+
173+
static class BarFactoryBean implements FactoryBean<Bar> {
174+
175+
@Override
176+
public Bar getObject() {
177+
return new Bar();
178+
}
179+
180+
@Override
181+
public Class<?> getObjectType() {
182+
return Bar.class;
183+
}
184+
185+
}
186+
187+
}

0 commit comments

Comments
 (0)