入口分析
先回顾一下上节@Autowired注解注入,寻找注入点的方法:
AutowiredFieldElement:字段对应的注入点
AutowiredMethodElement:方法对应的注入点
并且是针对@Autowired、@Value、@Inject注解标记的字段或方法:
注入点注入入口:
org.springframework.beans.factory.annotation.InjectionMetadata#inject
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
//遍历每个注入点进行依赖注入,有可能是字段,也有可能是方法
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
根据字段、方法有不同的实现,依次看一下
字段注入:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
//优先从缓存取,先不看
if (this.cached) {...}
else {
//根据field从BeanFactory中查到的匹配的Bean对象
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
//反射给field赋值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
//构造依赖描述符对象
// DependencyDescriptor:描述符用于即将被注入的特定依赖项。包装构造函数参数、方法参数或字段,允许统一访问它们的元数据。
// this.required:@Autowired的required属性
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
//autowiredBeanNames(在后续执行过程中会)记录当前Bean需要注入的Bean的BeanName
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
//类型转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
//核心方法,从工厂中解析依赖项要注入的值
//针对这个工厂中定义的bean解析指定的依赖项
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {...}
//后面是将结果缓存,先不看
synchronized (this) {...}
return value;
}
核心方法是AutowireCapableBeanFactory#resolveDependency
方法注入:
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//如果pvs中已经有当前注入点的值了,则跳过注入
if (checkPropertySkipping(pvs)) {
return;
}
Method method = (Method) this.member;
Object[] arguments;
//有缓存先从缓存取,暂时不看
if (this.cached) {...}
else {
//当前是方法入注,这里会解析方法入参
arguments = resolveMethodArguments(method, bean, beanName);
}
if (arguments != null) {
try {
//反射调用方法
ReflectionUtils.makeAccessible(method);
method.invoke(bean, arguments);
}
catch (InvocationTargetException ex) {...}
}
}
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#resolveMethodArguments
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
//方法有可能有多个参数,所以这里都是数组
int argumentCount = method.getParameterCount();
Object[] arguments = new Object[argumentCount];
DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
//autowiredBeanNames记录了当前Bean需要注入的Bean的BeanName
Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
Assert.state(beanFactory != null, "No BeanFactory available");
//类型转换器
TypeConverter typeConverter = beanFactory.getTypeConverter();
//遍历每个方法参数,找到匹配的bean对象
for (int i = 0; i < arguments.length; i++) {
//i是索引,代表方法上的第几个参数
MethodParameter methodParam = new MethodParameter(method, i);
//构造依赖描述符(对于方法入注,多个参数情况就会对应多个依赖描述符)
DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
currDesc.setContainingClass(bean.getClass());
descriptors[i] = currDesc;
try {
//看到也是调用了beanFactory.resolveDependency
//核心方法,从工厂中解析依赖项要注入的值
//针对这个工厂中定义的bean解析指定的依赖项
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
if (arg == null && !this.required) {
arguments = null;
break;
}
//每个参数对应的要传入的值
arguments[i] = arg;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
}
}
//缓存逻辑,和字段注入差不多,暂时不看
synchronized (this) {...}
return arguments;
}
}
可以看到,无论是字段注入,还是方法注入,解析依赖项要注入的值都调用了org.springframework.beans.factory.config.AutowireCapableBeanFactory#resolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, java.lang.String, java.util.Set<java.lang.String>, org.springframework.beans.TypeConverter)
从工厂解析依赖项
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//descriptor可能是字段,也可能是普通方法、构造方法中的一个参数
//1.初始化参数名字发现器,用来获取方法入参名字的
// 如果是字段注入,拿字段的类型和字段的名字比较简单
// 但是方法注入,拿方法参数的类型简单,但是拿方法参数的名字就比较复杂
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
//接下来会判断 字段/方法参数 的类型,走不同的逻辑:
// 2. 处理Optional类型的依赖注入
if (Optional.class == descriptor.getDependencyType()) {
//为指定的依赖项创建可选包装器。
return createOptionalDependency(descriptor, requestingBeanName);
}
// 3. 处理ObjectFactory和ObjectProvider类型的依赖注入
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
//可序列化的ObjectFactory/ObjectProvider用于延迟解析依赖项。
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// 处理JSR330 相关的依赖注入
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
//4. 查找具体的依赖注入对象(最常见)
//4.1 判断是否是懒注入
// 在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
//4.2 真正开始解析依赖项,核心是doResolveDependency
// descriptor表示某个字段属性、或某个方法上的某个入参
// requestingBeanName表示当前正在进行依赖注入的Bean
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
1. 初始化参数名字发现器
在jdk1.7中,拿方法入参类型有直接的api,但是获取参数名字没有直接提供api:
而1.8提供了getParameters方法可以获取Parameter,但是getName名字并不是我们期望的:
还需要配置一个编译时期的参数:
刷新一下maven,并重新编译以后再次执行:
上面可以看出,java反射层面其实并没有什么比较方便的api可以拿到方法入参到名字,那Spring是如何拿到的呢?默认支持两种方式,一个是上面说的反射,另一个是利用了一些字节码层面的技术,直接分析字节码内容是可以拿到的。
看Spring源码:
org.springframework.beans.factory.config.DependencyDescriptor#initParameterNameDiscovery
//这个方法比较简单,就是set赋值
public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) {
if (this.methodParameter != null) {
this.methodParameter.initParameterNameDiscovery(parameterNameDiscoverer);
}
}
//org.springframework.core.MethodParameter#initParameterNameDiscovery
public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
获取参数名字发现器:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getParameterNameDiscoverer
protected ParameterNameDiscoverer getParameterNameDiscoverer() {
return this.parameterNameDiscoverer;
}
有默认实现提供:
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
public DefaultParameterNameDiscoverer() {
// TODO Remove this conditional inclusion when upgrading to Kotlin 1.5, see https://youtrack.jetbrains.com/issue/KT-44594
if (KotlinDetector.isKotlinReflectPresent() && !NativeDetector.inNativeImage()) {
addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
}
//看到有两个具体的实现,会依次调用Discoverer来获取某个方法的参数名
//StandardReflectionParameterNameDiscoverer:它使用JDK 8的反射功能来内省参数名(基于“-parameters”编译器标志)。
addDiscoverer(new StandardReflectionParameterNameDiscoverer());
//LocalVariableTableParameterNameDiscoverer:使用ObjectWeb的ASM库来分析类文件。
//解析字节码文件,使用方法属性中的LocalVariableTable信息来发现参数名称。
addDiscoverer(new LocalVariableTableParameterNameDiscoverer());
}
}
优先利用反射去拿,如果运行环境是jdk1.7或者jdk1.8没有设置编译参数,有可能拿不到,再利用字节码中的本地变量表去拿。
小仙女讲JVM(4)—类文件结构
2. 处理Optional类型的依赖注入
org.springframework.beans.factory.support.DefaultListableBeanFactory#createOptionalDependency
private Optional<?> createOptionalDependency(
DependencyDescriptor descriptor, @Nullable String beanName, final Object... args) {
DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
@Override
public boolean isRequired() {
return false;
}
@Override
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :
super.resolveCandidate(beanName, requiredType, beanFactory));
}
};
//4.2 核心是doResolveDependency,真正开始解析依赖项
Object result = doResolveDependency(descriptorToUse, beanName, null, null);
//最终返回结果如果不是Optional,会用Optional再包装一下
return (result instanceof Optional ? (Optional<?>) result : Optional.ofNullable(result));
}
3. 处理ObjectFactory和ObjectProvider类型的依赖注入
org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider#getObject()
public Object getObject() throws BeansException {
if (this.optional) {
//2. 处理Option类型的依赖注入
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
//4.2 核心还是doResolveDependency,真正开始解析依赖项
Object result = doResolveDependency(this.descriptor, this.beanName, null, null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
return result;
}
}
延迟依赖查找功能,只有当使用者调用ObjectProvider#getObject()方法时,才会通过依赖查找的方式获取对应的Bean
Bean的延迟依赖查找功能,ObjectFactory 和 ObjectProvider
4. 查找具体的依赖注入对象
4.1 判断是否是懒注入
@Lazy注解可以加在类上、字段上,也可以加在方法入参上
//4.1 判断是否是懒注入
// 在属性或set方法上使用了@Lazy注解,那么则构造一个代理对象并返回,真正使用该代理对象时才进行类型筛选bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
//4.2 真正开始解析依赖项,核心是doResolveDependency
// descriptor表示某个字段属性、或某个方法上的某个入参
// requestingBeanName表示当前正在进行依赖注入的Bean
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
getAutowireCandidateResolver默认返回的是ContextAnnotationAutowireCandidateResolver
org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary
//判断是不是懒注入(@Autowired + @Lazy),如果是,则会在注入时先生成一个代理对象注入给属性
//所以懒注入并不代表属性为null
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
//不是懒注入,则返回null,否则创建一个代理对象
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
}
判断是否是懒注入
判断是否有@Lazy注解,且value是true:
org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#isLazy
protected boolean isLazy(DependencyDescriptor descriptor) {
//1.参数级别获取注解
//获取与被包装的字段或方法/构造函数参数关联的注解
for (Annotation ann : descriptor.getAnnotations()) {
Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
if (lazy != null && lazy.value()) {
return true;
}
}
//2.方法级别获取注解
//判断方法/构造函数上的注解
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
//该方法公开在方法/构造函数本身上声明的注解(即在方法/构造函数级别,而不是在参数级别)。
Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
if (lazy != null && lazy.value()) {
return true;
}
}
}
return false;
}
注意虽然MethodParameter代表的是方法上的某一个参数,但是methodParam.getAnnotatedElement()返回的是方法上的注解,非参数级别的。
创建懒注入的代理对象
动态代理,不是本节重点,以后讲SpringAOP的时候会细说。
只要知道这里会生成一个代理对象即可,当真正执行方法的时候才会去解析依赖项。
org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver#buildLazyResolutionProxy
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
BeanFactory beanFactory = getBeanFactory();
Assert.state(beanFactory instanceof DefaultListableBeanFactory,
"BeanFactory needs to be a DefaultListableBeanFactory");
final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;
TargetSource ts = new TargetSource() {
//被代理对象类型
@Override
public Class<?> getTargetClass() {
return descriptor.getDependencyType();
}
//是否是静态的:true,则每次调用getTarget()返回的都是相同的对象
@Override
public boolean isStatic() {
return false;
}
//获取被代理对象
@Override
public Object getTarget() {
Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
//4.2 核心还是doResolveDependency,真正开始解析依赖项
Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
if (target == null) {...}
if (autowiredBeanNames != null) {...}
return target;
}
@Override
public void releaseTarget(Object target) {...}
};
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
//生成一个代理对象
return pf.getProxy(dlbf.getBeanClassLoader());
}
一开始只会赋值一个代理对象,当真正使用这个对象执行其方法的时候,作为一个代理对象,最终肯定会去拿到被代理对象,执行被代理对象对应的方法,所以就会调用org.springframework.aop.TargetSource#getTarget这个方法拿到被代理对象,而在这个方法中才会真正解析依赖项:
4.2 真正开始解析依赖项(最核心方法)
篇幅过长,下一节讲。