源码分析:Spring是如何获取容器中的Bean?

if (!beanName.equals(parentBeanName)) {

pbd = getMergedBeanDefinition(parentBeanName);

}

else {

BeanFactory parent = getParentBeanFactory();

if (parent instanceof ConfigurableBeanFactory) {

pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);

}

else {

throw new NoSuchBeanDefinitionException(parentBeanName,

“Parent name '” + parentBeanName + “’ is equal to bean name '” + beanName +

“': cannot be resolved without an AbstractBeanFactory parent”);

}

}

}

catch (NoSuchBeanDefinitionException ex) {

throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,

“Could not resolve parent bean definition '” + bd.getParentName() + “'”, ex);

}

// Deep copy with overridden values.

mbd = new RootBeanDefinition(pbd);

mbd.overrideFrom(bd);

}

// 设置默认为单例

if (!StringUtils.hasLength(mbd.getScope())) {

mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);

}

// A bean contained in a non-singleton bean cannot be a singleton itself.

// Let’s correct this on the fly here, since this might be the result of

// parent-child merging for the outer bean, in which case the original inner bean

// definition will not have inherited the merged outer bean’s singleton status.

if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {

mbd.setScope(containingBd.getScope());

}

//将构建好的RootBeanDefinition进行缓存

if (containingBd == null && isCacheBeanMetadata()) {

this.mergedBeanDefinitions.put(beanName, mbd);

}

}

return mbd;

}

}

创建对象实例

======

上面构造好了RootBeanDefinition,下面来创建对象

//单例对象的创建

if (mbd.isSingleton()) {

sharedInstance = getSingleton(beanName, () -> {

try {

return createBean(beanName, mbd, args);

}

catch (BeansException ex) {

// Explicitly remove instance from singleton cache: It might have been put there

// eagerly by the creation process, to allow for circular reference resolution.

// Also remove any beans that received a temporary reference to the bean.

destroySingleton(beanName);

throw ex;

}

});

bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

}

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

throws BeanCreationException {

if (logger.isTraceEnabled()) {

logger.trace(“Creating instance of bean '” + beanName + “'”);

}

RootBeanDefinition mbdToUse = mbd;

// Make sure bean class is actually resolved at this point, and

// clone the bean definition in case of a dynamically resolved Class

// which cannot be stored in the shared merged bean definition.

Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {

mbdToUse = new RootBeanDefinition(mbd);

mbdToUse.setBeanClass(resolvedClass);

}

// Prepare method overrides.

try {

mbdToUse.prepareMethodOverrides();

}

catch (BeanDefinitionValidationException ex) {

throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),

beanName, “Validation of method overrides failed”, ex);

}

try {

// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.

Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

if (bean != null) {

return bean;

}

}

catch (Throwable ex) {

throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,

“BeanPostProcessor before instantiation of bean failed”, ex);

}

try {

//根据beanName创建对象

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

if (logger.isTraceEnabled()) {

logger.trace(“Finished creating instance of bean '” + beanName + “'”);

}

return beanInstance;

}

catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {

// A previously detected exception with proper bean creation context already,

// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.

throw ex;

}

catch (Throwable ex) {

throw new BeanCreationException(

mbdToUse.getResourceDescription(), beanName, “Unexpected exception during bean creation”, ex);

}

}

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)

throws BeanCreationException {

// 初始化Bean

BeanWrapper instanceWrapper = null;

if (mbd.isSingleton()) {

instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);

}

if (instanceWrapper == null) {

//创建Bean实例

instanceWrapper = createBeanInstance(beanName, mbd, args);

}

final Object bean = instanceWrapper.getWrappedInstance();

Class<?> beanType = instanceWrapper.getWrappedClass();

if (beanType != NullBean.class) {

mbd.resolvedTargetType = beanType;

}

// Allow post-processors to modify the merged bean definition.

synchronized (mbd.postProcessingLock) {

if (!mbd.postProcessed) {

try {

applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);

}

catch (Throwable ex) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName,

“Post-processing of merged bean definition failed”, ex);

}

mbd.postProcessed = true;

}

}

// Eagerly cache singletons to be able to resolve circular references

// even when triggered by lifecycle interfaces like BeanFactoryAware.

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&

isSingletonCurrentlyInCreation(beanName));

if (earlySingletonExposure) {

if (logger.isTraceEnabled()) {

logger.trace(“Eagerly caching bean '” + beanName +

“’ to allow for resolving potential circular references”);

}

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

}

