Provide listener framework for JDBC interactions and query executions via proxy.
R2DBC Proxying Framework
ttddyy/evernote-rest-webapp 26
Stateless MicroService Web Application which provides Restful APIs for Evernote.
ttddyy/datasource-proxy-r2dbc 25
proxy library for R2DBC-SPI
ttddyy/datasource-proxy-examples 20
examples for how to use datasource-proxy
Provides assertion APIs for query executions with assertEquals and assertThat(AssertJ and Hamcrest)
demo code
Samples for r2dbc-proxy
ttddyy/datasource-proxy-r2dbc-samples 2
Samples for datasource-proxy-r2dbc
ttddyy/junit5-extension-wait 2
JUnit5 Jupiter extension to delay finishing the test method
push eventr2dbc/r2dbc-proxy
commit sha d92560f3046ca12983d7b2f72e34e2f18d28e9ea
Extract StopWatch to an independent class
push time in 3 days
push eventr2dbc/r2dbc-proxy
commit sha 5a2b4305ecdeef4884e00e71bc452908904b7241
Extract StopWatch to an independent class (cherry picked from commit d92560f3046ca12983d7b2f72e34e2f18d28e9ea)
push time in 3 days
push eventr2dbc/r2dbc-proxy
commit sha 0febd39516e11059bba7f05a9c4742d37cfd1122
Introduce "FluxQueryInvocation" Previously, simple Flux with `doFirst()` and `doFinally()` were used to invoke method before/after callbacks. Instead, create `FluxQueryInvocation`, a new FluxOperator` and its subscriber/subscription to perform callback logic. [issue #70]
commit sha 8e318e8ebf782fedf8cb48076d65babe6454ae41
Use dedicated operator for method callback Previously, for methods that return publisher, method callback logic is implemented by wrapping the result publisher with new Flux using `doOnSubscribe`, `doFinally`, etc. In this commit, instead of wrap and augment the publisher, creates dedicated operators, `[Mono|Flux]MethodInvocation` and its subscriber/subscription, to handle method callback handling. Also, adds `MonoMethodInvocationConnectionFactoryCreate` to special handle `ConnectionFactory#create` method callbacks. [issue #70]
commit sha 4cdbfcc5bd12b4713bfa0fc21d8af937d2d33efb
Use custom subscribers only Previously, custom operators(`[Mono|Flux]MethodInvocation`, etc) were simply delegating the calls to custom subscribers that perform callback logic. In this commit, instead of custom operators, just use custom subscribers and use `Operations#liftPublisher` and `transform()` methods to apply them. [issue #70]
commit sha 9f95fe057d95d293429832ba9b905d32941a12bd
Merge branch 'gh-70_custom-subscriber' into main [closes #70]
push time in 3 days
issue closedr2dbc/r2dbc-proxy
Create dedicated subscribers to handle callback logic
Currently, callback logic for methods that return a publisher is implemented by wrapping the result publisher with a new Flux using doOnSubscribe, doFinally, etc., and same for query callback.
Since this is a bit fragile implementation, instead, create dedicated custom subscribers that performs callback logic, and apply them to the returned publisher.
closed time in 3 days
ttddyypush eventr2dbc/r2dbc-proxy
commit sha abaca50c04270344274419b335768691b9a4fa43
Introduce "FluxQueryInvocation" Previously, simple Flux with `doFirst()` and `doFinally()` were used to invoke method before/after callbacks. Instead, create `FluxQueryInvocation`, a new FluxOperator` and its subscriber/subscription to perform callback logic. [issue #70]
commit sha 80bf30c0bf48634525043cf795a762fdbea874ab
Use dedicated operator for method callback Previously, for methods that return publisher, method callback logic is implemented by wrapping the result publisher with new Flux using `doOnSubscribe`, `doFinally`, etc. In this commit, instead of wrap and augment the publisher, creates dedicated operators, `[Mono|Flux]MethodInvocation` and its subscriber/subscription, to handle method callback handling. Also, adds `MonoMethodInvocationConnectionFactoryCreate` to special handle `ConnectionFactory#create` method callbacks. [issue #70]
commit sha 19fd6ad22e0a136b099cc66b666ea8973390f419
Use custom subscribers only Previously, custom operators(`[Mono|Flux]MethodInvocation`, etc) were simply delegating the calls to custom subscribers that perform callback logic. In this commit, instead of custom operators, just use custom subscribers and use `Operations#liftPublisher` and `transform()` methods to apply them. [issue #70]
commit sha 2ca64b9ef1e586b01afcc13da491efd72f5c1b22
Merge branch 'gh-70_custom-subscriber' into 0.8.x [closes #70]
push time in 3 days
issue openedr2dbc/r2dbc-proxy
Create dedicated subscribers to handle callback logic
Currently, callback logic for methods that return a publisher is implemented by wrapping the result publisher with a new Flux using doOnSubscribe, doFinally, etc., and same for query callback.
Since this is a bit fragile implementation, instead, create dedicated custom subscribers that performs callback logic, and apply them to the returned publisher.
created time in 4 days
issue commentspring-projects/spring-security
Make "SECURITY_CONTEXT_ATTRIBUTES" key in subscriber context publicly accessible
Yeah, I have a utility class that uses the String key "org.springframework.security.SECURITY_CONTEXT_ATTRIBUTES" to retrieve Authentication from reactor context.
This works but since it is bit of internal to the spring security, it would be nice to have public(official) way of getting Authentication(as well as HttpServletRequest and HttpServletResponse) in WebClient filters in servlet environment.
I think it is in common needs getting Authentication when writing a custom WebClient filters.
comment created time in 7 days
push eventr2dbc/r2dbc-proxy
commit sha 5718b9aa46669fa209d79b41785e80e568e7ca18
Add ProxyConfigHolder Add `ProxyConfigHolder` interface and handling logic to the proxy handler. [closes #69] (cherry picked from commit dfe9e2a218ad52e2f90d6ca280481a22257add2c)
push time in 9 days
issue closedr2dbc/r2dbc-proxy
Provide a mechanism to retrieve "ProxyConfig" from proxied object
Currently, there is no means to retrieve ProxyConfig from proxied objects.
Similar to the ConnectionHolder interface which provides a method to extract Connection from proxied objects, introduce ProxyConfigHolder interface and add handling logic to the proxy handler.
closed time in 9 days
ttddyypush eventr2dbc/r2dbc-proxy
commit sha dfe9e2a218ad52e2f90d6ca280481a22257add2c
Add ProxyConfigHolder Add `ProxyConfigHolder` interface and handling logic to the proxy handler. [closes #69]
push time in 9 days
issue openedr2dbc/r2dbc-proxy
Provide a mechanism to retrieve "ProxyConfig" from proxied object
Currently, there is no means to retrieve ProxyConfig from proxied objects.
Similar to the ConnectionHolder interface which provides a method to extract Connection from proxied objects, introduce ProxyConfigHolder interface and add handling logic to the proxy handler.
created time in 9 days
push eventttddyy/r2dbc-proxy-examples
commit sha 16d30f6fdbb805607aa459d7e52f1862b0d939cb
Use beforeQuery/afterQuery methods for query execution callback
commit sha 5ae0653f4593b52a4701cc1c4532894b6d0db482
Update TracingExecutionListener Adds more endpoints: - `R2dbcSpiController` for using R2DBC SPI - `DatabaseClientController` for using `DatabaseClient` Also, adds unit test for `TracingExecutionListener`.
commit sha 102e6158ed1260ef7dcb87f50fe4f232a59944d0
Minor dependency upgrade
push time in 11 days
issue commentspring-projects/spring-framework
Mechanism to access request bound objects in WebClient filter in servlet env
We can aim to make it as easy as possible but we can't make the assumption that it is always needed.
Ok, thanks.
At least having mechanism to pass values to nested calls is really helpful. Then, WebClientCustomizer can handle population part in boot application.
comment created time in 12 days
issue commentspring-projects/spring-framework
Support registration of null reference for BeanFactoryPostProcessor
@quaff hm, by quick looking the code, what I can think of are:
- Original definition is looked up via bean name
dataSource, so it won't work whenDataSourceis registered under different name. - Cannot simply retrieve the raw
DataSource. It always need to unwrap fromTracingDataSource. - For
DataSource, if connection pool is involved, which usually shaped asDataSourceand delegate to actualDataSource, usually what you want to instrument is the outer mostDataSourcebecause you want to capture the application behavior not the connection pool behavior. (can be but secondary to the application behavior). I think swapping bean definitions would be difficult to handle such case. - It is using
GlobalTracer.get()as static retrieval. but you want to allow configuring own tracer bean to use. So, dependency injection would be hard to work on at this low level.
comment created time in 12 days
issue commentspring-projects/spring-framework
Support registration of null reference for BeanFactoryPostProcessor
I think my solution is simpler and elegant
Haha, yeah, probably. It's subjective and also depends on the requirement of your application. For example, sleuth uses more BPP and open-telemetry maybe use byte code manipulation(I didn't check, simply my guess since I remember I saw ByteBuddy dependency there) for tracing instrumentation. I think one drawback with BFPP impl above is it will lose the original bean definition with original name. So, whether it is acceptable compromise or not is upto the requirement for your app.
Sorry, it has derailed the original issue. Just a bit of side chatting.
comment created time in 13 days
issue commentspring-projects/spring-framework
Support registration of null reference for BeanFactoryPostProcessor
Hi @quaff
Isn't it more natural to use BeanPostProcessor to decorate those beans?
For example, spring-boot-data-source-decorator wraps DataSource with BPP here.
BTW, if you want to instrument DataSource with tracer, you could use spring-boot-data-source-decorator to wrap DataSource with datasource-proxy or p6spy for Spring Boot application. Or you could use java-jdbc if it is opentracing.
comment created time in 13 days
push eventr2dbc/r2dbc-proxy
commit sha 667d3be9889ecf2134fc2447ed2e930c8fb2e007
Fix "ConnectionFactory#create" after-method callback Wrap the return of `ConnectionFactory#create` with Mono. This fixes after-method callback to be invoked immediately after original `create` method is invoked in case when "usingWhen" is used. [closes #68] (cherry picked from commit 33984e2ed33c5ca606b02587c3cb92d0c92db5ef)
push time in 13 days
issue closedr2dbc/r2dbc-proxy
Make "afterMethod" callback work correctly for "ConnectionFactory#create" with "usingWhen"
When [Mono|Flux]#usingWhen is used for ConnectionFactory#create(), afterMethod callback is performed AFTER Connection::close(from async-cleanup).
Flux.usingWhen(connectionFactory.create(), connection -> {
// perform db operation
}, Connection::close, (c, err) -> c.close(), Connection::close);
This is because usingWhen method defers the completion of "resource supplier"(ConnectionFactory#create) until "async-cleanup"(Connection#close) to be finished.
There are two ways in r2dbc-proxy to make this work:
-
Wrap the proxied result(Flux) to Mono. When first element is emitted, the Mono makes cancel to the wrapped Flux which triggers
doFinallyon the Flux before "async-cleanup". -
Use
doOnNextto trigger afterMethod callback. Instead of usingdoFinally, special handle theConnectionFactory#createto usedoOnNext()to trigger the afterMethod callback. As soon as an element is emitted,doOnNext()is called before "async-cleanup".
If client side need to make it work for now, the quick workaround is:
Wrap the ConnectionFactory#create with Mono#from
return Flux.usingWhen(Mono.from(this.connectionFactory.create()), connection -> {
// logic to access DB
}, Connection::close, (c, err) -> c.close(), Connection::close);
For DatabaseClient in spring, the logic to acquire a connection already wraps the ConnectionFactory#create with Mono; so, DatabaseClient works without any changes.
private static Mono<Connection> fetchConnection(ConnectionFactory connectionFactory) {
return Mono.from(connectionFactory.create());
}
closed time in 13 days
ttddyypush eventr2dbc/r2dbc-proxy
commit sha 33984e2ed33c5ca606b02587c3cb92d0c92db5ef
Fix "ConnectionFactory#create" after-method callback Wrap the return of `ConnectionFactory#create` with Mono. This fixes after-method callback to be invoked immediately after original `create` method is invoked in case when "usingWhen" is used. [closes #68]
push time in 13 days
issue commentspring-projects/spring-framework
Mechanism to access request bound objects in WebClient filter in servlet env
add an option to have ClientRequest attributes be saved under some well known key in the Reactor context.
This sounds a nice solution.
It may also be good to auto attach servlet request, etc to the reactor context if in servlet environment; So that, ExchangeFilterFunction can have consistent way to retrieve servlet request and values associated to the attributes.
This gives benefit to library writers since everything concludes in ExchangeFilterFunction, maybe in combination with servlet Filter to populates values to request attributes, instead of interleaving WebClient.Builder or WebClient#attributes at WebClient build time.
comment created time in 14 days
issue commentspring-projects/spring-framework
Mechanism to access request bound objects in WebClient filter in servlet env
If WebClient.Builder could setup its subscriber context(defaultContext method below), maybe this would work.
FooContext.set("main-thread"); // setting to threadlocal
// a filter uses "foo" from subscriber context
ExchangeFilterFunction filter = (request, next) ->
Mono.subscriberContext()
.map(context -> (String) context.get("foo"))
.map(foo -> ClientRequest.from(request).header("foo", foo).build())
.flatMap(next::exchange);
WebClient webClient = WebClient.builder()
.filter(filter)
// populate subscriber context
.defaultContext(context -> context.hasKey("foo") ? context : context.put("foo", FooContext.get()))
.build();
webClient.get()
.uri("http://foo.com")
.retrieve()
.bodyToMono(String.class)
.flatMap(body ->
webClient.get()
.uri("http://bar.com")
.retrieve()
.bodyToMono(String.class)
)
.subscribeOn(Schedulers.boundedElastic()) // on different thread...
....
;
// both calls will have header "foo=main-thread"
When nested WebClient is called, the context key "foo" has already populated by outer WebClient, which used the original caller's thread.
Not sure it is even possible, but an idea.
comment created time in 15 days
issue openedr2dbc/r2dbc-proxy
Make "afterMethod" callback work correctly for "ConnectionFactory#create" with "usingWhen"
When [Mono|Flux]#usingWhen is used for ConnectionFactory#create(), afterMethod callback is performed AFTER Connection::close(from async-cleanup).
Flux.usingWhen(connectionFactory.create(), connection -> {
// perform db operation
}, Connection::close, (c, err) -> c.close(), Connection::close);
This is because usingWhen method defers the completion of "resource supplier"(ConnectionFactory#create) until "async-cleanup"(Connection#close) to be finished.
There are two ways in r2dbc-proxy to make this work:
-
Wrap the proxied result(Flux) to Mono. When first element is emitted, the Mono makes cancel to the wrapped Flux which triggers
doFinallyon the Flux before "async-cleanup". -
Use
doOnNextto trigger afterMethod callback. Instead of usingdoFinally, special handle theConnectionFactory#createto usedoOnNext()to trigger the afterMethod callback. As soon as an element is emitted,doOnNext()is called before "async-cleanup".
If client side need to make it work for now, the quick workaround is:
Wrap the ConnectionFactory#create with Mono#from
return Flux.usingWhen(Mono.from(this.connectionFactory.create()), connection -> {
// logic to access DB
}, Connection::close, (c, err) -> c.close(), Connection::close);
For DatabaseClient in spring, the logic to acquire a connection already wraps the ConnectionFactory#create with Mono; so, DatabaseClient works without any changes.
private static Mono<Connection> fetchConnection(ConnectionFactory connectionFactory) {
return Mono.from(connectionFactory.create());
}
created time in 17 days
issue commentspring-projects/spring-framework
Mechanism to access request bound objects in WebClient filter in servlet env
@rstoyanchev Oh, I wasn't aware of attributes method. Thanks.
Certainly it would be nice to mention ThreadLocal in documentation for attribute method usage.
I have simulated couple of our usecases trying with attributes in servlet environment with WebClient.
This serves most of the cases since I can assign values to attributes from Threadlocal at the time when request is made and on the thread that is making a request.
However, I found one case hard to do with attributes, which is nesting remote calls.
For example, make a first remote call, then based on the response, create another remote call.
Sample code:
ExchangeFilterFunction filter = (request, next) -> {
log.info("filter map=" + request.attributes());
return next.exchange(request);
};
WebClient webClient = WebClient.builder().filter(filter).defaultRequest(spec -> {
spec.attribute("bar", "BAR");
spec.attribute("tid", Thread.currentThread().getId());
spec.attribute("tname", Thread.currentThread().getName());
}).build();
webClient.get().uri("http://service1.com") // first call
.attribute("foo", "FOO")
.retrieve()
.bodyToMono(String.class)
.flatMap(str -> {
return webClient.get().uri("http://service2.com") // second call
.retrieve()
.bodyToMono(String.class);
})
.subscribeOn(Schedulers.boundedElastic()) // on different thread...
.block();
When making the first call, attributes tid and tname are main thread, but for the second call, the thread is on elastic thread; so cannot retrieve thread local values that are bound to the caller.
In the real environment, these two calls are service-to-service calls and when I call another service, I need to propagate some values stored in caller's thread local. (very much similar to ServletBearerExchangeFilterFunction in Spring Security)
Workaround can be, when constructing the second call, explicitly add attribute method and pass a value that the filter is looking for. However, it is invasive to application code and would like to handle it in filter or construction of webclient in library.
Currently, I use subscriber context approach as mentioned in the description. (reusing SecurityReactorContextSubscriberRegistrar from Spring Security)
Also, interesting thing is that the ServletOAuth2AuthorizedClientExchangeFilterFunction (pointed in your comment) uses attributes but also it is getting attribute values(request, response, and auth) from subscriber context which is populated by the lifter hook (SecurityReactorContextSubscriberRegistrar).
So, attributes works for single remote call cases, but when multiple calls on different threads are involved, I think above mentioned Hook approach may be in need.
comment created time in 17 days
pull request commentspring-projects/spring-framework
Efficiency of beanfactory postprocessors execution
I believe priority ordered BFPPs need to be applied first, THEN rest of the BFPP can be instantiated.
comment created time in 20 days
issue commentspring-projects/spring-boot
Provide diagnostic information about the ordering of auto-configuration classes
For those who want to have auto configuration order logged:
I wrote this class as a temporal workaround to write out "Auto configuration order report" to the log.
This class reflectively accesses auto configuration sorter and write the report upon receiving AutoConfigurationImportEvent.
code:
/**
* Write the processing order of auto configuration classes to the log.
* <p>
* This implementation reflectively invokes {@code AutoConfigurationSorter} to sort auto
* configuration classes since Spring Boot does not expose the sorting infrastructure for
* auto configuration classes.
* <p>
* Note: This class doesn't work with {@code ApplicationContextRunner}. This is because
* {@code ApplicationContextRunner} does not trigger
* {@link AutoConfigurationImportListener} event and relies on the directly
* populating(recording) {@link ConditionEvaluationReport} via
* {@link SpringBootCondition}. The configuration order is sorted by
* {@code AutoConfigurations} when new configurations are added to the runner. One
* possible solution is to use {@code ApplicationContextRunner#with} method to return a
* proxy. At the time of running the runner, it can introspect all configurations, which
* has ordered, and report the order of auto configuration classes.
* <p>
* https://github.com/spring-projects/spring-boot/issues/20732
*
* @author Tadaya Tsuyukubo
*/
// Inherit the logging category from Spring Boot. For example, with "--debug" option,
// "LoggingApplicationListener" sets the log level to "debug" for Spring Boot categories.
// Then, this logger will automatically inherit the same level.
@Slf4j(topic = "org.springframework.boot.mylib")
public class AutoConfigurationOrderLoggingListener
implements BeanFactoryAware, ResourceLoaderAware, AutoConfigurationImportListener {
private static final String SORTER_CLASS = "org.springframework.boot.autoconfigure.AutoConfigurationSorter";
private ConfigurableListableBeanFactory beanFactory;
private ResourceLoader resourceLoader;
@Override
public void onAutoConfigurationImportEvent(AutoConfigurationImportEvent event) {
// if (!log.isDebugEnabled()) {
// return; // only run when debug is on
// }
List<String> configs = event.getCandidateConfigurations();
List<String> sorted;
try {
sorted = sort(configs);
}
catch (Exception ex) {
log.error("Failed to sort auto configuration classes", ex);
return; // do not proceed
}
// If we want to follow how "ConditionEvaluationReport" is logged, log them at
// "ContextRefreshedEvent" and "ApplicationFailedEvent" with implementing
// "GenericApplicationListener" (see "ConditionEvaluationReportLoggingListener").
// Then, register to "spring.factories" as "ApplicationListener".
logAutoConfigurationOrder(sorted);
}
private void logAutoConfigurationOrder(List<String> configs) {
StringBuilder sb = getLogMessage(configs, "AUTO CONFIGURATION ORDER REPORT");
log.debug(sb.toString());
}
private StringBuilder getLogMessage(List<String> configs, String title) {
StringBuilder message = new StringBuilder();
message.append(String.format("%n%n%n"));
StringBuilder separator = new StringBuilder();
for (int i = 0; i < title.length(); i++) {
separator.append("=");
}
message.append(String.format("%s%n", separator));
message.append(String.format("%s%n", title));
message.append(String.format("%s%n%n%n", separator));
for (int i = 0; i < configs.size(); i++) {
message.append(String.format("%3d - %s%n", i + 1, configs.get(i)));
}
message.append(String.format("%n%n"));
return message;
}
// Equivalent to
// "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup.sortAutoConfigurations"
@SuppressWarnings("unchecked")
private List<String> sort(List<String> configs) throws Exception {
Class<?> clazz = ClassUtils.resolveClassName(SORTER_CLASS,
AutoConfigurationOrderLoggingListener.class.getClassLoader());
Method method = ReflectionUtils.findMethod(clazz, "getInPriorityOrder", Collection.class);
ReflectionUtils.makeAccessible(method);
Constructor<?> constructor = ReflectionUtils.accessibleConstructor(clazz, MetadataReaderFactory.class,
AutoConfigurationMetadata.class);
Object[] args = new Object[] { getMetadataReaderFactory(), getAutoConfigurationMetadata() };
Object sorter = BeanUtils.instantiateClass(constructor, args);
List<String> sorted = (List<String>) ReflectionUtils.invokeMethod(method, sorter, configs);
return sorted;
}
// Equivalent to
// "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup.getMetadataReaderFactory"
private MetadataReaderFactory getMetadataReaderFactory() {
String beanName = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory";
try {
return this.beanFactory.getBean(beanName, MetadataReaderFactory.class);
}
catch (NoSuchBeanDefinitionException ex) {
return new CachingMetadataReaderFactory(this.resourceLoader);
}
}
// Equivalent to
// "org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup.getAutoConfigurationMetadata"
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
String loaderClass = "org.springframework.boot.autoconfigure.AutoConfigurationMetadataLoader";
Class<?> clazz = ClassUtils.resolveClassName(loaderClass,
AutoConfigurationOrderLoggingListener.class.getClassLoader());
Method method = ReflectionUtils.findMethod(clazz, "loadMetadata", ClassLoader.class);
ReflectionUtils.makeAccessible(method);
AutoConfigurationMetadata metadata = (AutoConfigurationMetadata) ReflectionUtils.invokeMethod(method, null,
AutoConfigurationOrderLoggingListener.class.getClassLoader());
return metadata;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
spring.factories:
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
com.example.AutoConfigurationOrderLoggingListener
comment created time in 24 days
issue commentspring-projects/spring-boot
Investigate shutdown delay option
We have an operational scenario that directly open a shell on the pod and restart the application. This allows faster restart of the app since it doesn't involve k8s pod lifecycle.
In such case, k8s does not know the application is restarting and it still send traffic to the pod during shutdown. So, in our graceful shutdown logic(in addition to the one from boot 2.3), we put a sleep for the duration of readiness check frequency, to make sure k8s readiness check picks up that the app is about to restarting and stop routing the traffic before actual shutdown happens.
If Spring Boot provides sleep(delay) on its graceful shutdown logic, I can remove our sleep logic from our library, which is great.
comment created time in 24 days
issue openedspring-projects/spring-security
Make "SECURITY_CONTEXT_ATTRIBUTES" key in subscriber context publicly accessible
We use WebClient in servlet environment.
Some of our ExchangeFilterFunction requires current authentication object as well as values associated to the http request.
Previously, with RestTemplate, we used ThreadLocal to hold and retrieve request bounded values.(RequestContextHolder, SecurityContextHolder, etc.)
With WebClient, Spring Security's SecurityReactorContextSubscriber in SecurityReactorContextConfiguration exposes auth, servlet request, and servlet response in a Map(called ContextAttributes) to the subscriber context.
In our custom filter functions, we leverage this context-attributes-map to retrieve auth and request bounded values similar to what ServletBearerExchangeFilterFunction does.
Currently, to access this context-attributes-map, the key SECURITY_CONTEXT_ATTRIBUTES is defined as package private in SecurityReactorContextConfiguration.
static final String SECURITY_CONTEXT_ATTRIBUTES = "org.springframework.security.SECURITY_CONTEXT_ATTRIBUTES";
Even within Spring Security, ServletBearerExchangeFilterFunction(oauth2-resource-server module) and ServletOAuth2AuthorizedClientExchangeFilterFunction(oauth2-client module) which define same String constant key in order to access this context-attributes-map.
This is probably due to the SECURITY_CONTEXT_ATTRIBUTES constant is defined in SecurityReactorContextConfiguration(config module) which is a downstream module(and class is package private).
So, to allow context-attributes-map being used not only by oauth2-[resource-server|client] modules, but also user library/application, can this SECURITY_CONTEXT_ATTRIBUTES constant (and maybe mechanism around) be exposed to somewhere in upstream module public class?
Also, the context-attributes-map can be an independent class instead of generic Map to enhance accessibility of stored objects.
Ideally, I think this infrastructure(subscriber, lifter, context-attributes-map) is available in Spring Framework; then, Spring Security adds a logic to populate SecurityContext on it. (https://github.com/spring-projects/spring-framework/issues/25710)
created time in 24 days
issue openedspring-projects/spring-framework
Mechanism to access request bound objects in WebClient filter in servlet env
In servlet environment, when migrating RestTemplate to WebClient, one of the challenges people face is to access http request bound objects within WebClient filters(ExchangeFilterFunction).
I think this is an area currently lacking a support.
For example, SecurityContext, Locale/LocaleContext(LocaleContextHolder), HttpServletRequest(RequestContextHolder) and any values associated to the request(ThreadLocal) cannot easily be retrieved in ExchangeFilterFunction.
I think common solution for this is to use Hooks to populate the values to subscriber's context.
For example, in Spring Security, here defines and registers a hook that populates SecurityContext.
Since this mechanism also populates HttpServletRequest and HttpServletResponse, I leverage it in my exchange filter functions to retrieve request bound values.
I also have similar logic for MDC and LocaleContext.
I think this mechanism should be supported in Spring Framework itself; so that, all downstream libraries and application can leverage it.
For implementation perspective, for example, define a class ReactorContextAttribute which is a map kept in thread local. Then, framework guarantees to populate this map in subscriber's context. So that, users or downstream libraries can simply populate this map in request thread, then retrieves values from the map in subscriber context.
In addition, FrameworkServlet/DispatcherServlet resolved value/context, such as LocaleContext, can be placed in this map to make them accessible in exchange filter functions.
If such mechanism exists, for example, Spring Security can simply add a logic to populate SecurityContext.
I think this is a big missing piece to use WebClient in servlet environment along with supporting MDC.
created time in 24 days
issue openedspring-projects/spring-framework
Inconsistent log level in @Bean javadoc and ConfigurationClassEnhancer
@Bean javadoc states when BFPP is defined with non-static method, it writes a WARN-level log message.
This works out in BFPP cases, as they are not typically referenced by other @Bean methods. As a reminder, a WARN-level log message will be issued for any non-static @Bean methods having a return type assignable to BeanFactoryPostProcessor
The commit 9a43d2ec208d2e8cd0866431acf26af3529f8677 (SPR-16946, #21485) updated the logging level in ConfigurationClassEnhancer and this message shows up as INFO log.
if (logger.isInfoEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
So, either javadoc or log level need to be updated to match actual description and behavior.
created time in a month
issue openedspring-projects/spring-boot
Different bean resolution in @ConditionalOn*Bean vs autowiring
One of the application team reported an issue and I found this slightly unintuitive behavior between condition evaluation of @ConditionalOn*Bean and spring's autowiring resolution for method argument.
Sample Code:
public class AnotherApplication {
public static void main(String[] args) {
SpringApplication.run(Config.class, "--debug");
}
@SpringBootConfiguration(proxyBeanMethods = false)
static class Config {
@Bean
Parent foo() {
return new Child("FOO");
}
@Bean
Child bar() {
return new Child("BAR");
}
// @Bean
// Parent baz() {
// return new Child("BAZ");
// }
@Bean
@ConditionalOnSingleCandidate(Child.class) // <<<--
InitializingBean init(Child child) { // <<<--
return () -> {
System.out.println("initialized");
};
}
}
static class Parent {
String name;
public Parent(String name) {
this.name = name;
}
}
static class Child extends Parent {
public Child(String name) {
super(name);
}
}
}
Condition evaluation report:
Positive matches:
-----------------
AnotherApplication.Config#init matched:
- @ConditionalOnSingleCandidate (types: com.example.AnotherApplication$Child; SearchStrategy: all) found a primary bean from beans 'bar' (OnBeanCondition)
Failure:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method init in com.example.AnotherApplication$Config required a single bean, but 2 were found:
- foo: defined by method 'foo' in com.example.AnotherApplication$Config
- bar: defined by method 'bar' in com.example.AnotherApplication$Config
Analysis
While performing OnBeanCondition(@ConditionalOnSingleCandidate), it compares the target type(Child) against factory-method-return-type of each @Bean - Parent for bean foo and Child for bar.
Therefore, Child matches to bar bean and satisfies the condition.
The details of this process is, in OnBeanCondition, it calls beanFactory.getBeanNamesForType to collect bean names for the specified type(Child). In that, it calls AbstractBeanFactory#getSingleton. At this time, spring did not create raw beans yet, thus, the beanInstance becomes null. Then, it goes to check the bean definition's factoryMethodReturnType against specified condition type Child.
On the other hand, when spring performs autowiring for method arguments, it also calls
beanFactory.getBeanNamesForType. At this time, raw beans are available, and it finds the actual bean instances. Then, it proceeds to perform instanceof check against the method argument type Child.
This instanceof matches to both foo(Parent) and bar(Child) beans. Therefore, it detects two beans and fails to resolve which one to apply for the method argument.
There is another not intuitive behavior.
In following situation, it will not match the condition because the return type of foo is Parent.
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
Parent foo() {
return new Child("FOO");
}
@Bean
@ConditionalOnBean(Child.class)
InitializingBean init(Child child) {
...
}
}
Negative matches:
-----------------
AnotherApplication.Config#init:
Did not match:
- @ConditionalOnBean (types: com.example.AnotherApplication$Child; SearchStrategy: all) did not find any beans of type com.example.AnotherApplication$Child (OnBeanCondition)
However, once I add Child bar() bean, suddenly the condition matches but autoconfiguration for Child fails with finding two beans - foo and bar.
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
Parent foo() {
return new Child("FOO");
}
@Bean
Child bar() {
return new Child("BAR");
}
@Bean
@ConditionalOnBean(Child.class)
InitializingBean init(Child child) {
...
}
}
Positive matches:
-----------------
AnotherApplication.Config#init matched:
- @ConditionalOnBean (types: com.example.AnotherApplication$Child; SearchStrategy: all) found bean 'bar' (OnBeanCondition)
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method init in com.example.AnotherApplication$Config required a single bean, but 2 were found:
- foo: defined by method 'foo' in com.example.AnotherApplication$Config
- bar: defined by method 'bar' in com.example.AnotherApplication$Config
This suddenly matching multiple beans issue has reported in our application and I found this behavior.
I understand this is possibly working as designed.
The difference is due to the behavior of beanfactory.getBeanNamesForType which changes slightly different based on the stage this method is called. And also due to that bean instances cannot be checked while processing conditions.
It might be a corner case, but may be good to document such behavior on @ConditonalOn*Bean annotations.
created time in 2 months
pull request commentpgjdbc/r2dbc-postgresql
FYI, If you want to log bindings and query all together(also connection id), r2dbc-proxy provides such capability. Here is sample log. (It is multilined for display purpose but actual logging is single line, and configurable to own format)
comment created time in 2 months
push eventttddyy/spring-boot
commit sha ac651442fa82817a13654208328c3e45188fa305
Add support for selecting the Redis client to use See gh-22569
commit sha 589669d0cc49f05381cdf947e69804aa4d720a0d
Polish "Add support for selecting the Redis client to use" See gh-22569
commit sha 0bc5b20d561b44c6d89ac2f2e4826e9db985f3a0
Merge pull request #22569 from bono007 * pr/22569: Polish "Add support for selecting the Redis client to use" Add support for selecting the Redis client to use Closes gh-22569
commit sha 5352ec1cbaa36b14da031da1b5a42f86d79aa370
Support configuration of entityId for a SAML Relying Party See gh-22258
commit sha 621f0264990d36f30cee6149eb2e6a1f43b302ab
Polish "Support configuration of entityId for a SAML Relying Party" See gh-22258
commit sha b476bf82d8877e3b0b56f48f7ce7c48b94d57fb2
Merge pull request #22258 from danilopiazza * pr/22258: Polish "Support configuration of entityId for a SAML Relying Party" Support configuration of entityId for a SAML Relying Party Closes gh-22258
commit sha 2238b0d797be0fe55710f168cdde47cf2eca0dea
Try to make FileSystemWatcherTests.waitsForQuietPeriod() more robust Previously, waitsForQuietPeriod would iterate 10 times, touching a new file and then sleeping for 100ms at it did so. With a quiet period of 200ms, this was intended to result in a single change set containing 10 files. However, the test would fail occasionally as multiple change sets were detected. The test is multi-threaded and is, therefore, at the mercy of the scheduler. If the thread that is iterating and touching the files takes over 200ms to be scheduled – exceeding the watcher's quiet period – the watcher may detect a change set while the changes are still being made. Eliminating this possibilty would require the test to participate in the watcher's synchronization, which would require some changes to its implementation. Instead, this commit aims to avoid the problem by sleeping for 1/10 of the time (10ms) and expecting a single change set of 100 files. The hope is that the much shorter sleep time will result in the file touching thread being scheduled well within the 200ms quiet period. Closes gh-22732
commit sha 94644f381466d3e06cb7ea4cf2175f593bab201d
Merge branch '2.2.x' into 2.3.x Closes gh-22737
commit sha 7df49187fa4f5f469bb8785caceebadacbec53ed
Merge branch '2.3.x' Closes gh-22738
commit sha ae152b176ba0050aecfea724750f060eaf473f6b
Add test slice for Spring Data Cassandra See gh-17490
commit sha 313b2bef6fa396c16635914e1021f0af3418ee2c
Polish "Add test slice for Spring Data Cassandra" See gh-17490
commit sha b51e612c39c68b5940fe80053f9469a047c13bed
Merge pull request #17490 from ayudovin * pr/17490: Polish "Add test slice for Spring Data Cassandra" Add test slice for Spring Data Cassandra Closes gh-17490
commit sha 1017774ed59c9835a079475df62f8b3edde1d0e9
Polish See gh-22740
commit sha cccf9c24e21e8788cbed54334e6db383df599134
Merge pull request #22740 from izeye * pr/22740: Polish Closes gh-22740
commit sha 516582f6d323dd39648dd9bda5b8c600a15c30a5
Merge branch '2.3.x' Closes gh-22744
commit sha 71ffb44a3c6d2043cc491bb576518116015c5744
Remove WebClient's in-memory buffer size limit for endpoint tests Previously, the endpoints' responses could occasionally exceed WebClient's in-memory buffer limt, for example if the threads endpoint was reporting a large number of threads or the threads had large stacks. This commit disables WebClient's in-memory buffer size limit so that the tests passing is not dependent on the size of the endpoints' responses. Closes gh-22743
commit sha c40835eba0935d5ed11df31cf6bbee6313f8e396
Merge branch '2.2.x' into 2.3.x Closes gh-22746
commit sha 0e83b2f4c4fee7b3843c2b175e7a3402894e3b92
Merge branch '2.3.x' Closes gh-22747
commit sha bfe250e5d33aafe384604f01f7823ce8265e6a84
Clarify docs on schema and data SQL scripts with Flyway and Liquibase Closes gh-20920
commit sha a160755da51b56be981d5d1f39ab70372092b766
Merge branch '2.2.x' into 2.3.x Closes gh-22748
push time in 2 months
delete branch ttddyy/spring-framework
delete branch : 24634_order-detected-ex-translator
delete time in 2 months
PR opened spring-projects/spring-framework
By definition, this method should not return null.
pr created time in 2 months
issue commentr2dbc/r2dbc-spi
Add a method to unwrap to the specified class from nested wrapped object
The usecase for me is more on testing side at the moment.
When ConnectionFactory is created automatic(dynamic) fashion (e.g: spring-boot auto configuration), caller may not know how many times it is wrapped. So, need to introspect(unwrap) each of the object until it finds what it is looking for.
This, in turn, same for users who need to use implementation specific feature(one that is not available in SPI). The logic may not know how the object is constructed, so need to loop through the unwrapping.
The proposed API would not matter unwrapping type is either same as wrapping type or can be even different(not sure it's realistic or not though).
comment created time in 2 months
issue openedr2dbc/r2dbc-spi
Add a method to unwrap to the specified class from nested wrapped object
Currently Wrapped#unwrap retrieves the holding original object on the instance.
If an object is wrapped multiple times, then the caller needs to iterate through the target to find the one that is looking for to be unwrapped.
For example, if an object ConnectionFactory is wrapped as proxy -> pool -> H2 ConnectionFactory, caller needs to unwrap twice to get the original H2 connection-factory.
Similar to Wrapper#unwrap(Class) in JDBC, it is helpful for users to directly return unwrapping target object if it is available from wrapped object, or returns null.
This can be implemented in default method on the Wrapped interface.(Or static method) So that, each implementation does not need to handle the call.
Here is a sample implementation with default method to find the first (outer most) wrapped object that matches to the given class.
@Nullable
@SuppressWarnings("unchecked")
default <E> E unwrapTo(Class<E> targetClass) {
Assert.requireNonNull(targetClass, "targetClass must not be null");
Object target = this;
while (true) {
if (targetClass.isInstance(target)) {
return (E) target;
}
if (!(target instanceof Wrapped)) {
return null;
}
target = ((Wrapped<?>) target).unwrap();
}
}
We can have more generic one with Predicate:
@Nullable
default <E> E unwrapTo(Class<E> targetClass) {
return unwrapTo(targetClass::isInstance);
}
@Nullable
@SuppressWarnings("unchecked")
default <E> E unwrapTo(Predicate<Object> predicate) {
....
}
For boolean check (if we want), we could reuse above like:
default boolean isWrapping(Class<?> targetClass) {
return unwrapTo(targetClass) != null;
}
created time in 2 months
push eventttddyy/spring-boot
commit sha 630cbae7d7d6b7d9a5d672a793e1a1f807cf0b36
Document properties to enable probe health indicators Document property names to enable probe(readiness/liveness) health indicators. See gh-22631
commit sha 35093aacf4f45aa9eb29d2afb536d2103442ed6a
Polish "Document properties to enable probe health indicators" See gh-22631
commit sha 4aa010c874beb53df58b018aeea71e5b00829c25
Merge pull request #22631 from ttddyy * gh-22631: Polish "Document properties to enable probe health indicators" Document properties to enable probe health indicators Closes gh-22631
commit sha e6957ec8c4a8ffc5c8945cc12714674307363e02
Merge branch '2.3.x' Closes gh-22697
commit sha 8dedeb4c6a66bf518a455bf1331ebdb9a94bda19
Fix missing liveness and readiness indicators Prior to this commit, the livenessState and readinessState health indicators would not be configured automatically and would be missing from the "liveness" and "readiness" health groups, leading to 404s when hitting the `/actuator/health/liveness` or `/actuator/health/readiness`. This commit ensures that the health indicators beans have the proper name and revisits the auto-configuration conditions to reflect that as well. Fixes gh-22562
commit sha 6efff7b5854aede81f43129ab3f93582c4052397
Merge branch '2.3.x' Closes gh-22698
commit sha 2bdeba8aaa23f925982897b426328cf55df86fbc
Fix NPE in BeanDefinitionLoader when XML support is disabled See gh-22696
commit sha 11a296b0684df5caa9e5c0ce91fafb7a3a4efb24
Polish "Fix NPE in BeanDefinitionLoader when XML support is disabled" See gh-22696
commit sha 86e34dc4a70797f78da1697ad00cc32fcabe06a0
Merge pull request #22696 from dreis2211 * gh-22696: Polish "Fix NPE in BeanDefinitionLoader when XML support is disabled" Fix NPE in BeanDefinitionLoader when XML support is disabled Closes gh-22696
commit sha 989fc365282659854df10529847a1dbf9c83d775
Polish
commit sha 1168d8fa742ce432536a983b4159c5c79b1e0beb
Reduce reflection in LoggingSystem to make it more Graal-friendly Closes gh-22594
commit sha bd2874de497846f6d786d9f4896994d014b7ef9f
Fix broken links to Micrometer registry docs See gh-22704
commit sha bc020d95b6eeeee3a186a11a417df2e63b795918
Merge pull request #22704 from izeye * pr/22704: Fix broken links to Micrometer registry docs Closes gh-22704
commit sha 4082cddce24bd6e60136f584d22f956a83c1afc7
Merge branch '2.1.x' into 2.2.x Closes gh-22705
commit sha 13f1d00048a7602a60b6b685e2d7150481311600
Merge branch '2.2.x' into 2.3.x Closes gh-22706
commit sha bb3066f61af75442ee1b5546faf1ef6f64cfb621
Merge branch '2.3.x' Closes gh-22707
commit sha e49e2dfff111c90e2a710749c6a32fef56327615
Use Supplier variants of Assert methods See gh-22699
commit sha e18198237b508dd8c0bb466ed4eb7f756393e478
Merge pull request #22699 from dreis2211 * pr/22699: Use Supplier variants of Assert methods Closes gh-22699
commit sha a334134fd0ee72838be265ad48f22ff0cf402ff4
Make Slack build failure notifications more noticeable Closes gh-22709
commit sha 992deb4647db308d91a55aa8d80aef7651af786b
Merge branch '2.2.x' into 2.3.x Closes gh-22711
push time in 2 months
pull request commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
@snicoll While writing tests, I found using Option has a problem wrapping ConnectionPool with proxy. This is because @Bean method for ConnectionPool wraps the result of createConnectionFactory(). Therefore, proxy cannot wrap the ConnectionPool.
So, I fallback to the original plan to make a hook on createConnectionFactory() to post process configured ConnectionFactory. (which I also applied to creating ConnectionPool)
comment created time in 2 months
push eventttddyy/spring-boot
commit sha a8e6c53c84024e27c403c08891348b8bf7ea225c
Remove version management for exec-maven plugin See gh-22397
commit sha 8a450c790642e2e1ede4eb931b357c8ea05dab4a
Merge pull request #22397 from dreis2211 * pr/22397: Remove version management for exec-maven plugin Closes gh-22397
commit sha 85828953bd82ce2e0f1a61847338a1bc32e41241
Perform enablement checks once in BackgroundPreinitializer Closes gh-22406
commit sha 66bf684eb6d8d83266fc266648bb157ca19d4b68
Ignore BackgroundPreinitializer in native images BackgroundPreinitializer is not relevant in native images so it is better to ignore it automatically in order to reduce the footprint in such environment. See gh-22392
commit sha 137ce1a9de6087f26357a6829fa6864b948b641a
Merge pull request #22392 from sdeleuze * gh-22392: Ignore BackgroundPreinitializer in native images Closes gh-22392
commit sha 179d2c79d6d76cf7f77185e331839da01aee27cf
Avoid trivialising what the reader's learning about Closes gh-22408
commit sha 21f733b89bdc80d5ed642ab48b07d19531218055
Merge branch '2.1.x' into 2.2.x Closes gh-22409
commit sha accc1f1ca81dc8bd05b5da2b0848b37c371cb69b
Merge branch '2.2.x' into 2.3.x Closes gh-22410
commit sha 19ad163486f39ba7d8f05896c0a52ca7912f1bd9
Merge branch '2.3.x' Closes gh-22411
commit sha 5795caea81ef5d65100406ac0b8a187ed6545087
Reinstate jetty-jndi exclusion in spring-boot-starter-jetty Fixes gh-22241
commit sha e4b065bdd9f0a0ecd8cd890fc45f8333d5f3471c
Merge branch '2.3.x' Closes gh-22419
commit sha 0fd567664af5df590dc35d6433bc22911007f6e0
Make DefaultErrorAttributes easier to subclass for message customization Closes gh-22378
commit sha c90dc87b0b4dc83b10c0fafd061d69da19d063f8
Upgrade to Couchbase Client 2.7.16 Closes gh-22420
commit sha 43fd27bb71628321b4233f86db231c9052c0ae72
Upgrade to Jackson 2.9.10.20200621 Closes gh-22421
commit sha c166b5b23e65f4fc1e8e66b26706aeadaf7b81f8
Upgrade to Appengine Sdk 1.9.81 Closes gh-22422
commit sha dd9c9fa7be69a376accbf0ae5d1cd647f1c27100
Upgrade to Micrometer 1.1.15 Closes gh-22423
commit sha 83ca02f16da88186c2c206bc78b28d7bb39d427d
Upgrade to Netty 4.1.51.Final Closes gh-22424
commit sha 775231e3e908459ac2f6406bbec522725a8aa78f
Upgrade to Mysql 8.0.21 Closes gh-22425
commit sha 1113d5cc23431f6188a0774c55236cfdba720b71
Upgrade to Activemq 5.15.13 Closes gh-22426
commit sha 50b05ac6522bff8bca506049cfaca57869518c34
Upgrade to Tomcat 9.0.37 Closes gh-22427
push time in 2 months
pull request commentspring-projects/spring-boot
Document properties to enable probe health indicators
I was working on readiness/liveness, so I was only looking them especially they are not enabled by default. But it is even better if all properties are documented on the table there. It is easy for readers to have information there how to enable healthindicators (though other than readiness/liveness are enabled by default). I don't think it is easy for readers to realize there is an appendices that have all properties listed for actuator unless there is an explicit link in the section.
comment created time in 2 months
issue commentspring-projects/spring-boot
Add logging when health groups endpoints(readiness/liveness) return unhealthy response
@wilkinsona Thanks for the pointer.
The logging on the code above only happen when the actual health check logic throws an exception.
Some of the healthcheck implementation throws Exception and let here to set DOWN status, but some are constructing response health status in the logic without throwing exception.
The intention for my case is when health check(aggregated) returns non UP state(DOWN, OUT_OF_SERVICE, UNKNOWN), then perform logging.
This is because the response of liveness health group(/actuator/health/liveness) will trigger the restart of the application. When it happens, I would like to come back to see application log and find out which health indicator returned non-UP status as well as details if available.
comment created time in 2 months
issue commentspring-projects/spring-boot
Kubernetes readiness probe endpoint returning 404 on Spring Boot 2.3.2
Instead of referencing readinessStateProbeIndicator and livenessStateProbeIndicator, I think you need to set management.health.livenessstate.enabled and management.health.readinessstate.enabled properties introduced by spring-boot 2.3.2. So that, you could use readinessState and livenessState reference.
When management.health.[readiness|livenessstate].enabled properties are set to false(by default), AvailabilityProbesAutoConfiguration creates readinessStateProbeIndicator and livenessStateProbeIndicator beans which need to be referenced as [readiness|liveness]StateProbeIndicator(full bean name).
On the other hand, when properties are enabled, AvailabilityHealthContributorAutoConfiguration creates [readiness|liveness]StateHealthIndicator beans which can be referenced as [readiness|liveness]State.
The problem is in AvailabilityProbesHealthEndpointGroups created by AvailabilityProbesHealthEndpointGroupsPostProcessor, this creates readiness/liveness groups with [readiness|liveness]State.
So, if [readiness|liveness]State are not available, groups are created but referenced HealthIndicator beans are not there.
comment created time in 2 months
issue openedspring-projects/spring-boot
Add logging when health groups endpoints(readiness/liveness) return unhealthy response
This is similar to #22509 to improve root cause analysis when probe endpoints returned non 200 response.
I am migrating k8s http probes to use readiness and liveness health group endpoints(/actuator/health/[readiness|liveness]).
When these endpoints return non UP status(other than 200 response), k8s stops traffic or shutdown the pod. When such event happens, k8s http probe only record the returned http status for the reason of its probe failure.
This makes hard to investigate WHY readiness/liveness probes returned non 200 response when somebody needs to investigate the failure reason later. Even if k8s could record body of probe response, it would be nicer to have such information in application log.
I wrote this implementation to our services to log information when health endpoints returns non UP response.
@Slf4j
public class LoggingHealthEndpointWebExtension extends HealthEndpointWebExtension {
public LoggingHealthEndpointWebExtension(HealthContributorRegistry registry, HealthEndpointGroups groups) {
super(registry, groups);
}
@Override
public WebEndpointResponse<HealthComponent> health(ApiVersion apiVersion, SecurityContext securityContext,
boolean showAll, String... path) {
WebEndpointResponse<HealthComponent> response = super.health(apiVersion, securityContext, showAll, path);
HealthComponent health = response.getBody();
if (health == null) {
return response;
}
Status status = health.getStatus();
if (status != Status.UP) {
Map<String, HealthComponent> components = new TreeMap<>();
if (health instanceof CompositeHealth) {
Map<String, HealthComponent> details = ((CompositeHealth) health).getComponents();
if (details != null) {
components.putAll(details);
}
}
log.warn("Health endpoints {} returned {}. components={}", path, status, components);
}
return response;
}
}
If HealthEndpointSupport could have logging capability (or HealthEndpointWebExtension and ReactiveHealthEndpointWebExtension for web only), then we don't need to have this custom implementation.
Something like:
boolean enableLogging;
if(this.enableLogging && health.getStatus() != Status.UP) {
log.warn(...);
}
created time in 2 months
PR opened spring-projects/spring-boot
Document property names to enable probe(readiness/liveness) health indicators.
<!-- Thanks for contributing to Spring Boot. Please review the following notes before submitting you pull request.
Please submit only genuine pull-requests. Do not use this repository as a GitHub playground.
Security Vulnerabilities
STOP! If your contribution fixes a security vulnerability, please do not submit it. Instead, please head over to https://pivotal.io/security to learn how to disclose a vulnerability responsibly.
Dependency Upgrades
Please do not open a pull request for a straightforward dependency upgrade (one that only updates the version property). We have a semi-automated process for such upgrades that we prefer to use. However, if the upgrade is more involved (such as requiring changes for removed or deprecated API) your pull request is most welcome.
Describing Your Changes
If, having reviewed the notes above, you're ready to submit your pull request, please provide a brief description of the proposed changes. If they fix a bug, please describe the broken behaviour and how the changes fix it. If they make an enhancement, please describe the new functionality and why you believe it's useful. If your pull request relates to any existing issues, please reference them by using the issue number prefixed with #. -->
pr created time in 2 months
PR opened spring-projects/spring-boot
Prior to this change, TaskExecutorBuilder used second as its precision to
map awaitTerminationPeriod value. This caused a loss of millisecond information
in the period.
This commit fixes the loss by converting the period to millisecond and use the
setAwaitTerminationMillis on executor/scheduler.
<!-- Thanks for contributing to Spring Boot. Please review the following notes before submitting you pull request.
Please submit only genuine pull-requests. Do not use this repository as a GitHub playground.
Security Vulnerabilities
STOP! If your contribution fixes a security vulnerability, please do not submit it. Instead, please head over to https://pivotal.io/security to learn how to disclose a vulnerability responsibly.
Dependency Upgrades
Please do not open a pull request for a straightforward dependency upgrade (one that only updates the version property). We have a semi-automated process for such upgrades that we prefer to use. However, if the upgrade is more involved (such as requiring changes for removed or deprecated API) your pull request is most welcome.
Describing Your Changes
If, having reviewed the notes above, you're ready to submit your pull request, please provide a brief description of the proposed changes. If they fix a bug, please describe the broken behaviour and how the changes fix it. If they make an enhancement, please describe the new functionality and why you believe it's useful. If your pull request relates to any existing issues, please reference them by using the issue number prefixed with #. -->
pr created time in 2 months
pull request commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
@ttddyy I can see a WIP in your last update and the tests have been commented out. Do you need something from us? Thanks a lot for your effort.
@snicoll Thanks for checking. I wanted to check whether the current impl with customizer is ok before I proceed. And since you said ok, I'll finish up the rest of the PR.
comment created time in 2 months
issue openedspring-projects/spring-boot
Add logging for availability state change
Changing availability state(readiness/liveness/etc.) is significant events for application. Currently, there is no logging around the availability state change and this makes it hard to find out what caused the state to change when somebody needs to look back what has happened to the application. So, we would like to capture the state change event in application log.
The caller(event publisher) side can log the event but it is more enforced if ApplicationAvailabilityBean(receiver side) logs the event.
For now, state change logging can be achieved by implementing a custom ApplicationListener like followings.
@Slf4j
@Order(0) // make sure this listener run before "ApplicationAvailabilityBean"
class AvailabilityStateChangeLoggingListener implements ApplicationListener<AvailabilityChangeEvent<?>> {
private final ApplicationAvailability availability;
public AvailabilityStateChangeLoggingListener(ApplicationAvailability availability) {
this.availability = availability;
}
@Override
public void onApplicationEvent(AvailabilityChangeEvent<?> event) {
AvailabilityState newState = event.getState();
AvailabilityState lastState = this.availability.getState(newState.getClass());
if (lastState != null && newState != lastState) {
Class<? extends AvailabilityState> stateType = getStateType(newState);
log.info("AvailabilityState changed. type={}, new={}, last={}, source={}",
stateType.getSimpleName(), newState, lastState, event.getSource().getClass().getSimpleName());
}
}
@SuppressWarnings("unchecked")
private Class<? extends AvailabilityState> getStateType(AvailabilityState state) {
if (state instanceof Enum) {
return (Class<? extends AvailabilityState>) ((Enum<?>) state).getDeclaringClass();
}
return state.getClass();
}
}
But the caveat is this needs to implement @Order/Ordered to ensure the listener ordering correct to retrieve the last state.
If ApplicationAvailabilityBean logs state change, this custom listener is not needed.
created time in 2 months
push eventttddyy/spring-boot
commit sha 48cf578baea0fc2583e7f4fa47e68e67e500da3d
WIP: Add autoconfiguration for r2dbc-proxy Add autoconfiguration for r2dbc-proxy. Create a proxy of `ConnectionFactory` when: - r2dbc-proxy is in classpath - property is enabled (enabled by default) - r2dbc-proxy listener beans are defined
push time in 2 months
push eventttddyy/spring-boot
commit sha 4d37430bfe33ba45c0fa3eccf226c4c833babf58
Use servlet context that can access classloader Update `SpringBootServletInitializer` to use the `ServletContext` that was provided to the initial `onStartup` call rather than the one from the `ServletContextEvent`. This allows the `getClassLoader()` call to complete without throwing an `UnsupportedOperationException`. Fixes gh-21684
commit sha 16cab0d83c80a7978bd3bef2894e3ddec466d1ed
Merge branch '2.3.x' Closes gh-21690
commit sha c0f748e1436cd44af3a79d2d9953665bf060a3bf
Always apply retry plugin but only retry on CI Previously, the retry plugin was only applied on CI as we do not want tests to be retried in local builds. Unfortunately, this arrangement led to test tasks from CI builds having additional doFirst and doLast actions and an additional property. These differences meant that the output from a test task that has run on CI could not be used by a local build. This commit changes our configuration of the test retry plugin so that it is now always applied. To retain the behaviour of only retrying tests on CI, max retries is configured to 3 on CI and 0 for local builds. Closes gh-21698
commit sha 15ec26171c2b1ca073aafeba6ac6c3a54242b921
Merge branch '2.3.x' Closes gh-21699
commit sha 24138c104cc95ecf7c469c6fccb205902058c73c
Use highlightjs for syntax highlighting in Asciidoctor's HTML output Closes gh-21701
commit sha c4faeac4d7b62482b85281c9c4b71e9d610af230
Merge branch '2.3.x' Closes gh-21703
commit sha b6474f2ca1aefdae7bc55aaa64bb3ebaaf127a96
Remove accidentally committed hook file
commit sha 4a0d37267586af4193271bfae82ff192e6183433
Merge branch '2.2.x' into 2.3.x
commit sha c666f0ff05355613761b2ee1d7b80c6ec93b0893
Merge branch '2.3.x'
commit sha 4a6e08c8179e945560282c47300d15020ff7810f
Add logging to forward-merge script Add some logging to aid with development.
commit sha 39caf45155eb76ff5e986d08774772915a52aa28
Allow forward merge to work with .x patterns Closes gh-21687
commit sha ba53d10060a6395e2f6b299eba6f985ddc14564b
Merge branch '2.2.x' into 2.3.x Closes gh-21706
commit sha 87a155410b22edd351928849ce7c44b901f73ef9
Merge branch '2.3.x' Closes gh-21707
commit sha 10fdd6506310ea0255bf8e05cf422f0dd4ef0ea4
Add prepare-forward-merge script Add a git hook script that can be used to prepare a sensible merge commit message. Closes gh-21688
commit sha 7561123cd926332a44c891a15dfce37186390240
Merge branch '2.2.x' into 2.3.x Closes gh-21709
commit sha 2fe299f6d0ddbc8e7891422c8c79d50ef538d1a3
Merge branch '2.3.x' Closes gh-21710
commit sha 54f93e9b0f6517d0d7e306942dacd7d0ef855a90
Fix multi-release JAR test on JDK 15 See gh-21605
commit sha 78165c619dc215d7ec82f28a9e6fe01b293f71a0
Merge pull request #21605 from dreis2211 * pr/21605: Fix multi-release JAR test on JDK 15 Closes gh-21605
commit sha 20f0b41099d080cda1606a0e8629bd1ac11a075b
Upgrade CI to Docker 19.03.9 Closes gh-21681
commit sha 97533a53648087ff867c4fd7e2e7000fd1ada0f1
Merge branch '2.1.x' into 2.2.x Closes gh-21682
push time in 2 months
pull request commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
After discussing with @snicoll we found that ordering of pool/proxy/driver wrapping matters (speaking in URL syntax,
r2dbc:pool:proxy:h2vs.r2dbc:proxy:pool:h2) if someone wants to e.g. measure how many real connections were created/closed by the pool vs. how long a connection is in use by the application.
Yes, the ordering matters, and it can be even r2dbc:proxy:pool:proxy:h2.(though, there is a problem specifying listeners for which proxy to apply since there is only one proxyListener option)
I consider most of the case proxy is the outer most wrapper since you want to check the Application behavior.
If a user wants to proxy the middle ConnectionFactory, the user needs to wrap it manually, but I think that is more advanced use case.
For connection-pool in Spring Boot, it may provide a flag in connection-pool settings which would be specific to proxying the connection-pool with some canned proxy listener such as metrics.
comment created time in 2 months
Pull request review commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
ConnectionPool connectionFactory(R2dbcProperties properties, ResourceLoader reso @Bean ConnectionFactory connectionFactory(R2dbcProperties properties, ResourceLoader resourceLoader,- ObjectProvider<ConnectionFactoryOptionsBuilderCustomizer> customizers) {+ ObjectProvider<ConnectionFactoryOptionsBuilderCustomizer> customizers,+ ObjectProvider<ProxyListenersProvider> proxyListenersProviders) { return createConnectionFactory(properties, resourceLoader.getClassLoader(),- customizers.orderedStream().collect(Collectors.toList()));+ customizers.orderedStream().collect(Collectors.toList()),+ proxyListenersProviders.getIfAvailable(() -> ProxyListenersProvider.EMPTY)); } } + @Configuration(proxyBeanMethods = false)+ @ConditionalOnClass(ProxyConnectionFactory.class)+ @ConditionalOnProperty(prefix = "spring.r2dbc.proxy", value = "enabled", havingValue = "true",+ matchIfMissing = true)+ static class Proxy {
Currently, ConnectionFactoryOptionsBuilderCustomizer provides a way to customize Options on ConnectionFactoryBuilder. So, I could use it as a hook point to add/replace some of the Options.
I wasn't sure it is ok to use customizer facility within Spring Boot, but if that's ok, then here can define a customizer bean (probably with @Order to allow users to run own customizers before and after). Then, it will be pretty much all we need for r2dbc-proxy.
comment created time in 2 months
Pull request review commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
package org.springframework.boot.autoconfigure.r2dbc; +import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; +import io.r2dbc.proxy.ProxyConnectionFactoryProvider;+import io.r2dbc.proxy.listener.ProxyExecutionListener;
ok, I made not to throw NoClassDefFoundError but I'll go some other way not to use them here.
comment created time in 2 months
Pull request review commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
private String determineEmbeddedUsername(R2dbcProperties properties) { } } + private void configureIfProxyListenersExist(Builder optionsBuilder, ConnectionFactoryOptions urlOptions,+ ProxyListenersProvider proxyListenersProvider) {+ List<ProxyExecutionListener> proxyListeners = proxyListenersProvider.listeners();+ if (proxyListeners.isEmpty()) {+ return;+ }+ String driver = urlOptions.getRequiredValue(ConnectionFactoryOptions.DRIVER);+ if (!ProxyConnectionFactoryProvider.PROXY_DRIVER.equals(driver)) {+ optionsBuilder.option(ConnectionFactoryOptions.DRIVER, ProxyConnectionFactoryProvider.PROXY_DRIVER);+ String protocol = urlOptions.getValue(ConnectionFactoryOptions.PROTOCOL);+ String newProtocol = StringUtils.isEmpty(protocol) ? driver : driver + ":" + protocol;+ optionsBuilder.option(ConnectionFactoryOptions.PROTOCOL, newProtocol);+ }+ optionsBuilder.option(ProxyConnectionFactoryProvider.PROXY_LISTENERS, proxyListeners);+ }
What here is doing is reconstructing DRIVER and PROTOCOL options.
e.g: r2dbc:h2:mem://... to r2dbc:proxy:h2:mem://...
| - | DRIVER | PROTOCOL |
|---|---|---|
| From | h2 | mem |
| To | proxy | h2:mem |
This way, the discovery mechanism will create ConnectionFactory for proxy and mysql.
Actually, I think same way may be used for r2dbc-pool via PoolingConnectionFactoryProvider as well.
comment created time in 2 months
pull request commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
Hi @snicoll I added a commit 9cccc61004fa4616a02d32b3572149675f3f329b.
This uses ConnectionFactoryOptionsInitializer(via ConnectionFactoryConfigurations#createConnectionFactory) to construct ConnectionFactory options used by ProxyConnectionFactoryProvider(r2bc-proxy).
Also, added ProxyListenersProvider interface to avoid direct reference to the classes in r2dbc-proxy to make it work when r2dbc-proxy is not available.
If this looks good, I'll cleanup the commits with tests.
comment created time in 2 months
push eventttddyy/spring-boot
commit sha 9cccc61004fa4616a02d32b3572149675f3f329b
WIP: Configure r2dbc-proxy listeners via ConnectionFactory Option Populate `ConnectionFactory` options for r2dbc-proxy listeners when those beans are defined.
push time in 2 months
pull request commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
@snicoll Ok, I'll explore the path for modifying ConnectionFactoryConfigurations#createConnectionFactory with ConnectionFactoryOptions.
ProxyConnectionFactoryProvider(ConnectionFactoryProvider impl in r2dbc-proxy) understands proxy-listener options.
So, if proxy-listener beans are defined, pass them as ConnectionFactoryOptions, then ConnectionFactories#find() would delegate to ProxyConnectionFactoryProvider for actual ProxyConnectionFactory creation with those proxy-listener beans.
I think this way is better since it would make more use of r2dbc-spi infrastructure.
comment created time in 3 months
pull request commentspring-projects/spring-boot
Add autoconfiguration for r2dbc-proxy
Hi @marcingrzejszczak
I wrote a sample listener for tracing here long time ago. Looking at it now, I can cleanup a bit. I'll find a time to update it as for a sample listener impl for tracing.
comment created time in 3 months