001/* 002 * Copyright 2002-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.annotation; 018 019import java.beans.PropertyDescriptor; 020import java.lang.annotation.Annotation; 021import java.lang.reflect.AccessibleObject; 022import java.lang.reflect.Constructor; 023import java.lang.reflect.Field; 024import java.lang.reflect.InvocationTargetException; 025import java.lang.reflect.Method; 026import java.lang.reflect.Modifier; 027import java.util.ArrayList; 028import java.util.Arrays; 029import java.util.Collections; 030import java.util.Iterator; 031import java.util.LinkedHashSet; 032import java.util.List; 033import java.util.Map; 034import java.util.Set; 035import java.util.concurrent.ConcurrentHashMap; 036 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039 040import org.springframework.beans.BeanUtils; 041import org.springframework.beans.BeansException; 042import org.springframework.beans.PropertyValues; 043import org.springframework.beans.TypeConverter; 044import org.springframework.beans.factory.BeanCreationException; 045import org.springframework.beans.factory.BeanFactory; 046import org.springframework.beans.factory.BeanFactoryAware; 047import org.springframework.beans.factory.BeanFactoryUtils; 048import org.springframework.beans.factory.InjectionPoint; 049import org.springframework.beans.factory.NoSuchBeanDefinitionException; 050import org.springframework.beans.factory.UnsatisfiedDependencyException; 051import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 052import org.springframework.beans.factory.config.DependencyDescriptor; 053import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; 054import org.springframework.beans.factory.support.LookupOverride; 055import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor; 056import org.springframework.beans.factory.support.RootBeanDefinition; 057import org.springframework.core.BridgeMethodResolver; 058import org.springframework.core.MethodParameter; 059import org.springframework.core.Ordered; 060import org.springframework.core.PriorityOrdered; 061import org.springframework.core.annotation.AnnotationAttributes; 062import org.springframework.core.annotation.AnnotationUtils; 063import org.springframework.core.annotation.MergedAnnotation; 064import org.springframework.core.annotation.MergedAnnotations; 065import org.springframework.lang.Nullable; 066import org.springframework.util.Assert; 067import org.springframework.util.ClassUtils; 068import org.springframework.util.ReflectionUtils; 069import org.springframework.util.StringUtils; 070 071/** 072 * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor} 073 * implementation that autowires annotated fields, setter methods, and arbitrary 074 * config methods. Such members to be injected are detected through annotations: 075 * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value} 076 * annotations. 077 * 078 * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation, 079 * if available, as a direct alternative to Spring's own {@code @Autowired}. 080 * 081 * <h3>Autowired Constructors</h3> 082 * <p>Only one constructor of any given bean class may declare this annotation with 083 * the 'required' attribute set to {@code true}, indicating <i>the</i> constructor 084 * to autowire when used as a Spring bean. Furthermore, if the 'required' attribute 085 * is set to {@code true}, only a single constructor may be annotated with 086 * {@code @Autowired}. If multiple <i>non-required</i> constructors declare the 087 * annotation, they will be considered as candidates for autowiring. The constructor 088 * with the greatest number of dependencies that can be satisfied by matching beans 089 * in the Spring container will be chosen. If none of the candidates can be satisfied, 090 * then a primary/default constructor (if present) will be used. If a class only 091 * declares a single constructor to begin with, it will always be used, even if not 092 * annotated. An annotated constructor does not have to be public. 093 * 094 * <h3>Autowired Fields</h3> 095 * <p>Fields are injected right after construction of a bean, before any 096 * config methods are invoked. Such a config field does not have to be public. 097 * 098 * <h3>Autowired Methods</h3> 099 * <p>Config methods may have an arbitrary name and any number of arguments; each of 100 * those arguments will be autowired with a matching bean in the Spring container. 101 * Bean property setter methods are effectively just a special case of such a 102 * general config method. Config methods do not have to be public. 103 * 104 * <h3>Annotation Config vs. XML Config</h3> 105 * <p>A default {@code AutowiredAnnotationBeanPostProcessor} will be registered 106 * by the "context:annotation-config" and "context:component-scan" XML tags. 107 * Remove or turn off the default annotation configuration there if you intend 108 * to specify a custom {@code AutowiredAnnotationBeanPostProcessor} bean definition. 109 * 110 * <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection; 111 * thus the latter configuration will override the former for properties wired through 112 * both approaches. 113 * 114 * <h3>{@literal @}Lookup Methods</h3> 115 * <p>In addition to regular injection points as discussed above, this post-processor 116 * also handles Spring's {@link Lookup @Lookup} annotation which identifies lookup 117 * methods to be replaced by the container at runtime. This is essentially a type-safe 118 * version of {@code getBean(Class, args)} and {@code getBean(String, args)}. 119 * See {@link Lookup @Lookup's javadoc} for details. 120 * 121 * @author Juergen Hoeller 122 * @author Mark Fisher 123 * @author Stephane Nicoll 124 * @author Sebastien Deleuze 125 * @author Sam Brannen 126 * @since 2.5 127 * @see #setAutowiredAnnotationType 128 * @see Autowired 129 * @see Value 130 */ 131public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter 132 implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware { 133 134 protected final Log logger = LogFactory.getLog(getClass()); 135 136 private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4); 137 138 private String requiredParameterName = "required"; 139 140 private boolean requiredParameterValue = true; 141 142 private int order = Ordered.LOWEST_PRECEDENCE - 2; 143 144 @Nullable 145 private ConfigurableListableBeanFactory beanFactory; 146 147 private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); 148 149 private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256); 150 151 private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256); 152 153 154 /** 155 * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's 156 * standard {@link Autowired @Autowired} and {@link Value @Value} annotations. 157 * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation, 158 * if available. 159 */ 160 @SuppressWarnings("unchecked") 161 public AutowiredAnnotationBeanPostProcessor() { 162 this.autowiredAnnotationTypes.add(Autowired.class); 163 this.autowiredAnnotationTypes.add(Value.class); 164 try { 165 this.autowiredAnnotationTypes.add((Class<? extends Annotation>) 166 ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader())); 167 logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring"); 168 } 169 catch (ClassNotFoundException ex) { 170 // JSR-330 API not available - simply skip. 171 } 172 } 173 174 175 /** 176 * Set the 'autowired' annotation type, to be used on constructors, fields, 177 * setter methods, and arbitrary config methods. 178 * <p>The default autowired annotation types are the Spring-provided 179 * {@link Autowired @Autowired} and {@link Value @Value} annotations as well 180 * as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available. 181 * <p>This setter property exists so that developers can provide their own 182 * (non-Spring-specific) annotation type to indicate that a member is supposed 183 * to be autowired. 184 */ 185 public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) { 186 Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null"); 187 this.autowiredAnnotationTypes.clear(); 188 this.autowiredAnnotationTypes.add(autowiredAnnotationType); 189 } 190 191 /** 192 * Set the 'autowired' annotation types, to be used on constructors, fields, 193 * setter methods, and arbitrary config methods. 194 * <p>The default autowired annotation types are the Spring-provided 195 * {@link Autowired @Autowired} and {@link Value @Value} annotations as well 196 * as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available. 197 * <p>This setter property exists so that developers can provide their own 198 * (non-Spring-specific) annotation types to indicate that a member is supposed 199 * to be autowired. 200 */ 201 public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) { 202 Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty"); 203 this.autowiredAnnotationTypes.clear(); 204 this.autowiredAnnotationTypes.addAll(autowiredAnnotationTypes); 205 } 206 207 /** 208 * Set the name of an attribute of the annotation that specifies whether it is required. 209 * @see #setRequiredParameterValue(boolean) 210 */ 211 public void setRequiredParameterName(String requiredParameterName) { 212 this.requiredParameterName = requiredParameterName; 213 } 214 215 /** 216 * Set the boolean value that marks a dependency as required. 217 * <p>For example if using 'required=true' (the default), this value should be 218 * {@code true}; but if using 'optional=false', this value should be {@code false}. 219 * @see #setRequiredParameterName(String) 220 */ 221 public void setRequiredParameterValue(boolean requiredParameterValue) { 222 this.requiredParameterValue = requiredParameterValue; 223 } 224 225 public void setOrder(int order) { 226 this.order = order; 227 } 228 229 @Override 230 public int getOrder() { 231 return this.order; 232 } 233 234 @Override 235 public void setBeanFactory(BeanFactory beanFactory) { 236 if (!(beanFactory instanceof ConfigurableListableBeanFactory)) { 237 throw new IllegalArgumentException( 238 "AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory); 239 } 240 this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; 241 } 242 243 244 @Override 245 public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { 246 InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null); 247 metadata.checkConfigMembers(beanDefinition); 248 } 249 250 @Override 251 public void resetBeanDefinition(String beanName) { 252 this.lookupMethodsChecked.remove(beanName); 253 this.injectionMetadataCache.remove(beanName); 254 } 255 256 @Override 257 @Nullable 258 public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) 259 throws BeanCreationException { 260 261 // Let's check for lookup methods here... 262 if (!this.lookupMethodsChecked.contains(beanName)) { 263 if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) { 264 try { 265 Class<?> targetClass = beanClass; 266 do { 267 ReflectionUtils.doWithLocalMethods(targetClass, method -> { 268 Lookup lookup = method.getAnnotation(Lookup.class); 269 if (lookup != null) { 270 Assert.state(this.beanFactory != null, "No BeanFactory available"); 271 LookupOverride override = new LookupOverride(method, lookup.value()); 272 try { 273 RootBeanDefinition mbd = (RootBeanDefinition) 274 this.beanFactory.getMergedBeanDefinition(beanName); 275 mbd.getMethodOverrides().addOverride(override); 276 } 277 catch (NoSuchBeanDefinitionException ex) { 278 throw new BeanCreationException(beanName, 279 "Cannot apply @Lookup to beans without corresponding bean definition"); 280 } 281 } 282 }); 283 targetClass = targetClass.getSuperclass(); 284 } 285 while (targetClass != null && targetClass != Object.class); 286 287 } 288 catch (IllegalStateException ex) { 289 throw new BeanCreationException(beanName, "Lookup method resolution failed", ex); 290 } 291 } 292 this.lookupMethodsChecked.add(beanName); 293 } 294 295 // Quick check on the concurrent map first, with minimal locking. 296 Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass); 297 if (candidateConstructors == null) { 298 // Fully synchronized resolution now... 299 synchronized (this.candidateConstructorsCache) { 300 candidateConstructors = this.candidateConstructorsCache.get(beanClass); 301 if (candidateConstructors == null) { 302 Constructor<?>[] rawCandidates; 303 try { 304 rawCandidates = beanClass.getDeclaredConstructors(); 305 } 306 catch (Throwable ex) { 307 throw new BeanCreationException(beanName, 308 "Resolution of declared constructors on bean Class [" + beanClass.getName() + 309 "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); 310 } 311 List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length); 312 Constructor<?> requiredConstructor = null; 313 Constructor<?> defaultConstructor = null; 314 Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass); 315 int nonSyntheticConstructors = 0; 316 for (Constructor<?> candidate : rawCandidates) { 317 if (!candidate.isSynthetic()) { 318 nonSyntheticConstructors++; 319 } 320 else if (primaryConstructor != null) { 321 continue; 322 } 323 MergedAnnotation<?> ann = findAutowiredAnnotation(candidate); 324 if (ann == null) { 325 Class<?> userClass = ClassUtils.getUserClass(beanClass); 326 if (userClass != beanClass) { 327 try { 328 Constructor<?> superCtor = 329 userClass.getDeclaredConstructor(candidate.getParameterTypes()); 330 ann = findAutowiredAnnotation(superCtor); 331 } 332 catch (NoSuchMethodException ex) { 333 // Simply proceed, no equivalent superclass constructor found... 334 } 335 } 336 } 337 if (ann != null) { 338 if (requiredConstructor != null) { 339 throw new BeanCreationException(beanName, 340 "Invalid autowire-marked constructor: " + candidate + 341 ". Found constructor with 'required' Autowired annotation already: " + 342 requiredConstructor); 343 } 344 boolean required = determineRequiredStatus(ann); 345 if (required) { 346 if (!candidates.isEmpty()) { 347 throw new BeanCreationException(beanName, 348 "Invalid autowire-marked constructors: " + candidates + 349 ". Found constructor with 'required' Autowired annotation: " + 350 candidate); 351 } 352 requiredConstructor = candidate; 353 } 354 candidates.add(candidate); 355 } 356 else if (candidate.getParameterCount() == 0) { 357 defaultConstructor = candidate; 358 } 359 } 360 if (!candidates.isEmpty()) { 361 // Add default constructor to list of optional constructors, as fallback. 362 if (requiredConstructor == null) { 363 if (defaultConstructor != null) { 364 candidates.add(defaultConstructor); 365 } 366 else if (candidates.size() == 1 && logger.isInfoEnabled()) { 367 logger.info("Inconsistent constructor declaration on bean with name '" + beanName + 368 "': single autowire-marked constructor flagged as optional - " + 369 "this constructor is effectively required since there is no " + 370 "default constructor to fall back to: " + candidates.get(0)); 371 } 372 } 373 candidateConstructors = candidates.toArray(new Constructor<?>[0]); 374 } 375 else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { 376 candidateConstructors = new Constructor<?>[] {rawCandidates[0]}; 377 } 378 else if (nonSyntheticConstructors == 2 && primaryConstructor != null && 379 defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) { 380 candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor}; 381 } 382 else if (nonSyntheticConstructors == 1 && primaryConstructor != null) { 383 candidateConstructors = new Constructor<?>[] {primaryConstructor}; 384 } 385 else { 386 candidateConstructors = new Constructor<?>[0]; 387 } 388 this.candidateConstructorsCache.put(beanClass, candidateConstructors); 389 } 390 } 391 } 392 return (candidateConstructors.length > 0 ? candidateConstructors : null); 393 } 394 395 @Override 396 public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { 397 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); 398 try { 399 metadata.inject(bean, beanName, pvs); 400 } 401 catch (BeanCreationException ex) { 402 throw ex; 403 } 404 catch (Throwable ex) { 405 throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); 406 } 407 return pvs; 408 } 409 410 @Deprecated 411 @Override 412 public PropertyValues postProcessPropertyValues( 413 PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) { 414 415 return postProcessProperties(pvs, bean, beanName); 416 } 417 418 /** 419 * 'Native' processing method for direct calls with an arbitrary target instance, 420 * resolving all of its fields and methods which are annotated with one of the 421 * configured 'autowired' annotation types. 422 * @param bean the target instance to process 423 * @throws BeanCreationException if autowiring failed 424 * @see #setAutowiredAnnotationTypes(Set) 425 */ 426 public void processInjection(Object bean) throws BeanCreationException { 427 Class<?> clazz = bean.getClass(); 428 InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null); 429 try { 430 metadata.inject(bean, null, null); 431 } 432 catch (BeanCreationException ex) { 433 throw ex; 434 } 435 catch (Throwable ex) { 436 throw new BeanCreationException( 437 "Injection of autowired dependencies failed for class [" + clazz + "]", ex); 438 } 439 } 440 441 442 private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { 443 // Fall back to class name as cache key, for backwards compatibility with custom callers. 444 String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); 445 // Quick check on the concurrent map first, with minimal locking. 446 InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); 447 if (InjectionMetadata.needsRefresh(metadata, clazz)) { 448 synchronized (this.injectionMetadataCache) { 449 metadata = this.injectionMetadataCache.get(cacheKey); 450 if (InjectionMetadata.needsRefresh(metadata, clazz)) { 451 if (metadata != null) { 452 metadata.clear(pvs); 453 } 454 metadata = buildAutowiringMetadata(clazz); 455 this.injectionMetadataCache.put(cacheKey, metadata); 456 } 457 } 458 } 459 return metadata; 460 } 461 462 private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { 463 if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { 464 return InjectionMetadata.EMPTY; 465 } 466 467 List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); 468 Class<?> targetClass = clazz; 469 470 do { 471 final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); 472 473 ReflectionUtils.doWithLocalFields(targetClass, field -> { 474 MergedAnnotation<?> ann = findAutowiredAnnotation(field); 475 if (ann != null) { 476 if (Modifier.isStatic(field.getModifiers())) { 477 if (logger.isInfoEnabled()) { 478 logger.info("Autowired annotation is not supported on static fields: " + field); 479 } 480 return; 481 } 482 boolean required = determineRequiredStatus(ann); 483 currElements.add(new AutowiredFieldElement(field, required)); 484 } 485 }); 486 487 ReflectionUtils.doWithLocalMethods(targetClass, method -> { 488 Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); 489 if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { 490 return; 491 } 492 MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod); 493 if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { 494 if (Modifier.isStatic(method.getModifiers())) { 495 if (logger.isInfoEnabled()) { 496 logger.info("Autowired annotation is not supported on static methods: " + method); 497 } 498 return; 499 } 500 if (method.getParameterCount() == 0) { 501 if (logger.isInfoEnabled()) { 502 logger.info("Autowired annotation should only be used on methods with parameters: " + 503 method); 504 } 505 } 506 boolean required = determineRequiredStatus(ann); 507 PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); 508 currElements.add(new AutowiredMethodElement(method, required, pd)); 509 } 510 }); 511 512 elements.addAll(0, currElements); 513 targetClass = targetClass.getSuperclass(); 514 } 515 while (targetClass != null && targetClass != Object.class); 516 517 return InjectionMetadata.forElements(elements, clazz); 518 } 519 520 @Nullable 521 private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) { 522 MergedAnnotations annotations = MergedAnnotations.from(ao); 523 for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { 524 MergedAnnotation<?> annotation = annotations.get(type); 525 if (annotation.isPresent()) { 526 return annotation; 527 } 528 } 529 return null; 530 } 531 532 /** 533 * Determine if the annotated field or method requires its dependency. 534 * <p>A 'required' dependency means that autowiring should fail when no beans 535 * are found. Otherwise, the autowiring process will simply bypass the field 536 * or method when no beans are found. 537 * @param ann the Autowired annotation 538 * @return whether the annotation indicates that a dependency is required 539 */ 540 @SuppressWarnings({"deprecation", "cast"}) 541 protected boolean determineRequiredStatus(MergedAnnotation<?> ann) { 542 // The following (AnnotationAttributes) cast is required on JDK 9+. 543 return determineRequiredStatus((AnnotationAttributes) 544 ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType()))); 545 } 546 547 /** 548 * Determine if the annotated field or method requires its dependency. 549 * <p>A 'required' dependency means that autowiring should fail when no beans 550 * are found. Otherwise, the autowiring process will simply bypass the field 551 * or method when no beans are found. 552 * @param ann the Autowired annotation 553 * @return whether the annotation indicates that a dependency is required 554 * @deprecated since 5.2, in favor of {@link #determineRequiredStatus(MergedAnnotation)} 555 */ 556 @Deprecated 557 protected boolean determineRequiredStatus(AnnotationAttributes ann) { 558 return (!ann.containsKey(this.requiredParameterName) || 559 this.requiredParameterValue == ann.getBoolean(this.requiredParameterName)); 560 } 561 562 /** 563 * Obtain all beans of the given type as autowire candidates. 564 * @param type the type of the bean 565 * @return the target beans, or an empty Collection if no bean of this type is found 566 * @throws BeansException if bean retrieval failed 567 */ 568 protected <T> Map<String, T> findAutowireCandidates(Class<T> type) throws BeansException { 569 if (this.beanFactory == null) { 570 throw new IllegalStateException("No BeanFactory configured - " + 571 "override the getBeanOfType method or specify the 'beanFactory' property"); 572 } 573 return BeanFactoryUtils.beansOfTypeIncludingAncestors(this.beanFactory, type); 574 } 575 576 /** 577 * Register the specified bean as dependent on the autowired beans. 578 */ 579 private void registerDependentBeans(@Nullable String beanName, Set<String> autowiredBeanNames) { 580 if (beanName != null) { 581 for (String autowiredBeanName : autowiredBeanNames) { 582 if (this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)) { 583 this.beanFactory.registerDependentBean(autowiredBeanName, beanName); 584 } 585 if (logger.isTraceEnabled()) { 586 logger.trace("Autowiring by type from bean name '" + beanName + 587 "' to bean named '" + autowiredBeanName + "'"); 588 } 589 } 590 } 591 } 592 593 /** 594 * Resolve the specified cached method argument or field value. 595 */ 596 @Nullable 597 private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) { 598 if (cachedArgument instanceof DependencyDescriptor) { 599 DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument; 600 Assert.state(this.beanFactory != null, "No BeanFactory available"); 601 return this.beanFactory.resolveDependency(descriptor, beanName, null, null); 602 } 603 else { 604 return cachedArgument; 605 } 606 } 607 608 609 /** 610 * Class representing injection information about an annotated field. 611 */ 612 private class AutowiredFieldElement extends InjectionMetadata.InjectedElement { 613 614 private final boolean required; 615 616 private volatile boolean cached; 617 618 @Nullable 619 private volatile Object cachedFieldValue; 620 621 public AutowiredFieldElement(Field field, boolean required) { 622 super(field, null); 623 this.required = required; 624 } 625 626 @Override 627 protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { 628 Field field = (Field) this.member; 629 Object value; 630 if (this.cached) { 631 value = resolvedCachedArgument(beanName, this.cachedFieldValue); 632 } 633 else { 634 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); 635 desc.setContainingClass(bean.getClass()); 636 Set<String> autowiredBeanNames = new LinkedHashSet<>(1); 637 Assert.state(beanFactory != null, "No BeanFactory available"); 638 TypeConverter typeConverter = beanFactory.getTypeConverter(); 639 try { 640 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); 641 } 642 catch (BeansException ex) { 643 throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); 644 } 645 synchronized (this) { 646 if (!this.cached) { 647 Object cachedFieldValue = null; 648 if (value != null || this.required) { 649 cachedFieldValue = desc; 650 registerDependentBeans(beanName, autowiredBeanNames); 651 if (autowiredBeanNames.size() == 1) { 652 String autowiredBeanName = autowiredBeanNames.iterator().next(); 653 if (beanFactory.containsBean(autowiredBeanName) && 654 beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { 655 cachedFieldValue = new ShortcutDependencyDescriptor( 656 desc, autowiredBeanName, field.getType()); 657 } 658 } 659 } 660 this.cachedFieldValue = cachedFieldValue; 661 this.cached = true; 662 } 663 } 664 } 665 if (value != null) { 666 ReflectionUtils.makeAccessible(field); 667 field.set(bean, value); 668 } 669 } 670 } 671 672 673 /** 674 * Class representing injection information about an annotated method. 675 */ 676 private class AutowiredMethodElement extends InjectionMetadata.InjectedElement { 677 678 private final boolean required; 679 680 private volatile boolean cached; 681 682 @Nullable 683 private volatile Object[] cachedMethodArguments; 684 685 public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) { 686 super(method, pd); 687 this.required = required; 688 } 689 690 @Override 691 protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { 692 if (checkPropertySkipping(pvs)) { 693 return; 694 } 695 Method method = (Method) this.member; 696 Object[] arguments; 697 if (this.cached) { 698 // Shortcut for avoiding synchronization... 699 arguments = resolveCachedArguments(beanName); 700 } 701 else { 702 int argumentCount = method.getParameterCount(); 703 arguments = new Object[argumentCount]; 704 DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount]; 705 Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount); 706 Assert.state(beanFactory != null, "No BeanFactory available"); 707 TypeConverter typeConverter = beanFactory.getTypeConverter(); 708 for (int i = 0; i < arguments.length; i++) { 709 MethodParameter methodParam = new MethodParameter(method, i); 710 DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required); 711 currDesc.setContainingClass(bean.getClass()); 712 descriptors[i] = currDesc; 713 try { 714 Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter); 715 if (arg == null && !this.required) { 716 arguments = null; 717 break; 718 } 719 arguments[i] = arg; 720 } 721 catch (BeansException ex) { 722 throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex); 723 } 724 } 725 synchronized (this) { 726 if (!this.cached) { 727 if (arguments != null) { 728 DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length); 729 registerDependentBeans(beanName, autowiredBeans); 730 if (autowiredBeans.size() == argumentCount) { 731 Iterator<String> it = autowiredBeans.iterator(); 732 Class<?>[] paramTypes = method.getParameterTypes(); 733 for (int i = 0; i < paramTypes.length; i++) { 734 String autowiredBeanName = it.next(); 735 if (beanFactory.containsBean(autowiredBeanName) && 736 beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) { 737 cachedMethodArguments[i] = new ShortcutDependencyDescriptor( 738 descriptors[i], autowiredBeanName, paramTypes[i]); 739 } 740 } 741 } 742 this.cachedMethodArguments = cachedMethodArguments; 743 } 744 else { 745 this.cachedMethodArguments = null; 746 } 747 this.cached = true; 748 } 749 } 750 } 751 if (arguments != null) { 752 try { 753 ReflectionUtils.makeAccessible(method); 754 method.invoke(bean, arguments); 755 } 756 catch (InvocationTargetException ex) { 757 throw ex.getTargetException(); 758 } 759 } 760 } 761 762 @Nullable 763 private Object[] resolveCachedArguments(@Nullable String beanName) { 764 Object[] cachedMethodArguments = this.cachedMethodArguments; 765 if (cachedMethodArguments == null) { 766 return null; 767 } 768 Object[] arguments = new Object[cachedMethodArguments.length]; 769 for (int i = 0; i < arguments.length; i++) { 770 arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]); 771 } 772 return arguments; 773 } 774 } 775 776 777 /** 778 * DependencyDescriptor variant with a pre-resolved target bean name. 779 */ 780 @SuppressWarnings("serial") 781 private static class ShortcutDependencyDescriptor extends DependencyDescriptor { 782 783 private final String shortcut; 784 785 private final Class<?> requiredType; 786 787 public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) { 788 super(original); 789 this.shortcut = shortcut; 790 this.requiredType = requiredType; 791 } 792 793 @Override 794 public Object resolveShortcut(BeanFactory beanFactory) { 795 return beanFactory.getBean(this.shortcut, this.requiredType); 796 } 797 } 798 799}