笔记参考B站黑马程序员视频:spring原理
1.@Value模拟实现
我们先提供需要读取的Bean
package com.dreams.demo46;
import org.springframework.beans.factory.annotation.Value;
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.stereotype.Component;
import java.lang.reflect.Field;
@Configuration
@SuppressWarnings("all")
public class Demo {
public static void main(String[] args) throws Exception {
//......
}
public class Bean1 {
@Value("${JAVA_HOME}")
private String home;
@Value("18")
private int age;
}
public class Bean2 {
@Value("#{@bean3}") // SpringEL #{SpEL}
private Bean3 bean3;
}
@Component("bean3")
public class Bean3 {
}
static class Bean4 {
@Value("#{'hello, ' + '${JAVA_HOME}'}")
private String value;
}
}要读取@Value注解的逻辑在main方法中
先创建一个基于注解配置的Spring应用上下文,这已经包括了很多Bean处理器
ContextAnnotationAutowireCandidateResolver 来获取 @Value 注解中定义的属性值,并在需要时解析占位符。
getSuggestedValue方法:使用解析器 resolver 获取了 DependencyDescriptor 中对应字段的值,这里需要传入DependencyDescriptor 对象,描述了 Bean1 类中名为 home 的字段。
这样最后就可以使用应用上下文的环境对象 context.getEnvironment() 来解析字符串中的 ${} 占位符,将其替换为实际的属性值。
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Field field = Bean1.class.getDeclaredField("home");
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();
System.out.println(value);
// 解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
}
上面读取到的默认是字符串类型,对于读取非字符串属性:
通过 getTypeConverter().convertIfNecessary() 方法将解析后的属性值 value 转换为 dd1 所描述的字段 age 的类型,并打印转换后的对象的类型信息。
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Field field = Bean1.class.getDeclaredField("age");
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();
System.out.println(value);
// 解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
System.out.println(value.getClass());
Object age = context.getBeanFactory().getTypeConverter().convertIfNecessary(value, dd1.getDependencyType());
System.out.println(age.getClass());
}
还有一种情况是
#{} 表示后面跟着的是 Spring Expression Language (SpEL) 表达式。@bean3 是一个 SpEL 表达式,它的含义是要从 Spring 容器中获取一个名为 bean3 的 Bean,并将其注入到当前属性 bean3 中。
public class Bean2 {
@Value("#{@bean3}") // SpringEL #{SpEL}
private Bean3 bean3;
}
context.getBeanFactory().getBeanExpressionResolver().evaluate(value, …) 方法用于解析 #{} 中的 SpEL 表达式,并获取其结果。
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Field field = Bean2.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(field, false);
// 获取 @Value 的内容
String value = resolver.getSuggestedValue(dd1).toString();
System.out.println(value);
// 解析 ${}
value = context.getEnvironment().resolvePlaceholders(value);
System.out.println(value);
System.out.println(value.getClass());
// 解析 #{} @bean3
Object bean3 = context.getBeanFactory().getBeanExpressionResolver().evaluate(value, new BeanExpressionContext(context.getBeanFactory(), null));
// 类型转换
Object result = context.getBeanFactory().getTypeConverter().convertIfNecessary(bean3, dd1.getDependencyType());
System.out.println(result);
}
同样上面的代码就能解决这种Bean
static class Bean3 {
@Value("#{'hello, ' + '${JAVA_HOME}'}")
private String value;
}
2.@Autowired模拟实现
同样模拟一下@Autowired的实现
不同Bean注入
先准备要通过@Autowired注入的Bean
package com.dreams.demo47;
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 Demo {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
// ......
}
static class Bean1 {
@Autowired @Lazy private Bean2 bean2;
@Autowired public void setBean2(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();
}*/
}
}主要逻辑在main方法中
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo.class);
DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 1. 根据成员变量的类型注入
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
System.out.println(beanFactory.doResolveDependency(dd1, "bean1", null, null));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 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));
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 3. 结果包装为 Optional<Bean2>
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
if (dd3.getDependencyType() == Optional.class) {
dd3.increaseNestingLevel();
Object result = beanFactory.doResolveDependency(dd3, "bean1", null, null);
System.out.println(Optional.ofNullable(result));
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 4. 结果包装为 ObjectProvider,ObjectFactory
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"), false);
if (dd4.getDependencyType() == ObjectFactory.class) {
dd4.increaseNestingLevel();
ObjectFactory objectFactory = new ObjectFactory() {
@Override
public Object getObject() throws BeansException {
return beanFactory.doResolveDependency(dd4, "bean1", null, null);
}
};
System.out.println(objectFactory.getObject());
}
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
// 5. 对 @Lazy 的处理
DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
System.out.println(proxy);
System.out.println(proxy.getClass());
}
代码解释:
1. 注入成员变量类型的依赖
创建一个依赖描述符(DependencyDescriptor),用于描述要注入的依赖,doResolveDependency 方法用于根据依赖描述符 dd1,解析和实现 Bean1 中 bean2 成员变量的依赖注入。通过 beanFactory 解析并解决依赖。
// 1. 根据成员变量的类型注入
DependencyDescriptor dd1 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
System.out.println(beanFactory.doResolveDependency(dd1, "bean1", null, null));对应读取是bean2


