第四十七讲-Autowired注入底层
第四十七讲-Autowired注入底层
本讲我们来讲一下@Autowired注入底层
我们都知道@Autowired注入是按照类型来进行装配(注入)的,它要支持各种各样的类型,这就决定了@Autowired的实现非常的复杂。
我们来看一个例子:
@Configuration
public class A47_1 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_1.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
}
static class Bean1 {
@Autowired
private Bean2 bean2;
@Autowired
public void setBean2(@Lazy Bean2 bean2) {
this.bean2 = bean2;
}
@Autowired
private Optional<Bean2> bean3;
@Autowired
private ObjectFactory<Bean2> bean4;
}
@Component("bean2")
static class Bean2 {
@Override
public String toString() {
return super.toString();
}
}
}
1. 根据成员变量的类型注入
// 1. 根据成员变量的类型注入
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"),false);
System.out.println(beanFactory.doResolveDependency(dd1, "bean1", null, null));
运行结果如下:
com.cherry.springa47.A47_1$Bean2@7671cb68
根据成员变量的类型注入(装配)成功
2. 根据方法参数的类型注入
// 2. 根据参数的类型注入
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2,0),false);
System.out.println(beanFactory.doResolveDependency(dd2, "bean1", null, null));
运行结果如下:
com.cherry.springa47.A47_1$Bean2@7671cb68
根据方法参数的类型注入(装配)成功
3. 结果包装类为Optional<Bean2>
有时候@Autowired注入后的类型为包装后的类型,例如下面的代码:
// 3. 结果包装类为Optional\<Bean2>
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
if (dd3.getDependencyType() == Optional.class){
System.out.println(dd3.getDependencyType());
dd3.increaseNestingLevel(); // 增加一层内嵌,找到optional中内嵌的类型,也就是泛型的类型
System.out.println(dd3.getDependencyType());
Object result = beanFactory.doResolveDependency(dd3, "bean1", null, null);
Optional.ofNullable(result);
System.out.println(result);
}
运行结果如下:
class java.util.Optional
class com.cherry.springa47.A47_1$Bean2
com.cherry.springa47.A47_1$Bean2@7671cb68
根据包装类的内部类类型注入(装配)成功
4. 结果包装为ObjectProvider,ObjectFactory
其实这和上面的Optional类型差不多了,具体代码看下面的例子:
// 4. 结果包装为ObjectProvider,ObjectFactory
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
if (dd4.getDependencyType() == ObjectFactory.class){
dd4.increaseNestingLevel();
// 将bean工厂注入给成成员变量bean4,当bean4调用getObject()方法才会创建Bean2对象的创建,也就是说推迟了Bean2对象的创建
ObjectFactory objectFactory = new ObjectFactory() {
@Override
public Object getObject() throws BeansException {
return beanFactory.doResolveDependency(dd4, "bean1", null, null);
}
};
System.out.println(objectFactory.getObject());
}
运行结果如下:
com.cherry.springa47.A47_1$Bean2@7671cb68
我们发现,也正确获得了Bean2对象
5. 对@Lazy的处理
@Lazy注解既可以加在成员变量上,也可以加在方法参数上,作用就是创建一个代理对象,将来访问代理对象的方法时才会获取真实的对象,其作用和ObjectFactory类似,推迟对代理对象的获取。
如下面的代码,我们将bean成员变量加上@Lazy注解:
static class Bean1 {
@Autowired
@Lazy
private Bean2 bean2;
//......
}
// 对@Lazy的处理
DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
// 解析@Autowired和@Lazy注解
// 如果成员变量或方法参数上加上了@Lazy注解,该解析器就会帮助我们创建一个代理对象
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
//检查成员变量或方法上有没有@Lazy注解,如果有,则会帮我们创建出代理类对象
Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
System.out.println(proxy);
System.out.println(proxy.getClass());
}
运行结果如下:
com.cherry.springa47.A47_1$Bean2@6b8ca3c8
class com.cherry.springa47.A47_1$Bean2$$SpringCGLIB$$0
@SuppressWarnings("all")
@Configuration
public class A47_2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_2.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. 数组类型");
testArray(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. List 类型");
testList(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. applicationContext");
testApplicationContext(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4. 泛型");
testGeneric(beanFactory);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>> 5. @Qualifier");
testQualifier(beanFactory);
/*
学到了什么
1. 如何获取数组元素类型
2. Spring 如何获取泛型中的类型
3. 特殊对象的处理, 如 ApplicationContext, 并注意 Map 取值时的类型匹配问题 (另见 TestMap)
4. 谁来进行泛型匹配 (另见 TestGeneric)
5. 谁来处理 @Qualifier
6. 刚开始都只是按名字处理, 等候选者确定了, 才会创建实例
*/
}
// @Qualifier注解:根据bean的名字进行匹配并注入注入(装饰)bean
private static void testQualifier(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd5 = new DependencyDescriptor(Target.class.getDeclaredField("service"), true);
Class<?> type = dd5.getDependencyType();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
// @Qualifier("service2")
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,name), dd5)) {
System.out.println(name);
System.out.println(dd5.resolveCandidate(name, type, beanFactory));
}
}
}
// Dao接口中的泛型Bean对象
private static void testGeneric(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd4 = new DependencyDescriptor(Target.class.getDeclaredField("dao"), true);
Class<?> type = dd4.getDependencyType();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
BeanDefinition bd = beanFactory.getMergedBeanDefinition(name);
// 对比 BeanDefinition 与 DependencyDescriptor 的泛型是否匹配
if (resolver.isAutowireCandidate(new BeanDefinitionHolder(bd,name), dd4)) {
System.out.println(name);
System.out.println(dd4.resolveCandidate(name, type, beanFactory));
}
}
}
// ConfigurableApplicationContext 存储bean对象
private static void testApplicationContext(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException, IllegalAccessException {
DependencyDescriptor dd3 = new DependencyDescriptor(Target.class.getDeclaredField("applicationContext"), true);
Field resolvableDependencies = DefaultListableBeanFactory.class.getDeclaredField("resolvableDependencies");
resolvableDependencies.setAccessible(true);
Map<Class<?>, Object> dependencies = (Map<Class<?>, Object>) resolvableDependencies.get(beanFactory);
// dependencies.forEach((k, v) -> {
// System.out.println("key:" + k + " value: " + v);
// });
for (Map.Entry<Class<?>, Object> entry : dependencies.entrySet()) {
// 左边类型 右边类型
if (entry.getKey().isAssignableFrom(dd3.getDependencyType())) {
System.out.println(entry.getValue());
break;
}
}
}
// 使用List集合存储bean对象
private static void testList(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
// 是否List集合类型
if (dd2.getDependencyType() == List.class) {
// 获取集合中的元素类型
Class<?> resolve = dd2.getResolvableType().getGeneric().resolve();
System.out.println(resolve);
List<Object> list = new ArrayList<>();
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, resolve);
for (String name : names) {
Object bean = dd2.resolveCandidate(name, resolve, beanFactory);
list.add(bean);
}
System.out.println(list);
}
}
// 使用数组存储bean对象
private static void testArray(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd1 = new DependencyDescriptor(Target.class.getDeclaredField("serviceArray"), true);
// 判断拿到的是不是数组类型
if (dd1.getDependencyType().isArray()) {
// 拿到数组中的元素类型
Class<?> componentType = dd1.getDependencyType().getComponentType();
System.out.println(componentType);
// 查找当前容器与所有祖先bean的名字
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);
List<Object> beans = new ArrayList<>();
for (String name : names) {
// 同样根据bean name 找到bean
System.out.println(name);
// 根据bean的名字找到bean对象
Object bean = dd1.resolveCandidate(name, componentType, beanFactory);
beans.add(bean);
}
Object array = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
System.out.println(array);
}
}
static class Target {
@Autowired private Service[] serviceArray;
@Autowired private List<Service> serviceList;
@Autowired private ConfigurableApplicationContext applicationContext;
@Autowired private Dao<Teacher> dao;
@Autowired @Qualifier("service2") private Service service;
}
interface Dao<T> {
}
@Component("dao1") static class Dao1 implements Dao<Student> { }
@Component("dao2") static class Dao2 implements Dao<Teacher> { }
static class Student { }
static class Teacher { }
interface Service { }
@Component("service1")
static class Service1 implements Service { }
@Component("service2")
static class Service2 implements Service { }
@Component("service3")
static class Service3 implements Service { }
}
运行结果如下:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. 数组类型
interface com.cherry.springa47.A47_2$Service
service3
service2
service1
[Lcom.cherry.springa47.A47_2$Service;@41e1e210
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. List 类型
interface com.cherry.springa47.A47_2$Service
[com.cherry.springa47.A47_2$Service3@15bbf42f, com.cherry.springa47.A47_2$Service2@550ee7e5, com.cherry.springa47.A47_2$Service1@5f9b2141]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. applicationContext
org.springframework.beans.factory.support.DefaultListableBeanFactory@7fc229ab: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,a47_2,service3,service2,service1,dao2,dao1]; root of factory hierarchy
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4. 泛型
dao2
com.cherry.springa47.A47_2$Dao2@7ea9e1e2
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 5. @Qualifier
service2
com.cherry.springa47.A47_2$Service2@550ee7e5
package com.cherry.springa47;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Configuration
public class A47_3 {
public static void main(String[] args) throws NoSuchFieldException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(A47_3.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
testPrimary(beanFactory);
testDefault(beanFactory);
/*
学到了什么
1. @Primary 的处理, 其中 @Primary 会在 @Bean 解析或组件扫描时被解析 (另见 TestPrimary)
2. 最后的防线, 通过属性或参数名匹配
*/
}
private static void testDefault(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd = new DependencyDescriptor(Target2.class.getDeclaredField("service3"), false);
Class<?> type = dd.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
if(name.equals(dd.getDependencyName())) {
System.out.println(name);
}
}
}
private static void testPrimary(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd = new DependencyDescriptor(Target1.class.getDeclaredField("service"), false);
Class<?> type = dd.getDependencyType();
for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, type)) {
// 判断类上是否加了@Primary注解,如果加了,打印出该bean的名字
if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
System.out.println(name);
}
}
}
static class Target1 {
@Autowired private Service service;
}
// 如果既不加@Primary注解,也不加@Qualified注解,那么Spring还有最后一道防线,就是根据成员变量的名字与bean的名字来进行匹配!!!
// 如果匹配的上,则会优先选择匹配上的名字的bean装配(注入)
static class Target2 {
@Autowired private Service service3;
}
/**
* @Primary注解相比于@Qualifier注解优先级较低,也能解决@Qualifier解决的问题
* @Qualifier注解用于解决当依赖项(注入点)存在多个候选bean时的二义性问题。
* 当你有两个或更多的bean可以满足同一个依赖关系时,@Qualifier可以帮助指定应该使用哪一个bean。
*
*/
interface Service { }
@Component("service1") static class Service1 implements Service { }
@Component("service2") @Primary static class Service2 implements Service { }
@Component("service3") static class Service3 implements Service { }
}
分类:
Spring 高级49讲
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构