@Autowired注入底层原理
常见的@Autowired有以下5种形式进行注入,下面模拟了Spring中对这5种形式的注入进行解析并写入Spring容器内。
1.根据成员变量的类型获取
2.根据方法中参数类型进行获取
3.结果包装为Optional<bean2>类型
4.结果包装为ObjectProvider
5.对@lazy进行处理
package com.example.springdemo.demos.a15;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.util.Optional;
@Configuration
public class TestAutowired {public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestAutowired.class);DefaultListableBeanFactory factory = context.getDefaultListableBeanFactory();//1.根据成员变量的类型获取DependencyDescriptor descriptor = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);System.out.println(factory.resolveDependency(descriptor, "bean1", null, null));//2.根据参数类型进行获取Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);DependencyDescriptor descriptor2 = new DependencyDescriptor(new MethodParameter(setBean2, 0),false);System.out.println(factory.doResolveDependency(descriptor2, "bean1", null, null));//3.结果包装为Optional<bean2>类型DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"),false);if(dd3.getDependencyType() == Optional.class){dd3.increaseNestingLevel();Object result = factory.doResolveDependency(dd3,"bean1",null,null);System.out.println(Optional.ofNullable(result));}//4.结果包装为ObjectProviderDependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"),false);if(dd4.getDependencyType() == ObjectFactory.class){dd4.increaseNestingLevel();ObjectFactory objectFactory = new ObjectFactory() {@Overridepublic Object getObject() throws BeansException {Object result = factory.doResolveDependency(dd4,"bena1",null,null);return result;}};System.out.println(objectFactory.getObject());}//5.对@lazy进行处理DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean5"),false);ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();resolver.setBeanFactory(factory);Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");System.out.println(proxy.getClass());}@Componentstatic class Bean1 {@Autowiredprivate Bean2 bean2;@Autowiredpublic void setBean2(Bean2 bean2){this.bean2 = bean2;}@Autowiredprivate Optional<Bean2> bean3;@Autowiredprivate ObjectFactory<Bean2> bean4;@Autowired @Lazyprivate Bean3 bean5;}@Component("bean2")static class Bean2 {private String name;}@Component("bean3")static class Bean3 {private String name;}
}
第一种方式:
通过成员变量的类型获取并注入@Autowired底层。DependencyDescriptor descriptor = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);Spring底层通过这个类进行依赖解析,后面都用到了这种方式。
第二种方式:
通过根据方法里面的参数类型进行获取。
第三种方式:
获取包装类里面的bean2,首先拿到Optional<bean2>,后面dd3.increaseNestingLevel()增加了嵌套层级,使得可以进一步对Optional<bean2>里面的bean2进行解析。
第四种方式:
注入的对象是 ObjectFactory<Bean2> bean4的形式。通过下面的方式获取到ObjectFactory工厂对象里面的Bean2对象。可以延迟加载Bean2,等真正需要的时候才去获取。
ObjectFactory objectFactory = new ObjectFactory() {@Overridepublic Object getObject() throws BeansException {Object result = factory.doResolveDependency(dd4,"bena1",null,null);return result;}};
第五种方式:
配合使用了@Lazy的成员变量,通过ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver()解析@Lazy,获得代理对象。
测试结果:
可以看到以上方式都正常解析并注入到Spring容器中了。