Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a89faa8

Browse filesBrowse files
committed
spring-integration: support auto-configure to shorten configuration steps
1 parent 1c0f0c8 commit a89faa8
Copy full SHA for a89faa8
Expand file treeCollapse file tree

15 files changed

+300
-128
lines changed
Open diff view settings
Collapse file

‎docs/java-controller-tutorial-rewrite-rs-controller.md‎

Copy file name to clipboardExpand all lines: docs/java-controller-tutorial-rewrite-rs-controller.md
+97-10Lines changed: 97 additions & 10 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,33 @@ plugins are present in the [pom.xml](https://github.com/yue9944882/replicaset-co
4646
</plugin>
4747
```
4848

49+
#### Introducing Spring Integration Dependency
50+
51+
Adding the following dependency to your `pom.xml`.
52+
53+
```xml
54+
<dependency>
55+
<groupId>io.kubernetes</groupId>
56+
<artifactId>client-java-spring-integration</artifactId>
57+
<version>${ >= 11.0.0 recommended}</version>
58+
</dependency>
59+
```
60+
61+
The dependency will auto-configure the necessary configuration beans for injecting informers
62+
and reconcilers to your application. And note that you can disable the configuration beans by
63+
setting the following properties in your spring context:
64+
65+
66+
```text
67+
kubernetes.informer.enabled=false # disables informer injection
68+
kubernetes.reconciler.enabled=false # disables reconciler injection
69+
```
70+
4971
#### Adding a Main Class
5072

5173
So that the project can be packaged as a executable jar. See the example class [here](https://github.com/yue9944882/replicaset-controller/blob/master/src/main/java/com/github/yue9944882/kubernetes/Application.java).
5274

53-
#### Loading Post-Processor Spring Beans
75+
##### Loading Post-Processor Spring Beans (Required only if you're using < 11.0.0 releases)
5476

5577
Adding the following annotation to whatever Java class under spring context, so that processors can be activated.
5678

@@ -60,10 +82,6 @@ Adding the following annotation to whatever Java class under spring context, so
6082

6183
Corresponding example is available [here](https://github.com/yue9944882/replicaset-controller/blob/master/src/main/java/com/github/yue9944882/kubernetes/config/ControllerConfiguration.java#L20).
6284

63-
__NOTE__: In the future releases (already landed on master, will release after 11.0.0), you will be able to activate the processors by configuration-
64-
beans. To previewing the feature, you can take a glance at the test codes for [KubernetesReconcilerConfigurer](https://github.com/kubernetes-client/java/blob/351ffa13d49cb76445788d78bf83e03a5edf139a/spring/src/test/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerCreatorTest.java#L75-L79) and
65-
[KubernetesInformerConfigurer](https://github.com/kubernetes-client/java/blob/351ffa13d49cb76445788d78bf83e03a5edf139a/spring/src/test/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerCreatorTest.java#L73-L76).
66-
6785
#### Declaring Your Informer Factory
6886

6987
You're supposed to create a new class (can be a inner-class) extending `io.kubernetes.client.informer.SharedInformerFactory`,
@@ -99,10 +117,11 @@ The registered informer-factory won't be running unless you explcitly calls `sta
99117
the method is the trigger to run the controller, so hold it carefully until you're ready :). In the example project, the
100118
informer-factory was started inside `ControllerManager#run`.
101119

102-
The [KubernetesInformerFactoryProcessor](https://github.com/kubernetes-client/java/blob/master/spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerFactoryProcessor.java)
103-
will be parsing the `@KubernetesInformers` annotation on informer-factory class and then register `SharedInformer` and
104-
`Lister` beans for the kubernetes resource classes. You can easily acquire them by declaring them as parameters in the
105-
bean method. See this example source to see the per-resource informer/lister bean registration [here](https://github.com/yue9944882/replicaset-controller/blob/c8dda02fe444d7154117b9bf0583557502694e1b/src/main/java/com/github/yue9944882/kubernetes/config/ControllerConfiguration.java#L35-L43).
120+
As a deeper insight, it's the [KubernetesInformerFactoryProcessor](https://github.com/kubernetes-client/java/blob/master/spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerFactoryProcessor.java)
121+
parsing the `@KubernetesInformers` annotation on informer-factory class and then register `SharedInformer` and
122+
`Lister` beans for the kubernetes resource classes. You can easily acquire them by `@Autowired` (for >= 11.0.0 release)
123+
or declaring them as parameters in the bean method. See this example source to see the per-resource informer/lister
124+
bean registration [here](https://github.com/yue9944882/replicaset-controller/blob/c8dda02fe444d7154117b9bf0583557502694e1b/src/main/java/com/github/yue9944882/kubernetes/config/ControllerConfiguration.java#L35-L43).
106125

107126

108127
#### Declaring Your Reconciler
@@ -126,10 +145,78 @@ the watch connections are managed by informer-factory and they're multiplex'd. S
126145
to the watch connection. For more detail, take a look at the example code [here](https://github.com/yue9944882/replicaset-controller/blob/c8dda02fe444d7154117b9bf0583557502694e1b/src/main/java/com/github/yue9944882/kubernetes/ReplicaSetReconciler.java#L27-L40).
127146

128147

148+
#### Injecting Informer/Lister using @Autowired (Optional for >= 11.0.0 releases)
149+
150+
You can easily acquire `SharedInformer` and `Lister` instances via `@Autowired` annotations instead of passing them from
151+
the bean constructor, see the following example:
152+
153+
```java
154+
public class ReplicaSetReconciler implements Reconciler {
155+
@Autowired private SharedInformer<V1Pod> podInformer;
156+
@Autowired private Lister<V1Pod> podLister;
157+
@Autowired private SharedInformer<V1Node> nodeInformer;
158+
@Autowired private Lister<V1Node> nodeLister;
159+
...
160+
}
161+
```
162+
163+
Note that the type parameter for the informer and lister i.e. the kubernetes api resource type must be declared in your
164+
`@KubernetesInformers` annotation.
165+
166+
#### Setting Event-Filter or ReadyFunc for your reconciler
167+
168+
Both the event-filter method and ready-func method is supposed to be "public" access.
169+
170+
```java
171+
public class ReplicaSetReconciler implements Reconciler {
172+
...
173+
@AddWatchEventFilter(apiTypeClass = V1Pod.class)
174+
public boolean onAddFilter(V1Pod pod) {
175+
return true; // returns true to handle the event
176+
}
177+
178+
@UpdateWatchEventFilter(apiTypeClass = V1Pod.class)
179+
public boolean onUpdateFilter(V1Pod oldPod, V1Pod newPod) {
180+
return true; // returns true to handle the event
181+
}
182+
183+
@DeleteWatchEventFilter(apiTypeClass = V1Pod.class)
184+
public boolean onDeleteFilter(V1Pod pod) {
185+
return true; // returns true to handle the event
186+
}
187+
188+
@KubernetesReconcilerReadyFunc
189+
public boolean podInformerCacheReady() {
190+
return podInformer.hasSynced(); // return true if reconciler is ready to run.
191+
}
192+
..
193+
}
194+
```
195+
196+
#### Creating Your Controller Bean (Required for >= 11.0.0 releases)
197+
198+
The controller bean is the entry bean to run your reconciler class definition. You're supposed to create a controller
199+
bean instance using `KubernetesControllerFactory`:
200+
201+
202+
```java
203+
@Configuration
204+
public class MyConfiguration {
205+
...
206+
@Bean
207+
public KubernetesControllerFactory replicasetController(
208+
SharedInformerFactory sharedInformerFactory,
209+
Reconciler reconciler) {
210+
return new KubernetesControllerFactory(sharedInformerFactory, reconciler);
211+
}
212+
...
213+
}
214+
```
215+
129216
#### Running the Reconcilers
130217

131218
Now both the informer-factory and the reconciler are set, the last step is to stitch them together by adding a starter
132-
(or runner) bean implemeting `InitializingBean` as is shown in the following approaches:
219+
(or a `CommandLineRunner`) or a bean implemeting `InitializingBean` as is shown in the following approaches:
133220

134221

135222
- (Option 1) Run it immediately.
Collapse file

‎examples/src/main/java/io/kubernetes/client/examples/SpringControllerExample.java‎

Copy file name to clipboardExpand all lines: examples/src/main/java/io/kubernetes/client/examples/SpringControllerExample.java
+3-3Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,9 @@ public CommandLineRunner commandLineRunner(
6767
// *REQUIRED*
6868
// Configurer components that registers informers to the informer-factory in the context.
6969
@Bean
70-
public KubernetesInformerConfigurer kubernetesInformerConfigurer(ApiClient apiClient) {
71-
return new KubernetesInformerConfigurer(apiClient);
70+
public KubernetesInformerConfigurer kubernetesInformerConfigurer(
71+
ApiClient apiClient, SharedInformerFactory sharedInformerFactory) {
72+
return new KubernetesInformerConfigurer(apiClient, sharedInformerFactory);
7273
}
7374

7475
// *REQUIRED*
@@ -126,7 +127,6 @@ public static class MySharedInformerFactory extends SharedInformerFactory {}
126127
// io.kubernetes.client.extended.controller.Controller}
127128
// with the name specified and registering it to the spring bean-factory.
128129
@KubernetesReconciler(
129-
value = "node-printing-controller",
130130
watches =
131131
@KubernetesReconcilerWatches({
132132
@KubernetesReconcilerWatch(
Collapse file

‎spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerConfigurer.java‎

Copy file name to clipboardExpand all lines: spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerConfigurer.java
+6-2Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
package io.kubernetes.client.spring.extended.controller;
1414

15+
import io.kubernetes.client.informer.SharedInformerFactory;
1516
import io.kubernetes.client.openapi.ApiClient;
1617
import org.springframework.beans.factory.FactoryBean;
1718

@@ -23,14 +24,17 @@ public class KubernetesInformerConfigurer
2324
implements FactoryBean<KubernetesInformerFactoryProcessor> {
2425

2526
private final ApiClient apiClient;
27+
private final SharedInformerFactory sharedInformerFactory;
2628

27-
public KubernetesInformerConfigurer(ApiClient apiClient) {
29+
public KubernetesInformerConfigurer(
30+
ApiClient apiClient, SharedInformerFactory sharedInformerFactory) {
2831
this.apiClient = apiClient;
32+
this.sharedInformerFactory = sharedInformerFactory;
2933
}
3034

3135
@Override
3236
public KubernetesInformerFactoryProcessor getObject() throws Exception {
33-
return new KubernetesInformerFactoryProcessor(apiClient);
37+
return new KubernetesInformerFactoryProcessor(apiClient, sharedInformerFactory);
3438
}
3539

3640
@Override
Collapse file

‎spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerFactoryProcessor.java‎

Copy file name to clipboardExpand all lines: spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesInformerFactoryProcessor.java
+5-41Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,11 @@
1919
import io.kubernetes.client.openapi.ApiClient;
2020
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformer;
2121
import io.kubernetes.client.spring.extended.controller.annotation.KubernetesInformers;
22-
import io.kubernetes.client.util.ClientBuilder;
2322
import io.kubernetes.client.util.generic.GenericKubernetesApi;
24-
import java.io.IOException;
2523
import java.time.Duration;
26-
import java.util.Map;
27-
import java.util.Optional;
2824
import org.slf4j.Logger;
2925
import org.slf4j.LoggerFactory;
3026
import org.springframework.beans.BeansException;
31-
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
3227
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
3328
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3429
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -57,53 +52,22 @@ public class KubernetesInformerFactoryProcessor
5752

5853
private BeanDefinitionRegistry beanDefinitionRegistry;
5954

60-
private ApiClient apiClient = null;
55+
private final ApiClient apiClient;
56+
private final SharedInformerFactory sharedInformerFactory;
6157

62-
public KubernetesInformerFactoryProcessor(ApiClient apiClient) {
58+
public KubernetesInformerFactoryProcessor(
59+
ApiClient apiClient, SharedInformerFactory sharedInformerFactory) {
6360
this.apiClient = apiClient;
61+
this.sharedInformerFactory = sharedInformerFactory;
6462
}
6563

6664
@Override
6765
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
6866
throws BeansException {
69-
Optional<String> sharedInformerFactoryBeanName;
70-
try {
71-
Map<String, SharedInformerFactory> sharedInformerFactories =
72-
beanFactory.getBeansOfType(SharedInformerFactory.class);
73-
if (sharedInformerFactories.size() > 1) {
74-
log.warn("More than sharedInformerFactory registered..");
75-
return;
76-
}
77-
sharedInformerFactoryBeanName = sharedInformerFactories.keySet().stream().findFirst();
78-
} catch (NoSuchBeanDefinitionException e) {
79-
// should never happen..
80-
log.error("No sharedInformerFactory bean registered..");
81-
return;
82-
}
83-
84-
if (!sharedInformerFactoryBeanName.isPresent()) {
85-
log.info("No sharedInformerFactory selected, skipping informers constructing..");
86-
return;
87-
}
88-
89-
if (this.apiClient == null) {
90-
try {
91-
this.apiClient = beanFactory.getBean(ApiClient.class);
92-
} catch (NoSuchBeanDefinitionException e) {
93-
log.info("No ApiClient bean found, falling-back to default initialization..");
94-
try {
95-
this.apiClient = ClientBuilder.standard().build();
96-
} catch (IOException ex) {
97-
log.error("failed initializing ApiClient", ex);
98-
return;
99-
}
100-
}
101-
}
10267

10368
this.apiClient.setHttpClient(
10469
this.apiClient.getHttpClient().newBuilder().readTimeout(Duration.ZERO).build());
10570

106-
SharedInformerFactory sharedInformerFactory = beanFactory.getBean(SharedInformerFactory.class);
10771
KubernetesInformers kubernetesInformers =
10872
sharedInformerFactory.getClass().getAnnotation(KubernetesInformers.class);
10973
if (kubernetesInformers == null || kubernetesInformers.value().length == 0) {
Collapse file

‎spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerConfigurer.java‎

Copy file name to clipboardExpand all lines: spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerConfigurer.java
-39Lines changed: 0 additions & 39 deletions
This file was deleted.
Collapse file

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

Copy file name to clipboardExpand all lines: spring/src/main/java/io/kubernetes/client/spring/extended/controller/KubernetesReconcilerProcessor.java
-3Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ public int getOrder() {
5858
@Override
5959
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
6060
throws BeansException {
61-
if (this.sharedInformerFactory == null) {
62-
this.sharedInformerFactory = beanFactory.getBean(SharedInformerFactory.class);
63-
}
6461
String[] names = beanFactory.getBeanNamesForType(Reconciler.class);
6562
for (String name : names) {
6663
Reconciler reconciler = (Reconciler) beanFactory.getBean(name);
Collapse file

‎spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/KubernetesReconciler.java‎

Copy file name to clipboardExpand all lines: spring/src/main/java/io/kubernetes/client/spring/extended/controller/annotation/KubernetesReconciler.java
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@
3434
/**
3535
* The name of the Kubernetes Reconciler.
3636
*
37+
* <p>NOTE: No longer in use for version >= 11.0.0
38+
*
3739
* @return the string
3840
*/
39-
String value();
41+
@Deprecated
42+
String value() default "";
4043

4144
/**
4245
* Watches kubernetes resources.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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.config;
14+
15+
import java.lang.annotation.Documented;
16+
import java.lang.annotation.ElementType;
17+
import java.lang.annotation.Inherited;
18+
import java.lang.annotation.Retention;
19+
import java.lang.annotation.RetentionPolicy;
20+
import java.lang.annotation.Target;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
22+
23+
@Target(ElementType.TYPE)
24+
@Retention(RetentionPolicy.RUNTIME)
25+
@Documented
26+
@Inherited
27+
@ConditionalOnProperty(value = "kubernetes.actuator.prometheus.enabled")
28+
public @interface ConditionalOnActuatorPrometheusEndpointEnabled {}
Collapse file
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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.config;
14+
15+
import java.lang.annotation.Documented;
16+
import java.lang.annotation.ElementType;
17+
import java.lang.annotation.Inherited;
18+
import java.lang.annotation.Retention;
19+
import java.lang.annotation.RetentionPolicy;
20+
import java.lang.annotation.Target;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
22+
23+
@Target(ElementType.TYPE)
24+
@Retention(RetentionPolicy.RUNTIME)
25+
@Documented
26+
@Inherited
27+
@ConditionalOnProperty(value = "kubernetes.informer.enabled", matchIfMissing = true)
28+
public @interface ConditionalOnKubernetesInformerEnabled {}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.