diff --git a/framework-docs/modules/ROOT/pages/core/aot.adoc b/framework-docs/modules/ROOT/pages/core/aot.adoc index 6db059bacb0..80a75965d77 100644 --- a/framework-docs/modules/ROOT/pages/core/aot.adoc +++ b/framework-docs/modules/ROOT/pages/core/aot.adoc @@ -378,6 +378,20 @@ For instance, autowiring on fields and methods will be skipped as they are handl Rather than having prototype-scoped beans created with custom arguments, we recommend a manual factory pattern where a bean is responsible for the creation of the instance. +[[aot.bestpractices.circular-dependencies]] +=== Avoid Circular Dependencies + +Certain use cases can result in circular dependencies between one or more beans. With the +regular runtime, it may be possible to wire those circular dependencies via `@Autowired` +on setter methods or fields. However, an AOT-optimized context will fail to start with +explicit circular dependencies. + +In an AOT-optimized application, you should therefore strive to avoid circular +dependencies. If that is not possible, you can use `@Lazy` injection points or +`ObjectProvider` to lazily access or retrieve the necessary collaborating beans. See +xref:core/beans/classpath-scanning.adoc#beans-factorybeans-annotations-lazy-injection-points[this tip] +for further information. + [[aot.bestpractices.factory-bean]] === FactoryBean diff --git a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc index d5b07af5762..8193305116b 100644 --- a/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc +++ b/framework-docs/modules/ROOT/pages/core/beans/classpath-scanning.adoc @@ -480,11 +480,15 @@ factory method and other bean definition properties, such as a qualifier value t the `@Qualifier` annotation. Other method-level annotations that can be specified are `@Scope`, `@Lazy`, and custom qualifier annotations. -TIP: In addition to its role for component initialization, you can also place the `@Lazy` +[[beans-factorybeans-annotations-lazy-injection-points]] +[TIP] +==== +In addition to its role for component initialization, you can also place the `@Lazy` annotation on injection points marked with `@Autowired` or `@Inject`. In this context, it leads to the injection of a lazy-resolution proxy. However, such a proxy approach is rather limited. For sophisticated lazy interactions, in particular in combination with optional dependencies, we recommend `ObjectProvider` instead. +==== Autowired fields and methods are supported, as previously discussed, with additional support for autowiring of `@Bean` methods. The following example shows how to do so: diff --git a/spring-context/src/test/java/org/springframework/cache/interceptor/CacheOperationExpressionEvaluatorTests.java b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheOperationExpressionEvaluatorTests.java index 11625dce481..3b826775a54 100644 --- a/spring-context/src/test/java/org/springframework/cache/interceptor/CacheOperationExpressionEvaluatorTests.java +++ b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheOperationExpressionEvaluatorTests.java @@ -86,7 +86,7 @@ class CacheOperationExpressionEvaluatorTests { AnnotatedClass target = new AnnotatedClass(); Method method = ReflectionUtils.findMethod( AnnotatedClass.class, "multipleCaching", Object.class, Object.class); - Object[] args = new Object[] {new Object(), new Object()}; + Object[] args = {"arg1", "arg2"}; Collection caches = Collections.singleton(new ConcurrentMapCache("test")); EvaluationContext evalCtx = this.eval.createEvaluationContext(caches, method, args, @@ -155,7 +155,7 @@ class CacheOperationExpressionEvaluatorTests { AnnotatedClass target = new AnnotatedClass(); Method method = ReflectionUtils.findMethod( AnnotatedClass.class, "multipleCaching", Object.class, Object.class); - Object[] args = new Object[] {new Object(), new Object()}; + Object[] args = new Object[] {"arg1", "arg2"}; Collection caches = Collections.singleton(new ConcurrentMapCache("test")); return this.eval.createEvaluationContext( caches, method, args, target, target.getClass(), method, result);