From 97b83a3e4a16488438b9183760f7f1e0f778b88a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 4 Apr 2019 16:09:51 +0200 Subject: [PATCH 1/2] Revised documentation on constructor autowiring semantics Closes gh-22735 --- src/docs/asciidoc/core/core-beans.adoc | 56 +++++++++++++++++--------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/src/docs/asciidoc/core/core-beans.adoc b/src/docs/asciidoc/core/core-beans.adoc index 5e77405f70..40dde2635c 100644 --- a/src/docs/asciidoc/core/core-beans.adoc +++ b/src/docs/asciidoc/core/core-beans.adoc @@ -4690,9 +4690,9 @@ implementation type, consider declaring the most specific return type on your fa method (at least as specific as required by the injection points referring to your bean). ==== -You can also provide all beans of a particular type from the -`ApplicationContext` by adding the annotation to a field or method that expects an array -of that type, as the following example shows: +You can also provide all beans of a particular type from the `ApplicationContext` +by adding the annotation to a field or method that expects an array of that type, +as the following example shows: ==== [source,java,indent=0] @@ -4746,8 +4746,8 @@ Note that the standard `javax.annotation.Priority` annotation is not available a through `@Order` values in combination with `@Primary` on a single bean for each type. ==== -Even typed `Map` instances can be autowired as long as the expected key type is `String`. The Map -values contain all beans of the expected type, and the keys contain the +Even typed `Map` instances can be autowired as long as the expected key type is `String`. +The Map values contain all beans of the expected type, and the keys contain the corresponding bean names, as the following example shows: ==== @@ -4768,10 +4768,14 @@ corresponding bean names, as the following example shows: ---- ==== -By default, the autowiring fails whenever zero candidate beans are available. The -default behavior is to treat annotated methods, constructors, and fields as -indicating required dependencies. You can change this behavior as demonstrated, in the -following example: +By default, autowiring fails when no matching candidate beans are available for +a given injection point. In the case of a declared array, collection or map, +at least one matching element is expected. + +The default behavior is to treat annotated methods and fields as indicating +required dependencies. You can change this behavior as demonstrated in the +following example, enabling the framework to skip a non-satisfiable injection +point through marking it as non-required: ==== [source,java,indent=0] @@ -4791,18 +4795,34 @@ following example: ---- ==== +A non-required method will not be called at all if its dependency (or one of its +dependencies in case of multiple arguments) is not available. A non-required field +will not get populated at all in such case, leaving its default value in place. + +Injected constructor and factory method arguments are a special case since the +'required' flag on `@Autowired` has a somewhat different meaning due to Spring's +constructor resolution algorithm potentially dealing with multiple constructors. +Constructor and factory method arguments are effectively required by default but +with a few special rules in a single-constructor scenario, such as multi-element +injection points (arrays, collections, maps) resolving to empty instances if no +matching beans are available. This allows for a common implementation pattern +where all dependencies can be declared in a unique multi-argument constructor, +e.g. declared as a single public constructor without an `@Autowired` annotation. + [NOTE] ==== -Only one annotated constructor per-class can be marked as required, but multiple -non-required constructors can be annotated. In that case, each is considered among the -candidates and Spring uses the greediest constructor whose dependencies can be +Only one annotated constructor per class can be marked as required, but multiple +non-required constructors can be annotated. In that case, each is considered among +the candidates and Spring uses the greediest constructor whose dependencies can be satisfied -- that is, the constructor that has the largest number of arguments. - -The required attribute of `@Autowired` is recommended over the `@Required` annotation. -The required attribute indicates that the property is not required for autowiring -purposes. The property is ignored if it cannot be autowired. `@Required`, on the other -hand, is stronger in that it enforces the property that was set by any means supported -by the container. If no value is injected, a corresponding exception is raised. +The constructor resolution algorithm is the same as for non-annotated classes with +overloaded constructors, just narrowing the candidates to annotated constructors. + +The 'required' attribute of `@Autowired` is recommended over the `@Required` annotation +on setter methods. The 'required' attribute indicates that the property is not required +for autowiring purposes. The property is ignored if it cannot be autowired. `@Required`, +on the other hand, is stronger in that it enforces the property to be set by any means +supported by the container. If no value is defined, a corresponding exception is raised. ==== Alternatively, you can express the non-required nature of a particular dependency From 95232d5bf83730c33ba14db73dc6ddf489903749 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 4 Apr 2019 16:10:16 +0200 Subject: [PATCH 2/2] Upgrade to Apache HttpClient 4.5.8 and Jetty Reactive HttpClient 1.0.3 --- spring-test/spring-test.gradle | 2 +- spring-web/spring-web.gradle | 4 ++-- spring-webflux/spring-webflux.gradle | 4 ++-- spring-webmvc/spring-webmvc.gradle | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spring-test/spring-test.gradle b/spring-test/spring-test.gradle index d279755cd6..bfabbcfb9f 100644 --- a/spring-test/spring-test.gradle +++ b/spring-test/spring-test.gradle @@ -72,7 +72,7 @@ dependencies { testCompile("org.apache.tiles:tiles-core:${tiles3Version}", withoutJclOverSlf4J) testCompile("org.apache.tiles:tiles-servlet:${tiles3Version}", withoutJclOverSlf4J) testCompile("org.hsqldb:hsqldb:${hsqldbVersion}") - testCompile("org.apache.httpcomponents:httpclient:4.5.7") { + testCompile("org.apache.httpcomponents:httpclient:4.5.8") { exclude group: "commons-logging", module: "commons-logging" } testCompile("io.projectreactor.netty:reactor-netty") diff --git a/spring-web/spring-web.gradle b/spring-web/spring-web.gradle index f9e063b98b..34e02de820 100644 --- a/spring-web/spring-web.gradle +++ b/spring-web/spring-web.gradle @@ -37,9 +37,9 @@ dependencies { optional("org.eclipse.jetty:jetty-servlet") { exclude group: "javax.servlet", module: "javax.servlet-api" } - optional("org.eclipse.jetty:jetty-reactive-httpclient:1.0.2") + optional("org.eclipse.jetty:jetty-reactive-httpclient:1.0.3") optional("com.squareup.okhttp3:okhttp:3.14.0") - optional("org.apache.httpcomponents:httpclient:4.5.7") { + optional("org.apache.httpcomponents:httpclient:4.5.8") { exclude group: "commons-logging", module: "commons-logging" } optional("org.apache.httpcomponents:httpasyncclient:4.1.4") { diff --git a/spring-webflux/spring-webflux.gradle b/spring-webflux/spring-webflux.gradle index fe2103f507..b446666925 100644 --- a/spring-webflux/spring-webflux.gradle +++ b/spring-webflux/spring-webflux.gradle @@ -34,7 +34,7 @@ dependencies { optional("io.undertow:undertow-websockets-jsr:${undertowVersion}") { exclude group: "org.jboss.spec.javax.websocket", module: "jboss-websocket-api_1.1_spec" } - optional("org.apache.httpcomponents:httpclient:4.5.7") { + optional("org.apache.httpcomponents:httpclient:4.5.8") { exclude group: "commons-logging", module: "commons-logging" } optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") @@ -50,7 +50,7 @@ dependencies { testCompile("org.apache.tomcat:tomcat-util:${tomcatVersion}") testCompile("org.eclipse.jetty:jetty-server") testCompile("org.eclipse.jetty:jetty-servlet") - testCompile("org.eclipse.jetty:jetty-reactive-httpclient:1.0.2") + testCompile("org.eclipse.jetty:jetty-reactive-httpclient:1.0.3") testCompile("com.squareup.okhttp3:mockwebserver:3.14.0") testCompile("org.jetbrains.kotlin:kotlin-script-runtime:${kotlinVersion}") testRuntime("org.jetbrains.kotlin:kotlin-script-util:${kotlinVersion}") diff --git a/spring-webmvc/spring-webmvc.gradle b/spring-webmvc/spring-webmvc.gradle index cf756721df..29e1180be2 100644 --- a/spring-webmvc/spring-webmvc.gradle +++ b/spring-webmvc/spring-webmvc.gradle @@ -50,7 +50,7 @@ dependencies { testCompile("org.eclipse.jetty:jetty-server") { exclude group: "javax.servlet", module: "javax.servlet" } - testCompile("org.apache.httpcomponents:httpclient:4.5.7") { + testCompile("org.apache.httpcomponents:httpclient:4.5.8") { exclude group: "commons-logging", module: "commons-logging" } testCompile("commons-fileupload:commons-fileupload:1.4")