// Initialize the bean instance.

Object exposedObject = bean;

try {

populateBean(beanName, mbd, instanceWrapper);

exposedObject = initializeBean(beanName, exposedObject, mbd);

}

catch (Throwable ex) {

if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {

throw (BeanCreationException) ex;

}

else {

throw new BeanCreationException(

mbd.getResourceDescription(), beanName, “Initialization of bean failed”, ex);

}

}

if (earlySingletonExposure) {

Object earlySingletonReference = getSingleton(beanName, false);

if (earlySingletonReference != null) {

if (exposedObject == bean) {

exposedObject = earlySingletonReference;

}

else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {

String[] dependentBeans = getDependentBeans(beanName);

Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);

for (String dependentBean : dependentBeans) {

if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {

actualDependentBeans.add(dependentBean);

}

}

if (!actualDependentBeans.isEmpty()) {

throw new BeanCurrentlyInCreationException(beanName,

“Bean with name '” + beanName + “’ has been injected into other beans [” +

StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +

"] in its raw version as part of a circular reference, but has eventually been " +

"wrapped. This means that said other beans do not use the final version of the " +

"bean. This is often the result of over-eager type matching - consider using " +

“‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.”);

}

}

}

}

// Register bean as disposable.

try {

registerDisposableBeanIfNecessary(beanName, bean, mbd);

}

catch (BeanDefinitionValidationException ex) {

throw new BeanCreationException(

mbd.getResourceDescription(), beanName, “Invalid destruction signature”, ex);

}

return exposedObject;

}

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

// Make sure bean class is actually resolved at this point.

Class<?> beanClass = resolveBeanClass(mbd, beanName);

if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName,

"Bean class isn’t public, and non-public access not allowed: " + beanClass.getName());

}

Supplier<?> instanceSupplier = mbd.getInstanceSupplier();

if (instanceSupplier != null) {

return obtainFromSupplier(instanceSupplier, beanName);

}

if (mbd.getFactoryMethodName() != null) {

//使用FactotyMethod实例化Bean

return instantiateUsingFactoryMethod(beanName, mbd, args);

}

// Shortcut when re-creating the same bean…

boolean resolved = false;

boolean autowireNecessary = false;

if (args == null) {

synchronized (mbd.constructorArgumentLock) {

if (mbd.resolvedConstructorOrFactoryMethod != null) {

resolved = true;

autowireNecessary = mbd.constructorArgumentsResolved;

}

}

}

if (resolved) {

if (autowireNecessary) {

return autowireConstructor(beanName, mbd, null, null);

}

else {

return instantiateBean(beanName, mbd);

}

}

// Candidate constructors for autowiring?

Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||

mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

return autowireConstructor(beanName, mbd, ctors, args);

}

// Preferred constructors for default construction?

ctors = mbd.getPreferredConstructors();

if (ctors != null) {

return autowireConstructor(beanName, mbd, ctors, null);

}

// No special handling: simply use no-arg constructor.

return instantiateBean(beanName, mbd);

}

上面可以看到,通过不同的方法进行Bean的实例化,有FactoryMethod、autowireConstructor、还有无参构造器,这里看一下通过FactoryMethod的实例化

protected BeanWrapper instantiateUsingFactoryMethod(

String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);

}

public BeanWrapper instantiateUsingFactoryMethod(

String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {

BeanWrapperImpl bw = new BeanWrapperImpl();

this.beanFactory.initBeanWrapper(bw);

Object factoryBean;

Class<?> factoryClass;

boolean isStatic;

//获取FactoryBeanName

String factoryBeanName = mbd.getFactoryBeanName();

if (factoryBeanName != null) {

if (factoryBeanName.equals(beanName)) {

throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,

“factory-bean reference points back to the same bean definition”);

}

//从容器中获取factoryBean

factoryBean = this.beanFactory.getBean(factoryBeanName);

if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {

throw new ImplicitlyAppearedSingletonException();

}

//实例化factoryClass

factoryClass = factoryBean.getClass();

isStatic = false;

}

else {

// It’s a static factory method on the bean class.

if (!mbd.hasBeanClass()) {

throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,

“bean definition declares neither a bean class nor a factory-bean reference”);

}

factoryBean = null;

factoryClass = mbd.getBeanClass();

isStatic = true;

}

Method factoryMethodToUse = null;

ArgumentsHolder argsHolderToUse = null;

Object[] argsToUse = null;

if (explicitArgs != null) {

argsToUse = explicitArgs;

}