2. 根据参数的类型注入
使用 MethodParameter 类创建了一个 DependencyDescriptor 对象 dd2,用于描述 setBean2 方法的第一个(index 为 0)参数,使用 Bean1.class.getDeclaredMethod(“setBean2”, Bean2.class) 获取了 Bean1 类中设置 Bean2 的方法 setBean2。
// 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));读取这个


3. 结果包装为 Optional<Bean2>
也就是我们要找内嵌的属性

使用 Bean1.class.getDeclaredField(“bean3”) 创建了一个 DependencyDescriptor 对象 dd3,用于描述 Bean1 类中名为 bean3 的字段的依赖。然后使用 dd3.getDependencyType() 方法检查依赖的类型是否是 Optional。调用 dd3.increaseNestingLevel() 增加嵌套级别,这告诉 Spring 在解析依赖时应该返回一个 Optional 包装的类型,而不是直接的 Bean2 对象,然后使用 beanFactory.doResolveDependency(dd3, “bean1”, null, null) 方法解析依赖并获取结果。使用 beanFactory.doResolveDependency(dd3, “bean1”, null, null) 方法解析依赖并获取结果。
// 3. 结果包装为 Optional<Bean2>
DependencyDescriptor dd3 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean3"), false);
if (dd3.getDependencyType() == Optional.class) {
dd3.increaseNestingLevel();
Object result = beanFactory.doResolveDependency(dd3, "bean1", null, null);
System.out.println(Optional.ofNullable(result));
}
4. 结果包装为 ObjectProvider,ObjectFactory
处理为工厂方法

创建了一个匿名内部类实现 ObjectFactory 接口,重写了 getObject() 方法。
在 getObject() 方法中,调用 beanFactory.doResolveDependency() 解析依赖,并返回解析后的对象。
也就是说我们将工厂注入到属性里,然后后面使用这个属性也就是这个工厂的getObject方法时,Bean2才创建。
// 4. 结果包装为 ObjectProvider,ObjectFactory
DependencyDescriptor dd4 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean4"), false);
if (dd4.getDependencyType() == ObjectFactory.class) {
dd4.increaseNestingLevel();
ObjectFactory objectFactory = new ObjectFactory() {
@Override
public Object getObject() throws BeansException {
return beanFactory.doResolveDependency(dd4, "bean1", null, null);
}
};
System.out.println(objectFactory.getObject());
}
5. 对 @Lazy 的处理
要处理加了@Lazy的属性

ContextAnnotationAutowireCandidateResolver 就是负责解析 @Lazy 注解。它能够识别标记为 @Lazy 的 bean,并在需要时生成代理对象,以实现延迟加载的效果。
调用 resolver.getLazyResolutionProxyIfNecessary(dd5, “bean1”) 方法,该方法用于根据依赖描述符和 bean 名称获取延迟解析的代理对象。也就是如果有@Lazy 注解就创建代理。
// 5. 对 @Lazy 的处理
DependencyDescriptor dd5 = new DependencyDescriptor(Bean1.class.getDeclaredField("bean2"), false);
ContextAnnotationAutowireCandidateResolver resolver = new ContextAnnotationAutowireCandidateResolver();
resolver.setBeanFactory(beanFactory);
Object proxy = resolver.getLazyResolutionProxyIfNecessary(dd5, "bean1");
System.out.println(proxy);
System.out.println(proxy.getClass());
doResolveDependency类型匹配
这里模拟实现doResolveDependency类型匹配
package com.dreams.demo47;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@SuppressWarnings("all")
@Configuration
public class Demo2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Demo2.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);
}
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 {
}
}
先看处理数组的方法testArray

