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