else {

Object[] argsToResolve = null;

synchronized (mbd.constructorArgumentLock) {

factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;

if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {

// Found a cached factory method…

argsToUse = mbd.resolvedConstructorArguments;

if (argsToUse == null) {

argsToResolve = mbd.preparedConstructorArguments;

}

}

}

if (argsToResolve != null) {

argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);

}

}

if (factoryMethodToUse == null || argsToUse == null) {

// Need to determine the factory method…

// Try all methods with this name to see if they match the given arguments.

factoryClass = ClassUtils.getUserClass(factoryClass);

Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);

List candidateList = new ArrayList<>();

//过滤出工厂方法

for (Method candidate : rawCandidates) {

if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {

candidateList.add(candidate);

}

}

if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {

Method uniqueCandidate = candidateList.get(0);

if (uniqueCandidate.getParameterCount() == 0) {

mbd.factoryMethodToIntrospect = uniqueCandidate;

synchronized (mbd.constructorArgumentLock) {

mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;

mbd.constructorArgumentsResolved = true;

mbd.resolvedConstructorArguments = EMPTY_ARGS;

}

//使用工厂方法创建实例对象

bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));

return bw;

}

}

Method[] candidates = candidateList.toArray(new Method[0]);

AutowireUtils.sortFactoryMethods(candidates);

ConstructorArgumentValues resolvedValues = null;

boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);

int minTypeDiffWeight = Integer.MAX_VALUE;

Set ambiguousFactoryMethods = null;

int minNrOfArgs;

if (explicitArgs != null) {

minNrOfArgs = explicitArgs.length;

}

else {

// We don’t have arguments passed in programmatically, so we need to resolve the

// arguments specified in the constructor arguments held in the bean definition.

if (mbd.hasConstructorArgumentValues()) {

ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();

resolvedValues = new ConstructorArgumentValues();

minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);

}

else {

minNrOfArgs = 0;

}

}

/因代码太长,略过很多代码*******************

}

private Object instantiate(String beanName, RootBeanDefinition mbd,

@Nullable Object factoryBean, Method factoryMethod, Object[] args) {

try {

if (System.getSecurityManager() != null) {

return AccessController.doPrivileged((PrivilegedAction) () ->

this.beanFactory.getInstantiationStrategy().instantiate(

mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),

this.beanFactory.getAccessControlContext());

}

else {

//创建实例对象

return this.beanFactory.getInstantiationStrategy().instantiate(

mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);

}

}

catch (Throwable ex) {

throw new BeanCreationException(mbd.getResourceDescription(), beanName,

“Bean instantiation via factory method failed”, ex);

}

}

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,

@Nullable Object factoryBean, final Method factoryMethod, Object… args) {

try {

if (System.getSecurityManager() != null) {

AccessController.doPrivileged((PrivilegedAction) () -> {

ReflectionUtils.makeAccessible(factoryMethod);

return null;

});

}

else {

ReflectionUtils.makeAccessible(factoryMethod);

}

Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();

try {

currentlyInvokedFactoryMethod.set(factoryMethod);

//这里使用反射调用工厂方法,生成对象并返回

Object result = factoryMethod.invoke(factoryBean, args);

if (result == null) {

result = new NullBean();

}

return result;

}

finally {

if (priorInvokedFactoryMethod != null) {

currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);

}

else {

currentlyInvokedFactoryMethod.remove();

}

}

}

