protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
//创建一个treeSet进行去重
Set result = new TreeSet<>();
//获取所有的依赖
PropertyValues pvs = mbd.getPropertyValues();
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
//
for (PropertyDescriptor pd : pds) {
//只有写了set方法
//不在不检查依赖的集合中
//不是简单类型
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
//满足条件之后添加进里面
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
看代码比较抽象,所以决定举个栗子
配置文件只是简单的一个注入类型
类也很简单,只是简单地提供了一个set方法注入
下面我们直接看那两个集合是什么
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
结果如下
里面有两个对象
一个是bean自己的class,没有writeMethod
另外一个,关于twoPojo的,而且里面存称了writeMethod正式set方法!!!!
所以可以推测这个集合获取的是需要依赖的属性详情
PropertyValues pvs = mbd.getPropertyValues();
里面的东西如下所示
可以看到,里面完全就是配置文件里面的信息。。。。
所以,这个集合里面存储的是配置文件里面的依赖属性的信息
那么现在,这个for循环来剔除什么,就很容易看出了
回归到我们的for循环
for (PropertyDescriptor pd : pds) {
//只有写了set方法
//不在不检查依赖的集合中
//不是简单类型
//并且配置文件里面没有这个beanName,
//如果配置文件里有那就去IOC容器里面拿就好了,不需要自动注入
//而不是采用注入的方式
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
//满足条件之后添加进里面
result.add(pd.getName());
}
}
可以看到结果,result为0
假如我们去掉配置文件的property
可以看到结果带上了twoPOJO
下面再来看一下BeanUtils过滤了什么东西出来
可以看到其过滤一些类型
-
void类型
-
isPrimitiveOrWrapper:判断是不是包装类,也就是过滤包装类
-
Enum类型
-
Date类型
-
URI类型
-
URL类型
-
Locale类型
-
Class类型
-
CharSequence类型
总结一下哪种依赖bean会被
-
没有写Set方法的依赖会被过滤
-
位于不进行检查的集合中依赖会被过滤
-
配置文件中已经指定注入的类型会被过滤
-
属于简单类型的也会被过滤
AUTOWIRE_BY_TYPE
还有一种自动注入类型就是根据类型去寻找
对应的代码如下
对应的方法是autowireByType
源码如下
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
//获取类型处理器
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//使用一个LinkedHashSet来存储需要自动注入的bean的beanName
//之前存储beanName也是使用一个set进行去重,然后转化成一个字符串数组
Set autowiredBeanNames = new LinkedHashSet<>(4);
//可以看到这里同样要进行过滤,就不赘述了
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//遍历需要注入的依赖
for (String propertyName : propertyNames) {
try {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don’t try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
//判断该依赖是不是Object类型,(注意:过滤并没有将Object类型过滤)
if (Object.class != pd.getPropertyType()) {
//获取该bean的set方法的参数。。
//相当于就是获取类型了。。体现出了ByType
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
//解析指定beanName的属性所匹配的至,并把解析到的属性名称存储在autowiredBeanNames中
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
pvs.add(propertyName, autowiredArgument);
}
//遍历需要注入的bean
for (String autowiredBeanName : autowiredBeanNames) {
//注册依赖
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace(“Autowiring by type from bean name '” + beanName + “’ via property '” +
propertyName + “’ to bean named '” + autowiredBeanName + “'”);
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
}
从这里可以看到两个细节
-
Spring对于Object类型的,使用ByType是不会进行注入的
-
获取类型是通过过去Set方法的参数来实现的,参数其实就是Type了,可以看出是ByType的体现
-
通过resolveDependency来进行创建依赖
resolveDependency
可以看到,对ByType的依赖进行创建是交由DefaultListableBeanFactory来实现的,而ByName的依赖进行创建交由AbstractAutowireCapableFactory来实现的
源码如下
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
//扩展了对Optional类的支持
if (Optional.class == descriptor.getDependencyType()) {
//Optional类单独使用方法创建
return createOptionalDependency(descriptor, requestingBeanName);
}
//对于ObjectFactory和ObjectProvider也是单独方法创建
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
//对JavaInjectProviderClass进行单独处理
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
//对于其他一般类型
//使用AutowireCandidateResolver来进行注入
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
//如果AutpwireCandidateResolver注入失败,使用doResolveDependency进行注入
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
可以看到,对于一些特定类型单独处理之外,其他的类型都会走相同的步骤(大部分)
getLazyResollutionProxyIfNecessary
对于一般类型,首先会经过这个方法进行处理
从这个方法的注释来看,感觉像是对切入点进行添加代理的。。
不过其默认实现直接返回Null,那就先不看了。
doResolveDependency
接下来执行这个方法进行处理
源码如下,可以看到十分恐怖。。。
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
//获取类对象,也就是前面通过set方法拿到的参数
Class<?> type = descriptor.getDependencyType();
//支持新增的@Value注解
//@Value注解是可以直接用在类上的,所以这里是根据类获取其注解
//然后去相应配置中进行注入
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
//判断是不是@Value注入了
//所以ByName不会被@Value注入????
if (value != null) {
//如果是,会执行下面这些操作
if (value instanceof String) {
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution…
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
//考虑这个属性是不是多个Bean的,也就是处理集合类型
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
//查找出所有的候选者
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
//判断候选者的数量
if (matchingBeans.size() > 1) {
//如果存在两个或两个意思,执行下面操作
//决定使用哪个候选者
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
//判断是否可以决定出来
if (autowiredBeanName == null) {
//
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn’t even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
//如果只有一个候选值,进行下面处理
// We have exactly one match.
//去获取唯一的一个候选者
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
//使用候选者的属性
//beanName为key
//依赖的对象就是候选者的value
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
//添加进集合
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
//此时让result为得出来的候选者
Object result = instanceCandidate;
//再判断是不是NullBean类型
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
//返回结果
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
好复杂,看的要吐了。。。。。。
总结一下大概的过程
-
通过前面解析set方法得到的参数来获取Class类型
-
通过这个Class类型去判断其有没有被@Value注解标识
-
如果有,走另一个逻辑
-
如果没有,代表还是需要去注入
-
判断是不是集合类型的,如果是集合类型的,又走集合类型的处理
-
如果不是集合类型的,去获取所有候选者
-
判断候选者的数量
-
如果候选者数量存在两个以上
-
判断决定使用哪个候选者,如果决定不出来又是另外一个方法
-
如果决定出来了,该候选者就是依赖Bean的实例了
-
如果候选者只有一个,直接使用该候选者
-
然后对产生出来的候选者做一些判空处理
-
返回结果
大概的思路就是这样。。。。下次再仔细研究,这太难了
到了这里之后,我们就已经完成了对所有注入属性的获取,但是获取了属性是以PropertyValue形式存在的,还没有应用到已经实例化的bean中
注入属性
回到populate方法中,现在所有的依赖就已经创建好了,等待注入bean里面了,对应的执行的方法为applyPropertyValues方法,同时也是populateBean最后的执行方法
源码如下
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//如果依赖为空直接返回
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//判断依赖是不是已经转化为对应的类型
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
//如果转化成对应的类型,直接装入BeanWrapper中
bw.setPropertyValues(mpvs);
//结束返回
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, “Error setting property values”, ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
//将依赖放进original中
original = Arrays.asList(pvs.getPropertyValues());
}
//
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//获取对应的解析器
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
//使用一个ArrayList去存储依赖的深拷贝对象
List deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
//遍历所有依赖
for (PropertyValue pv : original) {
//判断依赖是不是已经转换过了
if (pv.isConverted()) {
//如果转换过了就直接添加进集合中去
deepCopy.add(pv);
}
else {
//获取依赖的名字,变量名
String propertyName = pv.getName();
//获取依赖的值,此时已经是一个对象了
Object originalValue = pv.getValue();
//如果值是AutowiredPropertyMarker…
//不太清楚这什么情况
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
//使用解析器进行解析
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//将解析结果放在convertedValue变量中
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
//进行转化
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
//添加进深拷贝集合里面
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
//最后将所有深拷贝的依赖存进beanWrapper中
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, “Error setting property values”, ex);
}
}
注入属性也好难懂,大体的过程是
-
判断依赖是不是都转化好了
-
如果都转化好了就直接添加进去beanWrapper中
-
如果没有转化好,就要进行对依赖深拷贝了
-
获取依赖的变量名和依赖的值,值通常是一个Spring自定义的RuntimeBeanReference
-
使用解析器进行转化
-
将转化后的值添加进去deepCopy集合中,deepCopy是一个ArrayList
-
最后将deepCopy集合存进beanWrapper中
所以,重点的部分在于解析和将解析后依赖存进beanWrapper这里,下面看看是如何进行解析的
valueResolver.resolveValueIfNecessary(pv, originalValue);
这个方法就是进行解析的
源码如下
@Nullable
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
//判断是不是RuntimeBeanReference
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
//判断是不是RuntimeBeanNameReference
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
“Invalid bean name '” + refName + "’ in bean reference for " + argName);
}
return refName;
}
//判断是不是BeanDefinitinHolder
else if (value instanceof BeanDefinitionHolder) {
// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
//判断是不是BeanDefinition
else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = “(inner bean)” + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
//判断是不是DependencyDescriptor
else if (value instanceof DependencyDescriptor) {
Set autowiredBeanNames = new LinkedHashSet<>(4);
Object result = this.beanFactory.resolveDependency(
(DependencyDescriptor) value, this.beanName, autowiredBeanNames, this.typeConverter);
for (String autowiredBeanName : autowiredBeanNames) {
if (this.beanFactory.containsBean(autowiredBeanName)) {
this.beanFactory.registerDependentBean(autowiredBeanName, this.beanName);
}
}
return result;
}
//判断是不是ManagedArray
else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
ManagedArray array = (ManagedArray) value;
Class<?> elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
try {
elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
}
catch (Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error resolving array type for " + argName, ex);
}
}
else {
elementType = Object.class;
}
}
return resolveManagedArray(argName, (List<?>) value, elementType);
}
//判断是不是ManagedList
else if (value instanceof ManagedList) {
// May need to resolve contained runtime references.
return resolveManagedList(argName, (List<?>) value);
}
//判断是不是ManagedSet
else if (value instanceof ManagedSet) {
// May need to resolve contained runtime references.
return resolveManagedSet(argName, (Set<?>) value);
}
//判断是不是ManagedMap
else if (value instanceof ManagedMap) {
// May need to resolve contained runtime references.
return resolveManagedMap(argName, (Map<?, ?>) value);
}
//判断是不是ManagedProperties
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
original.forEach((propKey, propValue) -> {
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
if (propKey == null || propValue == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting Properties key/value pair for " + argName + “: resolved to null”);
}
copy.put(propKey, propValue);
});
return copy;
}
//判断是不是TypeStringValue
else if (value instanceof TypedStringValue) {
// Convert value to target type here.
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
else {
return valueObject;
}
}
catch (Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting typed String value for " + argName, ex);
}
}
//判断是不是NullBean
else if (value instanceof NullBean) {
return null;
}
//如果都不是上述类型
else {
return evaluate(value);
}
}
可以看到,这里注入属性根据传进来的值是什么类型做了区分处理
-
RuntimeBeanReference类型的
-
RuntimeBeanNameReference类型的
-
BeanDefinitionHolder类型的
-
BeanDefiniton类型的
-
DependencyDescriptor类型的
-
ManagedArray类型的
-
ManagedList类型的额
-
ManagedSet类型的
-
ManagedMap类型的
-
ManagedProperty类型的
-
NullBean类型的
-
其他类型,这里的其他类型已经就是对应的class类型了
一般传进来的是一个已经是对应的类型了
那就会直接对应最后的evaluate方法
源码如下
@Nullable
protected Object evaluate(@Nullable Object value) {
//对字符串进行处理
//主要的处理是将字符串解析为一个Bean对象
if (value instanceof String) {
return this.doEvaluate((String)value);
}
//对字符串数组进行处理
else if (value instanceof String[]) {
String[] values = (String[])((String[])value);
boolean actuallyResolved = false;
Object[] resolvedValues = new Object[values.length];
//其实就是遍历字符串数组,对每个字符串进行处理
for(int i = 0; i < values.length; ++i) {
String originalValue = values[i];
Object resolvedValue = this.doEvaluate(originalValue);
if (resolvedValue != originalValue) {
actuallyResolved = true;
}
resolvedValues[i] = resolvedValue;
}
return actuallyResolved ? resolvedValues : values;
}
//不是字符串也不是字符串数组,直接返回value,也就是创建好的对象
//一般直接在这里就返回了
else {
return value;
}
}
可以看到这个方法对字符串和字符串数组做了特殊处理,但这里是不可能出现String类型和字符串数组类型的。。。因为前面已经过滤掉了
bw.setPropertyValues
这个方法就是将依赖存进beanWrapper中了
可以看到,此时要注入的依赖都存进了deepCopy中
进来这个方法之后,可以看到这个方法是交由AbstractPropertyAccessor实现的,并且调用了重载方法
源码如下
@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException {
//存储异常的
List propertyAccessExceptions = null;
//将传进来的依赖转为List
List propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
//这个参数为false,不考虑下面这步
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
//遍历传进来的所有依赖
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
言尽于此,完结
无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。
- 第一,设计模式能让专业人之间交流方便,如下:
程序员A:这里我用了XXX设计模式
程序员B:那我大致了解你程序的设计思路了
- 第二,易维护
项目经理:今天客户有这样一个需求…
程序员:明白了,这里我使用了XXX设计模式,所以改起来很快
- 第三,设计模式是编程经验的总结
程序员A:B,你怎么想到要这样去构建你的代码
程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题
- 第四,学习设计模式并不是必须的
程序员A:B,你这段代码使用的是XXX设计模式对吗?
程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
搜集费时费力,能看到此处的都是真爱!
id)
throws BeansException {
//存储异常的
List propertyAccessExceptions = null;
//将传进来的依赖转为List
List propertyValues = (pvs instanceof MutablePropertyValues ?
((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues()));
//这个参数为false,不考虑下面这步
if (ignoreUnknown) {
this.suppressNotWritablePropertyException = true;
}
try {
//遍历传进来的所有依赖
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-CleKnQQI-1711082482910)]
[外链图片转存中…(img-iQ4HkkDw-1711082482910)]
[外链图片转存中…(img-2eGQFM2j-1711082482911)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-Tv6TLtcz-1711082482911)]
言尽于此,完结
无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。
- 第一,设计模式能让专业人之间交流方便,如下:
程序员A:这里我用了XXX设计模式
程序员B:那我大致了解你程序的设计思路了
- 第二,易维护
项目经理:今天客户有这样一个需求…
程序员:明白了,这里我使用了XXX设计模式,所以改起来很快
- 第三,设计模式是编程经验的总结
程序员A:B,你怎么想到要这样去构建你的代码
程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题
- 第四,学习设计模式并不是必须的
程序员A:B,你这段代码使用的是XXX设计模式对吗?
程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的
[外链图片转存中…(img-ol5fngwF-1711082482912)]
从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!
[外链图片转存中…(img-YDsNK2ct-1711082482912)]
搜集费时费力,能看到此处的都是真爱!