Skip to content

Commit 4acac6f

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 d9c93bd commit 4acac6f

File tree

2 files changed

+225
-11
lines changed

2 files changed

+225
-11
lines changed

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

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
@@ -48,7 +50,7 @@ public abstract class AbstractDependsOnBeanFactoryPostProcessor implements BeanF
4850

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

51-
private final String[] dependsOn;
53+
private final Object[] dependsOn;
5254

5355
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
5456
Class<? extends FactoryBean<?>> factoryBeanClass, String... dependsOn) {
@@ -57,6 +59,20 @@ protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
5759
this.dependsOn = dependsOn;
5860
}
5961

62+
/**
63+
* Create an instance with target bean and factory bean classes and dependency types.
64+
* @param beanClass target bean class
65+
* @param factoryBeanClass target factory bean class
66+
* @param dependsOn dependency types
67+
* @since 2.2.0
68+
*/
69+
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass,
70+
Class<? extends FactoryBean<?>> factoryBeanClass, Class<?>... dependsOn) {
71+
this.beanClass = beanClass;
72+
this.factoryBeanClass = factoryBeanClass;
73+
this.dependsOn = dependsOn;
74+
}
75+
6076
/**
6177
* Create an instance with target bean class and dependencies.
6278
* @param beanClass target bean class
@@ -67,31 +83,51 @@ protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass, String..
6783
this(beanClass, null, dependsOn);
6884
}
6985

86+
/**
87+
* Create an instance with target bean class and dependency types.
88+
* @param beanClass target bean class
89+
* @param dependsOn dependency types
90+
* @since 2.2.0
91+
*/
92+
protected AbstractDependsOnBeanFactoryPostProcessor(Class<?> beanClass, Class<?>... dependsOn) {
93+
this(beanClass, null, dependsOn);
94+
}
95+
7096
@Override
7197
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
7298
for (String beanName : getBeanNames(beanFactory)) {
7399
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
74100
String[] dependencies = definition.getDependsOn();
75-
for (String bean : this.dependsOn) {
101+
for (String bean : getDependsOn(beanFactory)) {
76102
dependencies = StringUtils.addStringToArray(dependencies, bean);
77103
}
78104
definition.setDependsOn(dependencies);
79105
}
80106
}
81107

82-
private Iterable<String> getBeanNames(ListableBeanFactory beanFactory) {
83-
Set<String> names = new HashSet<>();
84-
names.addAll(Arrays
85-
.asList(BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, this.beanClass, true, false)));
108+
private Set<String> getDependsOn(ListableBeanFactory beanFactory) {
109+
if (this.dependsOn instanceof Class[]) {
110+
return Arrays.stream(((Class[]) this.dependsOn))
111+
.flatMap((beanClass) -> getBeanNames(beanFactory, beanClass).stream())
112+
.collect(Collectors.toCollection(LinkedHashSet::new));
113+
}
114+
return Arrays.stream(this.dependsOn).map(String::valueOf).collect(Collectors.toCollection(LinkedHashSet::new));
115+
}
116+
117+
private Set<String> getBeanNames(ListableBeanFactory beanFactory) {
118+
Set<String> names = getBeanNames(beanFactory, this.beanClass);
86119
if (this.factoryBeanClass != null) {
87-
for (String factoryBeanName : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory,
88-
this.factoryBeanClass, true, false)) {
89-
names.add(BeanFactoryUtils.transformedBeanName(factoryBeanName));
90-
}
120+
names.addAll(getBeanNames(beanFactory, this.factoryBeanClass));
91121
}
92122
return names;
93123
}
94124