catch (IllegalArgumentException ex) {

throw new BeanInstantiationException(factoryMethod,

“Illegal arguments to factory method '” + factoryMethod.getName() + "'; " +

"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);

}

catch (IllegalAccessException ex) {

throw new BeanInstantiationException(factoryMethod,

“Cannot access factory method '” + factoryMethod.getName() + “'; is it public?”, ex);

}

catch (InvocationTargetException ex) {

String msg = “Factory method '” + factoryMethod.getName() + “’ threw exception”;

if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&

((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {

msg = “Circular reference involving containing bean '” + bd.getFactoryBeanName() + "’ - consider " +

"declaring the factory method as static for independence from its containing instance. " + msg;

}

throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());

}

}

使用反射调用工厂方法,生成对象并返回,返回对象就表示从容器中根据注册的Bean信息拿到了具体的对象,到此整个调用链路都完成了。

我原本以为是在调用getBean()时才去进行Bean的实例化,但是在断点跟踪的过程中,发现单例对象实际上是在容器启动的时候就会去实例化,getBean()的时候直接拿,不用再实例化。代码如下:

public void refresh() throws BeansException, IllegalStateException {

synchronized (this.startupShutdownMonitor) {

// Prepare this context for refreshing.

prepareRefresh();

// Tell the subclass to refresh the internal bean factory.

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.

prepareBeanFactory(beanFactory);

try {

// Allows post-processing of the bean factory in context subclasses.

postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.

invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.

registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.

initMessageSource();

// Initialize event multicaster for this context.

initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.

onRefresh();

// Check for listener beans and register them.

registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.

finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.

finishRefresh();

}

catch (BeansException ex) {

if (logger.isWarnEnabled()) {

logger.warn("Exception encountered during context initialization - " +

"cancelling refresh attempt: " + ex);

}

// Destroy already created singletons to avoid dangling resources.

destroyBeans();

// Reset ‘active’ flag.

cancelRefresh(ex);

// Propagate exception to caller.

throw ex;

}

finally {

// Reset common introspection caches in Spring’s core, since we

// might not ever need metadata for singleton beans anymore…

resetCommonCaches();

}

}

}

在refresh()方法中有专门进行单例初始化的方法,就是

finishBeanFactoryInitialization(beanFactory),从注释可以看出来就是用来做单例的实例化的

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {

// Initialize conversion service for this context.

if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&

beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {

beanFactory.setConversionService(

beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));

}

// Register a default embedded value resolver if no bean post-processor

// (such as a PropertyPlaceholderConfigurer bean) registered any before:

// at this point, primarily for resolution in annotation attribute values.

if (!beanFactory.hasEmbeddedValueResolver()) {

beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));

}

// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.

String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);

for (String weaverAwareName : weaverAwareNames) {

getBean(weaverAwareName);

}

// Stop using the temporary ClassLoader for type matching.

beanFactory.setTempClassLoader(null);

// Allow for caching all bean definition metadata, not expecting further changes.

beanFactory.freezeConfiguration();

// 实例化单例对象

beanFactory.preInstantiateSingletons();

}

public void preInstantiateSingletons() throws BeansException {

if (logger.isTraceEnabled()) {

logger.trace("Pre-instantiating singletons in " + this);

}

// Iterate over a copy to allow for init methods which in turn register new bean definitions.

// While this may not be part of the regular factory bootstrap, it does otherwise work fine.

List beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans…

for (String beanName : beanNames) {

RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

if (isFactoryBean(beanName)) {

Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);

if (bean instanceof FactoryBean) {

final FactoryBean<?> factory = (FactoryBean<?>) bean;

boolean isEagerInit;

if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {

isEagerInit = AccessController.doPrivileged((PrivilegedAction)

((SmartFactoryBean<?>) factory)::isEagerInit,

getAccessControlContext());

}

else {

isEagerInit = (factory instanceof SmartFactoryBean &&

((SmartFactoryBean<?>) factory).isEagerInit());

}

if (isEagerInit) {

getBean(beanName);

}

}

}

else {

//从这里可以看出来,单例的实例化是通过调用getBean方法来实现的

getBean(beanName);

}

}

}

// Trigger post-initialization callback for all applicable beans…

for (String beanName : beanNames) {

Object singletonInstance = getSingleton(beanName);

if (singletonInstance instanceof SmartInitializingSingleton) {

final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

AccessController.doPrivileged((PrivilegedAction) () -> {

smartSingleton.afterSingletonsInstantiated();

return null;

}, getAccessControlContext());

}

else {

smartSingleton.afterSingletonsInstantiated();

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档

MySQL全家桶笔记

还有更多面试复习笔记分享如下

Java架构专题面试复习

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
martSingleton = (SmartInitializingSingleton) singletonInstance;

if (System.getSecurityManager() != null) {

AccessController.doPrivileged((PrivilegedAction) () -> {

smartSingleton.afterSingletonsInstantiated();

return null;

}, getAccessControlContext());

}

else {

smartSingleton.afterSingletonsInstantiated();

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-EMb8N2lo-1713751493597)]

[外链图片转存中…(img-aWck5ye1-1713751493598)]

[外链图片转存中…(img-z1pXZPeQ-1713751493598)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

由于篇幅有限,这里就不一一罗列了,20道常见面试题(含答案)+21条MySQL性能调优经验小编已整理成Word文档或PDF文档

[外链图片转存中…(img-Cn3oKZss-1713751493599)]

还有更多面试复习笔记分享如下

[外链图片转存中…(img-d8QDgHF0-1713751493599)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值