Skip to content

Commit 4681f03

Browse files
authored
Merge pull request #1516 from asavov/controllerFactory
Register ControllerFactory bean definition as opposite to bean instance
2 parents bc8f988 + ad7f1b6 commit 4681f03

File tree

2 files changed

+143
-28
lines changed

2 files changed

+143
-28
lines changed

spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerProcessor.java

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,17 @@
1212
*/
1313
package io.kubernetes.client.spring.extended.controller;
1414

15-
import io.kubernetes.client.extended.controller.Controller;
16-
import io.kubernetes.client.extended.controller.ControllerManager;
15+
import static org.springframework.util.Assert.notNull;
16+
1717
import io.kubernetes.client.extended.controller.reconciler.Reconciler;
1818
import io.kubernetes.client.informer.SharedInformerFactory;
19-
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconciler;
2019
import io.kubernetes.client.spring.extended.controller.factory.KubernetesControllerFactory;
21-
import java.util.concurrent.ExecutorService;
22-
import java.util.concurrent.Executors;
23-
import org.slf4j.Logger;
24-
import org.slf4j.LoggerFactory;
25-
import org.springframework.beans.BeansException;
26-
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
20+
import java.util.function.Supplier;
21+
import org.springframework.beans.factory.config.BeanDefinition;
2722
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
23+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
24+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
25+
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
2826
import org.springframework.core.Ordered;
2927

