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