1
1
/*
2
- * Copyright 2002-2023 the original author or authors.
2
+ * Copyright 2002-2024 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
16
16
17
17
package org .springframework .context .annotation ;
18
18
19
+ import java .io .Serializable ;
19
20
import java .lang .annotation .Annotation ;
20
21
import java .lang .reflect .Method ;
21
22
import java .util .Collection ;
27
28
28
29
import org .springframework .aop .TargetSource ;
29
30
import org .springframework .aop .framework .ProxyFactory ;
30
- import org .springframework .beans .factory .BeanFactory ;
31
31
import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
32
32
import org .springframework .beans .factory .annotation .QualifierAnnotationAutowireCandidateResolver ;
33
33
import org .springframework .beans .factory .config .DependencyDescriptor ;
34
34
import org .springframework .beans .factory .support .DefaultListableBeanFactory ;
35
35
import org .springframework .core .MethodParameter ;
36
36
import org .springframework .core .annotation .AnnotationUtils ;
37
37
import org .springframework .lang .Nullable ;
38
- import org .springframework .util .Assert ;
39
38
40
39
/**
41
40
* Complete implementation of the
@@ -85,47 +84,13 @@ protected Object buildLazyResolutionProxy(DependencyDescriptor descriptor, @Null
85
84
}
86
85
87
86
private Object buildLazyResolutionProxy (
88
- final DependencyDescriptor descriptor , @ Nullable final String beanName , boolean classOnly ) {
87
+ DependencyDescriptor descriptor , @ Nullable String beanName , boolean classOnly ) {
89
88
90
- BeanFactory beanFactory = getBeanFactory ();
91
- Assert .state (beanFactory instanceof DefaultListableBeanFactory ,
92
- "BeanFactory needs to be a DefaultListableBeanFactory" );
93
- final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory ) beanFactory ;
89
+ if (!(getBeanFactory () instanceof DefaultListableBeanFactory dlbf )) {
90
+ throw new IllegalStateException ("Lazy resolution only supported with DefaultListableBeanFactory" );
91
+ }
94
92
95
- TargetSource ts = new TargetSource () {
96
- @ Override
97
- public Class <?> getTargetClass () {
98
- return descriptor .getDependencyType ();
99
- }
100
- @ Override
101
- @ SuppressWarnings ("NullAway" )
102
- public Object getTarget () {
103
- Set <String > autowiredBeanNames = (beanName != null ? new LinkedHashSet <>(1 ) : null );
104
- Object target = dlbf .doResolveDependency (descriptor , beanName , autowiredBeanNames , null );
105
- if (target == null ) {
106
- Class <?> type = getTargetClass ();
107
- if (Map .class == type ) {
108
- return Collections .emptyMap ();
109
- }
110
- else if (List .class == type ) {
111
- return Collections .emptyList ();
112
- }
113
- else if (Set .class == type || Collection .class == type ) {
114
- return Collections .emptySet ();
115
- }
116
- throw new NoSuchBeanDefinitionException (descriptor .getResolvableType (),
117
- "Optional dependency not present for lazy injection point" );
118
- }
119
- if (autowiredBeanNames != null ) {
120
- for (String autowiredBeanName : autowiredBeanNames ) {
121
- if (dlbf .containsBean (autowiredBeanName )) {
122
- dlbf .registerDependentBean (autowiredBeanName , beanName );
123
- }
124
- }
125
- }
126
- return target ;
127
- }
128
- };
93
+ TargetSource ts = new LazyDependencyTargetSource (dlbf , descriptor , beanName );
129
94
130
95
ProxyFactory pf = new ProxyFactory ();
131
96
pf .setTargetSource (ts );
@@ -137,4 +102,96 @@ else if (Set.class == type || Collection.class == type) {
137
102
return (classOnly ? pf .getProxyClass (classLoader ) : pf .getProxy (classLoader ));
138
103
}
139
104
105
+
106
+ @ SuppressWarnings ("serial" )
107
+ private static class LazyDependencyTargetSource implements TargetSource , Serializable {
108
+
109
+ private final DefaultListableBeanFactory beanFactory ;
110
+
111
+ private final DependencyDescriptor descriptor ;
112
+
113
+ @ Nullable
114
+ private final String beanName ;
115
+
116
+ @ Nullable
117
+ private transient volatile Object cachedTarget ;
118
+
119
+ public LazyDependencyTargetSource (DefaultListableBeanFactory beanFactory ,
120
+ DependencyDescriptor descriptor , @ Nullable String beanName ) {
121
+
122
+ this .beanFactory = beanFactory ;
123
+ this .descriptor = descriptor ;
124
+ this .beanName = beanName ;
125
+ }
126
+
127
+ @ Override
128
+ public Class <?> getTargetClass () {
129
+ return this .descriptor .getDependencyType ();
130
+ }
131
+
132
+ @ Override
133
+ @ SuppressWarnings ("NullAway" )
134
+ public Object getTarget () {
135
+ Object cachedTarget = this .cachedTarget ;
136
+ if (cachedTarget != null ) {
137
+ return cachedTarget ;
138
+ }
139
+
140
+ Set <String > autowiredBeanNames = new LinkedHashSet <>(2 );
141
+ Object target = this .beanFactory .doResolveDependency (
142
+ this .descriptor , this .beanName , autowiredBeanNames , null );
143
+
144
+ if (target == null ) {
145
+ Class <?> type = getTargetClass ();
146
+ if (Map .class == type ) {
147
+ target = Collections .emptyMap ();
148
+ }
149
+ else if (List .class == type ) {
150
+ target = Collections .emptyList ();
151
+ }
152
+ else if (Set .class == type || Collection .class == type ) {
153
+ target = Collections .emptySet ();
154
+ }
155
+ else {
156
+ throw new NoSuchBeanDefinitionException (this .descriptor .getResolvableType (),
157
+ "Optional dependency not present for lazy injection point" );
158
+ }
159
+ }
160
+ else {
161
+ if (target instanceof Map <?, ?> map && Map .class == getTargetClass ()) {
162
+ target = Collections .unmodifiableMap (map );
163
+ }
164
+ else if (target instanceof List <?> list && List .class == getTargetClass ()) {
165
+ target = Collections .unmodifiableList (list );
166
+ }
167
+ else if (target instanceof Set <?> set && Set .class == getTargetClass ()) {
168
+ target = Collections .unmodifiableSet (set );
169
+ }
170
+ else if (target instanceof Collection <?> coll && Collection .class == getTargetClass ()) {
171
+ target = Collections .unmodifiableCollection (coll );
172
+ }
173
+ }
174
+
175
+ boolean cacheable = true ;
176
+ for (String autowiredBeanName : autowiredBeanNames ) {
177
+ if (!this .beanFactory .containsBean (autowiredBeanName )) {
178
+ cacheable = false ;
179
+ }
180
+ else {
181
+ if (this .beanName != null ) {
182
+ this .beanFactory .registerDependentBean (autowiredBeanName , this .beanName );
183
+ }
184
+ if (!this .beanFactory .isSingleton (autowiredBeanName )) {
185
+ cacheable = false ;
186
+ }
187
+ }
188
+ if (cacheable ) {
189
+ this .cachedTarget = target ;
190
+ }
191
+ }
192
+
193
+ return target ;
194
+ }
195
+ }
196
+
140
197
}
0 commit comments