3028
/**
@@ -34,18 +32,21 @@
3432
* <p>It will create a {@link io.kubernetes.client.extended.controller.Controller} for every
3533
* reconciler instances registered in the spring bean-factory.
3634
*/
37-
public class KubernetesReconcilerProcessor implements BeanFactoryPostProcessor, Ordered {
35+
public class KubernetesReconcilerProcessor implements BeanDefinitionRegistryPostProcessor, Ordered {
3836

39-
private static final Logger log = LoggerFactory.getLogger(KubernetesReconcilerProcessor.class);
37+
public static final String DEFAULT_SHARED_INFORMER_FACTORY_BEAN_NAME = "sharedInformerFactory";
4038

41-
private ControllerManager controllerManager;
39+
private final String sharedInformerFactoryBeanName;
4240

43-
private ExecutorService controllerManagerDaemon = Executors.newSingleThreadExecutor();
41+
private BeanDefinitionRegistry beanDefinitionRegistry;
4442

45-
private SharedInformerFactory sharedInformerFactory;
43+
public KubernetesReconcilerProcessor() {
44+
this(DEFAULT_SHARED_INFORMER_FACTORY_BEAN_NAME);
45+
}
4646

47-
public KubernetesReconcilerProcessor(SharedInformerFactory sharedInformerFactory) {
48-
this.sharedInformerFactory = sharedInformerFactory;
47+
public KubernetesReconcilerProcessor(String sharedInformerFactoryBeanName) {
48+
notNull(sharedInformerFactoryBeanName, "SharedInformerFactory bean name is required");
49+
this.sharedInformerFactoryBeanName = sharedInformerFactoryBeanName;
4950
}
5051

5152
@Override
@@ -54,20 +55,27 @@ public int getOrder() {
5455
}
5556

5657
@Override
57-
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
58-
throws BeansException {
59-
String[] names = beanFactory.getBeanNamesForType(Reconciler.class);
60-
for (String name : names) {
61-
Reconciler reconciler = (Reconciler) beanFactory.getBean(name);
62-
KubernetesReconciler kubernetesReconciler =
63-
reconciler.getClass().getAnnotation(KubernetesReconciler.class);
64-
String reconcilerName = kubernetesReconciler.value();
58+
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
59+
this.beanDefinitionRegistry = registry;
60+
}
61+
62+
@Override
63+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
64+
for (String reconcilerName : beanFactory.getBeanNamesForType(Reconciler.class)) {
65+
66+
Supplier<KubernetesControllerFactory> kubernetesControllerFactorySupplier =
67+
() ->
68+
new KubernetesControllerFactory(
69+
beanFactory.getBean(sharedInformerFactoryBeanName, SharedInformerFactory.class),
70+
beanFactory.getBean(reconcilerName, Reconciler.class));
6571

66-
KubernetesControllerFactory controllerFactory =
67-
new KubernetesControllerFactory(sharedInformerFactory, reconciler);
72+
BeanDefinition controllerFactoryBeanDefinition =
73+
BeanDefinitionBuilder.genericBeanDefinition(
74+
KubernetesControllerFactory.class, kubernetesControllerFactorySupplier)
75+
.getBeanDefinition();
6876

69-
Controller controller = controllerFactory.getObject();
70-
beanFactory.registerSingleton(reconcilerName, controller);
77+
beanDefinitionRegistry.registerBeanDefinition(
78+
reconcilerName + "Controller", controllerFactoryBeanDefinition);
7179
}
7280
}
7381
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
package io.kubernetes.client.spring.extended.controller;
14+
15+
import static org.junit.Assert.assertNotNull;
16+
17+
import io.kubernetes.client.extended.controller.Controller;
18+
import io.kubernetes.client.extended.controller.reconciler.Reconciler;
19+
import io.kubernetes.client.extended.controller.reconciler.Request;
20+
import io.kubernetes.client.extended.controller.reconciler.Result;
21+
import io.kubernetes.client.informer.SharedInformer;
22+
import io.kubernetes.client.informer.SharedInformerFactory;
23+
import io.kubernetes.client.openapi.models.V1Pod;
24+
import io.kubernetes.client.openapi.models.V1PodList;
25+
import io.kubernetes.client.spring.extended.controller.annotation.GroupVersionResource;
26+
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformer;
27+
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers;
28+
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconciler;
29+
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesReconcilerWatches;
30+
import org.junit.Test;
31+
import org.junit.runner.RunWith;
32+
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.beans.factory.annotation.Qualifier;
34+
import org.springframework.boot.autoconfigure.SpringBootApplication;
35+
import org.springframework.boot.test.context.SpringBootTest;
36+
import org.springframework.context.annotation.Bean;
37+
import org.springframework.test.context.junit4.SpringRunner;
38+
39+
@RunWith(SpringRunner.class)
40+
@SpringBootTest(classes = KubernetesReconcilerProcessorTest.App.class)
41+
public class KubernetesReconcilerProcessorTest {
42+
43+
@SpringBootApplication
44+
static class App {
45+
46+
@Bean
47+
KubernetesReconcilerProcessor reconcilerProcessorUnderTesting() {
48+
return new KubernetesReconcilerProcessor();
49+
}
50+
51+
@Bean
52+
SharedInformerFactory sharedInformerFactory() {
53+
return new TestSharedInformerFactory();
54+
}
55+
56+
@KubernetesInformers({
57+
@KubernetesInformer(
58+
apiTypeClass = V1Pod.class,
59+
apiListTypeClass = V1PodList.class,
60+
groupVersionResource = @GroupVersionResource(resourcePlural = "pods"))
61+
})
62+
static class TestSharedInformerFactory extends SharedInformerFactory {}
63+
64+
@Bean("testReconciler1")
65+
TestReconciler testReconciler1ToBeInjected() {
66+
return new TestReconciler();
67+
}
68+
69+
@Bean("testReconciler2")
70+
TestReconciler testReconciler2ToBeInjected() {
71+
return new TestReconciler();
72+
}
73+
}
74+
75+
@KubernetesReconciler(watches = @KubernetesReconcilerWatches())
76+
static class TestReconciler implements Reconciler {
77+
78+
@Autowired private SharedInformer<V1Pod> informerToBeInjected;
79+
80+
@Override
81+
public Result reconcile(Request request) {
82+
return new Result(false);
83+
}
84+
}
85+
86+
@Autowired
87+
@Qualifier("testReconciler1Controller")
88+
private Controller controller1CreatedByReconcilerProcessor;
89+
90+
@Autowired
91+
@Qualifier("testReconciler2Controller")
92+
private Controller controller2CreatedByReconcilerProcessor;
93+
94+
@Autowired
95+
@Qualifier("testReconciler1")
96+
private TestReconciler testReconciler1ToBeInjected;
97+
98+
@Autowired
99+
@Qualifier("testReconciler2")
100+
private TestReconciler testReconciler2ToBeInjected;
101+
102+
@Test
103+
public void testAutowiredFieldsOfReconcilerBeansAreSet() {
104+
assertNotNull(testReconciler1ToBeInjected.informerToBeInjected);
105+
assertNotNull(testReconciler2ToBeInjected.informerToBeInjected);
106+
}
107+
}

0 commit comments

Comments
 (0)