getDependencyType().isArray() 检查依赖类型是否为数组类型,getComponentType() 返回数组的组件类型,beanNamesForTypeIncludingAncestors() 根据给定的组件类型 componentType 在Bean工厂中获取所有符合条件的Bean名称。然后对于每个符合条件的Bean名称,使用 resolveCandidate() 方法获取对应的Bean实例(实际就是调用beanFactroy的getBean方法),并将其添加到 beans 列表中,最后使用 getTypeConverter() 获取类型转换器,并将 beans 列表转换为指定的数组类型 dd1.getDependencyType()。
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);
String[] names = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, componentType);
List<Object> beans = new ArrayList<>();
for (String name : names) {
System.out.println(name);
Object bean = dd1.resolveCandidate(name, componentType, beanFactory);
beans.add(bean);
}
Object array = beanFactory.getTypeConverter().convertIfNecessary(beans, dd1.getDependencyType());
System.out.println(array);
}
}
再来就是处理List集合testList方法

getDependencyType() == List.class 检查依赖的确是 List 类型。getResolvableType().getGeneric().resolve() 获取泛型参数的实际类型。比如 List<Service>,然后获取 Service 类的 Class 对象。beanNamesForTypeIncludingAncestors() 根据给定的类型 resolve 在Bean工厂中获取所有符合条件的Bean名称。对于每个符合条件的Bean名称,使用 resolveCandidate() 方法解析对应的Bean实例,并将其添加到 list 列表中。
private static void testList(DefaultListableBeanFactory beanFactory) throws NoSuchFieldException {
DependencyDescriptor dd2 = new DependencyDescriptor(Target.class.getDeclaredField("serviceList"), true);
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);
for (Object o : list) {
System.out.println(o);
}
}
}
接下来就是处理不是容器中的Bean了

如果是普通的Bean会存储在DefaultListableBeanFactory的属性singletonObjects,这个属性定义在DefaultListableBeanFactory的比较顶层的父类DefaultSingletonBeanRegistry

key是Bean的名字,value是Bean的实例

而ConfigurableApplicationContext这些不会放在这里
回到DefaultListableBeanFactory
会放在DefaultListableBeanFactory的属性resolvableDependencies中
key是对象的类型,value是对象

他在AbstractApplicationContext的refresh()方法的prepareBeanFactory(beanFactory)里被赋值

可以看到它加入了很多类型

我们通过反射获取
使用反射获取了 DefaultListableBeanFactory 类的 resolvableDependencies 字段。获取 resolvableDependencies 的值后,将其强制转换为 Map<Class<?>, Object> 类型。isAssignableFrom 方法检查 entry.getKey() 是否可以赋值给 dd3.getDependencyType(),如果是,则打印输出 entry.getValue()。
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;
}
}
}
接下来是解析加了泛型的接口

使用 BeanFactoryUtils.beanNamesForTypeIncludingAncestors 方法遍历 beanFactory 中与 type 类型匹配的所有 Bean 名称。
对于每个 Bean 名称,获取其 BeanDefinition 并存储在 bd 中。
使用 resolver.isAutowireCandidate 方法检查该 BeanDefinition 是否可以自动装配到 dd4 描述的依赖。
如果可以自动装配,则打印输出该 Bean 的名称,并通过 dd4.resolveCandidate 方法解析出该 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));
}
}
}
然后就是匹配@Qualifier(“service2”) 了

同样使用 resolver.isAutowireCandidate(new BeanDefinitionHolder(bd, name), dd5) 方法判断该 Bean 是否适合作为 dd5 描述的依赖项的自动装配候选项。@Qualifier(“service2”)就是在这里被解析
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));
}
}
}
spring底层会先查看有没有@Qualifier注解

没有就查看@Primary注解

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)) {
if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
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)) {
if (beanFactory.getMergedBeanDefinition(name).isPrimary()) {
System.out.println(name);
}
}
}
如果都没有,就无法区别该匹配哪一个就会报错。
3.参考
B站黑马程序员视频:spring原理


