Spring 5.x Source trip twenty six Detailed getBean
Create a parameter holding unit
I used the example of two factory methods do, in fact, their differences are the same, will complain, it does not matter, we mainly analyze the process works:
First, go get the name of the parameter name parameter probe, in fact, inside is ASM
read byte code to operate, mainly LocalVariableTableParameterNameDiscoverer
the class, binary stream to read class
the file, and then analyze more complex, are interested can see. Our analysis methods directly on the core of it.
createArgumentArray
Leaving a general case, does not include a xml
setting mode or parameter values manually set ConstructorArgumentValues
, it is the most common form. The number of parameters, traversing parameters, this will involve the index parameter paramIndex
matter, xml
there will be used, first, the factory method (constructor) and packaged into a common index MethodParameter
type of treatment, followed by automatic assembly, parses the parameter object , which is very complicated, said that while the last to be registered and are dependent dependent bean
, in fact, do caching, the next can be used directly.
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
//类型转换器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);//参数持有器
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);//构造器参数值集合
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);//装配的bean名字
//带参数的话
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
String paramName = (paramNames != null ? paramNames[paramIndex] : "");//获取参数名字
// Try to find matching constructor argument value, either indexed or generic.
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
...
}
if (valueHolder != null) {
...
}
else {
//获取统一的方法参数类型
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
if (!autowiring) {
throw new UnsatisfiedDependencyException(
...
}
try {//解析自动装配参数,找到会进行实例化
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = autowiredArgumentMarker;
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
}
}
//注册依赖的bean
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
if (logger.isDebugEnabled()) {
logger.debug("Autowiring by type from bean name '" + beanName +
"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
" to bean named '" + autowiredBeanName + "'");
}
}
return args;
}
A method of packaging parameters MethodParameter forExecutable
This is the process plant for methods and constructors together into a common form, to facilitate later unitary.
public static MethodParameter forExecutable(Executable executable, int parameterIndex) {
if (executable instanceof Method) {
return new MethodParameter((Method) executable, parameterIndex);
}
else if (executable instanceof Constructor) {
return new MethodParameter((Constructor<?>) executable, parameterIndex);
}
else {
throw new IllegalArgumentException("Not a Method/Constructor: " + executable);
}
}
MethodParameter constructor
In fact, the method and the index set in, there is a nested layer, such as list
in nested list
this, temporarily do not control, we still according to the general, the nesting is the layer that is 1
, if not 1
, go back inside to find embedded set type.
public MethodParameter(Method method, int parameterIndex, int nestingLevel) {
Assert.notNull(method, "Method must not be null");
this.executable = method;
this.parameterIndex = validateIndex(method, parameterIndex);
this.nestingLevel = nestingLevel;
}
Analytical parameter automatic assembly resolveAutowiredArgument
First, it is judged whether the injection point type InjectionPoint
, a method of this type is described, or a constructor parameter or attribute, since these are the places can be automatically injected. If so, it returns direct access to the injection point, or let beanFactory
to resolve dependencies, before that, first MethodParameter
encapsulated DependencyDescriptor
, that is, the injection point.
protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
Class<?> paramType = param.getParameterType();
if (InjectionPoint.class.isAssignableFrom(paramType)) {//是否是注入点类型,比如DependencyDescriptor
InjectionPoint injectionPoint = currentInjectionPoint.get();
if (injectionPoint == null) {
throw new IllegalStateException("No current InjectionPoint available for " + param);
}
return injectionPoint;
}
try {//beanFactory解析依赖
return this.beanFactory.resolveDependency(
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
}
catch (NoUniqueBeanDefinitionException ex) {
throw ex;
}
catch (NoSuchBeanDefinitionException ex) {
if (fallback) {
...
}
throw ex;
}
}
DefaultListableBeanFactory的resolveDependency
Judgment is dependent on what type, to handle different types, of course, we are sure is the last kind of situation, our custom type, see if lazy loading, if not immediately call doResolveDependency
to resolve.
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//设置参数名字探索器
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
if (Optional.class == descriptor.getDependencyType()) {//Optional类型
return createOptionalDependency(descriptor, requestingBeanName);
}//是对象工厂类型或者对象提供者类型
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}//java扩展的注入类
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {//我们自己只能的类型,先看是否是懒加载,是的话就直接返回,否则要去解析依赖
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
MethodParameter get dependent on type of getDependencyType
If there is property exists and is greater than the nested types 1
, will find out the real type, such as List<String>
this, String
the nest is 2
, true type is String. Of course, we are not a property injection, so a direct call MethodParameter
of getNestedParameterType
.
public Class<?> getDependencyType() {
if (this.field != null) {
if (this.nestingLevel > 1) {
Type type = this.field.getGenericType();
for (int i = 2; i <= this.nestingLevel; i++) {
if (type instanceof ParameterizedType) {
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
type = args[args.length - 1];
}
}
if (type instanceof Class) {
return (Class<?>) type;
}
else if (type instanceof ParameterizedType) {
Type arg = ((ParameterizedType) type).getRawType();
if (arg instanceof Class) {
return (Class<?>) arg;
}
}
return Object.class;
}
else {
return this.field.getType();
}
}
else {
return obtainMethodParameter().getNestedParameterType();
}
}
MethodParameter的getNestedParameterType
I found a lot of duplicate code, in fact, mostly with processing logic attributes the same, if there is only one layer, it is called directly getParameterType
.
public Class<?> getNestedParameterType() {
if (this.nestingLevel > 1) {
Type type = getGenericParameterType();
for (int i = 2; i <= this.nestingLevel; i++) {
if (type instanceof ParameterizedType) {
Type[] args = ((ParameterizedType) type).getActualTypeArguments();
Integer index = getTypeIndexForLevel(i);
type = args[index != null ? index : args.length - 1];
}
// TODO: Object.class if unresolvable
}
if (type instanceof Class) {
return (Class<?>) type;
}
else if (type instanceof ParameterizedType) {
Type arg = ((ParameterizedType) type).getRawType();
if (arg instanceof Class) {
return (Class<?>) arg;
}
}
return Object.class;
}
else {
return getParameterType();
}
}
DependencyDescriptor的getNestedParameterType
There is a direct return type, or other processing will be carried out to obtain the parameter type.
public Class<?> getParameterType() {
Class<?> paramType = this.parameterType;
if (paramType != null) {
return paramType;
}
if (getContainingClass() != getDeclaringClass()) {
paramType = ResolvableType.forMethodParameter(this, null, 1).resolve();
}
if (paramType == null) {
paramType = computeParameterType();
}
this.parameterType = paramType;
return paramType;
}
Well, here today, we hope to help study and understand, do not spray the Great God see, understand only their own learning, limited capacity, please excuse.