125+
private static Set<String> getBeanNames(ListableBeanFactory beanFactory, Class<?> beanClass) {
126+
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, beanClass, true, false);
127+
return Arrays.stream(names).map(BeanFactoryUtils::transformedBeanName)
128+
.collect(Collectors.toCollection(LinkedHashSet::new));
129+
}
130+
95131
private static BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {
96132
try {
97133
return beanFactory.getBeanDefinition(beanName);
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
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, FooBarFactoryBeanConfiguration.class)
48+
.run(this::assertThatFooDependsOnBar);
49+
}
50+
51+
@Test
52+
void fooBeansShouldDependOnBarBeanTypes() {
53+
this.contextRunner
54+
.withUserConfiguration(FooDependsOnBarTypePostProcessor.class, FooBarFactoryBeanConfiguration.class)
55+
.run(this::assertThatFooDependsOnBar);
56+
}
57+
58+
@Test
59+
void fooBeansShouldDependOnBarBeanNamesParentContext() {
60+
try (AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(
61+
FooBarFactoryBeanConfiguration.class)) {
62+
this.contextRunner.withUserConfiguration(FooDependsOnBarNamePostProcessor.class).withParent(parentContext)
63+
.run(this::assertThatFooDependsOnBar);
64+
}
65+
}
66+
67+
@Test
68+
void fooBeansShouldDependOnBarBeanTypesParentContext() {
69+
try (AnnotationConfigApplicationContext parentContext = new AnnotationConfigApplicationContext(
70+
FooBarFactoryBeanConfiguration.class)) {
71+
this.contextRunner.withUserConfiguration(FooDependsOnBarTypePostProcessor.class).withParent(parentContext)
72+
.run(this::assertThatFooDependsOnBar);
73+
}
74+
}
75+
76+
private void assertThatFooDependsOnBar(AssertableApplicationContext context) {
77+
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
78+
assertThat(getBeanDefinition("foo", beanFactory).getDependsOn()).containsExactly("bar", "barFactoryBean");
79+
assertThat(getBeanDefinition("fooFactoryBean", beanFactory).getDependsOn()).containsExactly("bar",
80+
"barFactoryBean");
81+
}
82+
83+
private BeanDefinition getBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {
84+
try {
85+
return beanFactory.getBeanDefinition(beanName);
86+
}
87+
catch (NoSuchBeanDefinitionException ex) {
88+
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
89+
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
90+
return getBeanDefinition(beanName, (ConfigurableListableBeanFactory) parentBeanFactory);
91+
}
92+
throw ex;
93+
}
94+
}
95+
96+
static class Foo {
97+
98+
}
99+
100+
static class Bar {
101+
102+
}
103+
104+
@Configuration(proxyBeanMethods = false)
105+
static class FooBarFactoryBeanConfiguration {
106+
107+
@Bean
108+
public FooFactoryBean fooFactoryBean() {
109+
return new FooFactoryBean();
110+
}
111+
112+
@Bean
113+
public BarFactoryBean barFactoryBean() {
114+
return new BarFactoryBean();
115+
}
116+
117+
}
118+
119+
@Configuration(proxyBeanMethods = false)
120+
static class FooBarConfiguration {
121+
122+
@Bean
123+
public Bar bar() {
124+
return new Bar();
125+
}
126+
127+
@Bean
128+
public Foo foo() {
129+
return new Foo();
130+
}
131+
132+
}
133+
134+
static class FooDependsOnBarTypePostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
135+
136+
protected FooDependsOnBarTypePostProcessor() {
137+
super(Foo.class, FooFactoryBean.class, Bar.class, BarFactoryBean.class);
138+
}
139+
140+
}
141+
142+
static class FooDependsOnBarNamePostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
143+
144+
protected FooDependsOnBarNamePostProcessor() {
145+
super(Foo.class, FooFactoryBean.class, "bar", "barFactoryBean");
146+
}
147+
148+
}
149+
150+
static class FooFactoryBean implements FactoryBean<Foo> {
151+
152+
@Override
153+
public Foo getObject() {
154+
return new Foo();
155+
}
156+
157+
@Override
158+
public Class<?> getObjectType() {
159+
return Foo.class;
160+
}
161+
162+
}
163+
164+
static class BarFactoryBean implements FactoryBean<Bar> {
165+
166+
@Override
167+
public Bar getObject() {
168+
return new Bar();
169+
}
170+
171+
@Override
172+
public Class<?> getObjectType() {
173+
return Bar.class;
174+
}
175+
176+
}
177+
178+
}

0 commit comments

Comments
 (0)