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.context.annotation; 018 019import java.lang.annotation.Annotation; 020import java.lang.reflect.Method; 021import java.util.Collection; 022import java.util.Collections; 023import java.util.LinkedHashSet; 024import java.util.List; 025import java.util.Map; 026import java.util.Set; 027 028import org.springframework.aop.TargetSource; 029import org.springframework.aop.framework.ProxyFactory; 030import org.springframework.beans.factory.BeanFactory; 031import org.springframework.beans.factory.NoSuchBeanDefinitionException; 032import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver; 033import org.springframework.beans.factory.config.DependencyDescriptor; 034import org.springframework.beans.factory.support.DefaultListableBeanFactory; 035import org.springframework.core.MethodParameter; 036import org.springframework.core.annotation.AnnotationUtils; 037import org.springframework.lang.Nullable; 038import org.springframework.util.Assert; 039 040/** 041 * Complete implementation of the 042 * {@link org.springframework.beans.factory.support.AutowireCandidateResolver} strategy 043 * interface, providing support for qualifier annotations as well as for lazy resolution 044 * driven by the {@link Lazy} annotation in the {@code context.annotation} package. 045 * 046 * @author Juergen Hoeller 047 * @since 4.0 048 */ 049public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver { 050 051 @Override 052 @Nullable 053 public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) { 054 return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null); 055 } 056 057 protected boolean isLazy(DependencyDescriptor descriptor) { 058 for (Annotation ann : descriptor.getAnnotations()) { 059 Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class); 060 if (lazy != null && lazy.value()) { 061 return true; 062 } 063 } 064 MethodParameter methodParam = descriptor.getMethodParameter(); 065 if (methodParam != null) { 066 Method method = methodParam.getMethod(); 067 if (method == null || void.class == method.getReturnType()) { 068 Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class); 069 if (lazy != null && lazy.value()) { 070 return true; 071 } 072 } 073 } 074 return false; 075 } 076 077 protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) { 078 BeanFactory beanFactory = getBeanFactory(); 079 Assert.state(beanFactory instanceof DefaultListableBeanFactory, 080 "BeanFactory needs to be a DefaultListableBeanFactory"); 081 final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory; 082 083 TargetSource ts = new TargetSource() { 084 @Override 085 public Class<?> getTargetClass() { 086 return descriptor.getDependencyType(); 087 } 088 @Override 089 public boolean isStatic() { 090 return false; 091 } 092 @Override 093 public Object getTarget() { 094 Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null); 095 Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null); 096 if (target == null) { 097 Class<?> type = getTargetClass(); 098 if (Map.class == type) { 099 return Collections.emptyMap(); 100 } 101 else if (List.class == type) { 102 return Collections.emptyList(); 103 } 104 else if (Set.class == type || Collection.class == type) { 105 return Collections.emptySet(); 106 } 107 throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(), 108 "Optional dependency not present for lazy injection point"); 109 } 110 if (autowiredBeanNames != null) { 111 for (String autowiredBeanName : autowiredBeanNames) { 112 if (dlbf.containsBean(autowiredBeanName)) { 113 dlbf.registerDependentBean(autowiredBeanName, beanName); 114 } 115 } 116 } 117 return target; 118 } 119 @Override 120 public void releaseTarget(Object target) { 121 } 122 }; 123 124 ProxyFactory pf = new ProxyFactory(); 125 pf.setTargetSource(ts); 126 Class<?> dependencyType = descriptor.getDependencyType(); 127 if (dependencyType.isInterface()) { 128 pf.addInterface(dependencyType); 129 } 130 return pf.getProxy(dlbf.getBeanClassLoader()); 131 } 132 133}