【Spring进阶系列丨第七篇】Spring框架新注解分类及详解

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

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

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:xhs1999xhs (备注Java)
img

正文

文章目录

在这里插入图片描述

一、Spring新注解

1.1、Configuration注解

1.1.1、定义一个类
public class SpringMainConfig {

}

1.1.2、使用Configuration注解修饰类
@Configuration
public class SpringMainConfig {
    
}

1.1.3、作用

​ 使用Configuration注解修饰的类表示的是:当前类是一个配置类。该类的作用和beans.xml是一样的,换句话说,该注解所修饰的类就是用来代替beans.xml文件的。

1.2、Bean注解

1.2.1、定义bean
public class User {
    
    private Integer id;
    
    private String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

1.2.2、在主配置类中注册bean

​ 在以前,使用xml去注册bean的时候,使用的是bean标签,形如:

<bean id="user" class="cn.bdqn.User"/>

​ 现在改为使用注解,使用的是@Bean注解。

@Configuration
public class SpringMainConfig {
    
    // 给容器中注册一个bean;类型为方法返回值的类型,默认方法名作为id,即bean的名字默认是方法名
    @Bean
    public User user(){
        return new User(1,"段康家");
    }
}

1.2.3、测试容器中是否有该bean
@Test
public void testUser() throws Exception{

    ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
    User user = (User) ac.getBean("user");
    System.out.println(user);	// User{id=1, name='段康家'}
}

1.2.4、注册bean的同时可以指定bean名称
@Configuration
public class SpringMainConfig {

    // 给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
  	// 可以再注册Bean的同时,不用方法名作为id,可以指定bean的名称。
    @Bean("user01")
    public User user(){
        return new User(1,"段康家");
    }
}


1.2.5、补充内容
1.2.5.1、案例1【方法有参数】
// 定义UserDao接口
public interface UserDao {

}

// 定义UserDao接口的实现类
public class UserDaoImpl01 implements UserDao{

}

// 定义UserService
public class UserServiceImpl {

    private UserDao userDao;
	
  	// 构造方法接收UserDao类型的对象
    public UserServiceImpl(UserDao userDao){
        this.userDao = userDao;
    }
}

重点看主配置类:

@Configuration
public class SpringMainConfig {

    // 给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
    @Bean
    public UserServiceImpl userService(UserDao userDao){
        return new UserServiceImpl(userDao);
    }

    @Bean
    public UserDao userDao01(){
        return new UserDaoImpl01();
    }
}

 @Test
public void testUser() throws Exception{

  	ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
    UserServiceImpl userService = (UserServiceImpl) ac.getBean("userService");
    System.out.println(userService);
}

说明:测试后发现程序能够正常运行,说明UserDao能够正常的以构造函数参数的形式注入到UserServiceImpl类中。

总结:当我们使用Bean注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。查找的方式和Autowired注解的作用是一样的。即:Spring会从容器中根据类型注入

1.2.5.2、案例2

当然还有一种情况是:容器中注册了多个相同类型的Bean,那么Spring又是如何注入的呢?在8.2.5.1案例基础之上再添加一个UserDaoImpl02。

public class UserDaoImpl02 implements UserDao{

}

在再主配置类中注册该UserDaoImpl02的Bean.

在这里插入图片描述

通过看图可以知道,有问题,不能够实现自动注入,该怎么办呢?两种方式:

a、修改方法的参数

在这里插入图片描述

b、指定Bean的名称

在这里插入图片描述

总结:本质上来说,解决方案1和解决方案2是一样的。

c、使用Qualifier注解。

​ 实际上在7.3.2章节中,已经讲到了关于Qualifier注解的使用,通过该注解实现的功能是:当系统中存在多个相同类型的bean的时候,Spring就会注入失败,这个时候就需要再根据名称实现注入,而使用Qualifier注解可以达到根据给定名称的bean实现注入 。在以前讲解的过程中,我们是把该注解应用到了对类的成员变量上 ,但是需要注意的细节是:该注解应用到成员变量上时,注入时不能单独使用,需要搭配Autowired注解 。 但是,这里有一个例外,那么就是该注解也可以应用在方法参数上。

在这里插入图片描述

特别注意:当把Qualifier注解应用在方法参数上时,可以单独使用

1.3、ComponentScan注解

==作用:==指定spring在创建容器时要扫描的包。作用就如同在配置文件中这样的定义:

<beans>
	<context:component-scan base-package="cn.bdqn"/>
</beans>

1.3.1、案例1

第一步:定义三个Bean,分别是CatController、CatService、CatMapper,并分别用@Controller、@Service、@Repository修饰。

package cn.bdqn.controller;

@Controller
public class CatController {
    
}

package cn.bdqn.service;

@Service
public class CatServiceImpl {

}

package cn.bdqn.mapper;

@Repository
public class CatMapper {
    
}

第二步:要想真正的注册到容器中,就必须要让容器扫描到此注解所修饰的类所在的包。

@Configuration
@ComponentScan(value = {"cn.bdqn"})
public class SpringMainConfig {
}

第三步:测试容器中是否注册了该bean。

@Test
public void testComponentScan() throws Exception{

    ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);

    // 获取Spring容器中已经注册好的bean,把所有bean的名字获取出来
    String[] names = ac.getBeanDefinitionNames();
    for (String name:names) {
        System.out.println(name);
    }
}
/\*\*
 结果:
 catController
 catMapper
 catServiceImpl
\*/

总结:默认情况下,Spring会扫描cn.bdqn包以及子包下面所有的使用@Controller、@Service、@Repository、@Component所修饰的bean注册到容器中

1.3.2、案例2

**需求:**我现在不想扫描被@Controller所修饰的类注册到容器中,即让Spring扫描不到即可。言外之意就是:把所有被@Controller所修饰的类给排除掉。

说明:定义的CatController、CatServiceImpl、CatMapper不变,使用的是案例1。唯一要修改的配置是主配置文件类。为@ComponentScan注解添加excludeFilters属性即可。

**含义:**excludeFilters的作用指定扫描的时候按照什么规则排除那些组件。

**做法:**修改主配置类,即

@Configuration
@ComponentScan(
  value = {"cn.bdqn"},
  excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,
                                          value = {Controller.class})
                   }
)
public class SpringMainConfig {
  
}

**测试:**测试代码同案例1

/\*\*
 catMapper
 catServiceImpl
\*\*/

1.3.3、案例3

**需求:**我现在只想扫描被@Controller所修饰的类注册到容器中,被其他修饰的注解不扫描。

说明:定义的CatController、CatServiceImpl、CatMapper不变,使用的是案例1。唯一要修改的配置是主配置文件类。为@ComponentScan注解添加includeFilters属性即可。

**含义:**includeFilters的作用指定扫描的时候只需要包含哪些组件。

**做法:**修改主配置类,即

@Configuration
@ComponentScan(value = {"cn.bdqn"},
               includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION,
                                          value = {Controller.class, Service.class})}
)
public class SpringMainConfig {
}

**测试:**测试代码同案例1

/\*\*
 catController
 catMapper
 catServiceImpl
 测试,发现,不仅仅Controller被扫描进来了,包括Service,Mapper也都扫描进来了,好像不起作用,没有生效,原因是在于在使用includeFilters做只包含的时候,还需要关闭默认的过滤规则【在默认情况下,Spring是扫描指定包及子包下的被@Component、@Controller、@Service等bean的。】
\*/

主配置文件类修改如下:

@Configuration
@ComponentScan(value = {"cn.bdqn"},
               includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION,
                                          value = {Controller.class, Service.class})},
               useDefaultFilters = false
)
public class SpringMainConfig {
}

测试:

/\*\*
 catController
 测试发现:结果正常,符合预期结果,只扫描到了Controller注解。
\*/

1.4、Scope注解

​ 作用:可以改变bean的作用域。在Spring中,Bean的默认作用域是单例的。

1.4.1、定义Bean
public class User {

    private Integer id;

    private String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }
}

1.4.2、注册Bean并定义作用域
@Configuration
public class SpringMainConfig {

    @Bean
    @Scope
    public User user(){
      	System.out.println("对象创建啦");
        return new User(1,"HelloWorld");
    }
}

1.4.3、测试
 @Test
public void testComponentScan() throws Exception{

  	ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
}
/\*\*
 对象创建啦
\*/

​ 结果:注册的Bean默认是单实例的,Spring容器将会在启动的时候调用方法创建对象后放入容器中,以后每次需要拿对象了就直接从容器中拿,而且每次拿的还是同一个。

1.4.4、将Bean的作用域改为多例
@Configuration
public class SpringMainConfig {

    @Bean
    @Scope("prototype")
    public User user(){
        System.out.println("对象创建啦");
        return new User(1,"HelloWorld");
    }
}

1.4.5、测试1
@Test
public void testPrototype() throws Exception{

  	ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
}
/\*\*
 测试后发现容器启动的时候,多例对象并不会创建。
\*/

1.4.6、测试2
 @Test
public void testPrototype() throws Exception{

  ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);

  User user01 = (User) ac.getBean("user");
  User user02 = (User) ac.getBean("user");
}
/\*\*
 对象创建啦
 对象创建啦
\*/

​ 总结:对于多实例来说,Spring容器在启动的时候并不会去调用方法创建对象并放在容器中,而是每次获取的时候才会调用方法创建对象,并且每次获取到的对象还不一样。

1.5、Lazy注解

作用:用此注解修饰的Bean表示的该Bean需要被懒加载,即不会随着Spring容器的启动而去创建。

1.5.1、注册Bean
@Configuration
public class SpringMainConfig {

    @Bean
    @Lazy(value = true)	// 开启懒加载
    public User user(){
        System.out.println("对象创建啦");
        return new User(1,"HelloWorld");
    }
}

1.5.2、测试
@Test
public void testSingleton() throws Exception{

   ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
}
/\*\*
 控制台什么都没有输出,因为我们的Bean被Layz注解修饰了,即使Spring容器启动了,我们的Bean也不会去创建,只有等到了真正要用到该bean了才去创建。
\*/

1.5.3、总结
  • 这个Lazy注解是针对单实例Bean才有效,因为也只有单实例Bean才会默认在容器启动的时候创建对象。
  • 懒加载:容器启动不创建对象,只有在第一次使用(获取)Bean的时候采取创建对象,并初始化。
  • 该注解的作用等价于。

1.6、Conditional注解【了解】

作用: 根据一定的条件进行判断,当满足这个条件时给容器注入Bean。

==位置:==既可以修饰类也可以修饰方法。

==需求:==当前操作系统如果是window,则注入WindoBean,如果是linux系统,则注入LinuxBean。

首先查看下@Conditional注解的源代码,即:

public @interface Conditional {
  	// 该注解的属性值是一个Class类型的数组,数组的Class元素类型必须继承Condition接口,即元素的类型必
  	// 须是Condition类型。
	Class<? extends Condition>[] value();	
}

继续Condition接口的源代码:

public interface Condition {
	
  	// 提供一个返回boolean值的方法,返回true则注入bean,false则不注入
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

1.6.1、定义两个Bean
// Window的bean
public class WindowBean {
    private String name;

    public WindowBean(String name) {
        this.name = name;
    }
}

// Linux的Bean
public class LinuxBean {
    private String name;

    public LinuxBean(String name) {
        this.name = name;
    }
}

1.6.2、定义两个类实现Condition接口
// Window环境的条件
public class WindowCondition implements Condition {

    // context:上下文环境
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        String osName = context.getEnvironment().getProperty("os.name");
        if (osName.contains("Windows")){
            return true;
        }
        return false;
    }
}

// Linux环境条件
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        String osName = context.getEnvironment().getProperty("os.name");
        if (osName.contains("linux")){
            return true;
        }
        return false;
    }
}

1.6.3、注册Bean
@Configuration
public class SpringMainConfig {

    // 如果当前环境是Winows环境则注入WindowBean
    @Bean
    @Conditional(value = {WindowCondition.class})
    public WindowBean windowBean(){
        return new WindowBean("这个是window操作系统");
    }

    // 如果当前环境是Linux环境则注入LinuxBean
    @Bean
    @Conditional(value = {LinuxCondition.class})
    public LinuxBean linuxBean(){
        return new LinuxBean("这个是Linux操作系统");
    }
}

1.6.4、测试1
@Test
public void testBean() throws Exception{

   ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
   // 查看Spring容器中所有注册的Bean
   String[] names = ac.getBeanDefinitionNames();
   for (String name:names) {
        System.out.println(name);	
    }
}
/\*\*
 windowBean
 由于现在是在window操作系统上测试,故仅仅注册了WindowBean。
\*/

1.6.5、测试2

测试下如果程序运行在linux下,是否能够注入LinuxBean?测试过程,即:运行程序的时候手动的指定运行时参数信息,步骤如下:

在这里插入图片描述

在这里插入图片描述

测试后,发现,打印的结果是:LinuxBean。

1.6.6、总结
  • 使用Conditional注解修饰在方法上,只有当条件满足的时候,即返回true,才会将所修饰的方法调用并且会创建Bean对象添加到容器中。
  • 使用Conditional也可以修饰类,比如修饰主配置类,那么假如这个主配置类中定义了很多的Bean,如果该注解修饰了一个类,则只有条件满足的时候,即返回true,那么主配置类中所定义的Bean才会注册到容器中。即:@Conditional标注在类上就决定了该类中的一批bean是否能够注入。

1.7、Import注解

在这里插入图片描述

1.7.1、用法一

​ 简单来说,Import注解可以去修饰常规组件类,意思是:所谓的常规组件类就是一个普通的Java类, 而如果这个普通的Java类被@Import注解修饰,那么也可以将这个Java类注册到Spring容器中,成为Bean。

1.7.1.1、定义Bean
public class Dog {
    
}

1.7.1.2、注册Bean
@Configuration
@Import(value = {Dog.class})
public class SpringMainConfig {
}

1.7.1.3、测试容器中是否有该Bean
@Test
public void testDogBean() throws Exception{

  	ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);
  	// 查看Spring容器中所有注册的Bean
  	String[] names = ac.getBeanDefinitionNames();
  	for (String name:names) {
       System.out.println(name);
  	}
}
/\*\*
 cn.bdqn.Dog
\*/

1.7.1.4、注意

使用Import注解导入一个常规组件的时候,这个Bean的名称是类的全路径

1.7.2、用法二

​ 即Import可以导入被@Configuration注解所修饰的类,换句话说,Import注解可以去导入其他的配置类,存在的一个细节是:假如这个配置类里面也注册了多个Bean,那么同样也会将这些个Bean一并注册到Spring容器中。

1.7.2.1、定义Bean
// 奥迪
public class AuDi {
    
}

// 宝马
public class BMW {

}

1.7.2.2、新建配置类并注册Bean
// 针对系统中存在的车的一个配置类
@Configuration
public class Car {

    @Bean
    public AuDi auDi(){
        return new AuDi();
    }

    @Bean
    public BMW bmw(){
        return new BMW();
    }
}


1.7.2.3、Import导入配置类
@Configuration
@Import(value = {Car.class})
public class SpringMainConfig {
}

1.7.2.4、测试容器有哪些Bean

​ 测试代码如同8.7.1.3,结果如下:

/\*\*
 cn.bdqn.Car ---> 配置类
 auDi ---> 配置类中的奥迪Bean
 bmw ---> 配置类中的宝马Bean
\*/

1.7.2.5、总结
  • 测试后发现,如果Import导入的是一个配置类,那么Spring会将这个配置类、以及配置类中定义的Bean都会注册到容器中。
  • 同时,有Import注解修饰的那个配置类是主配置类,被Import注解导入的配置类也叫子配置类。例如用法二,SpringMainConfig这个配置类就是主配置类,Car这个配置类称之为子配置类。
  • 这样做的好处:可以将不同功能、不同业务的Bean单独分开配置,而不是统一的都配置到一个配置类中,单独配置,结构清晰,功能划分的也很清楚。

1.8、PropertySource注解

==作用:可以设置properties文件的位置,这样的话,就可以通过Value注解读取配置文件的内容。==该注解的作用等同于:

<context:property-placeholder location="classpath:db.properties"/>

位置:该注解通常和@Configuration注解一起使用。

1.8.1、定义Pig.properties文件
id=1
name=丁春秋

1.8.2、主配置类
@Configuration	// 主配置类
@ComponentScan("cn.bdqn")	// 扫描包,目的是能够扫描到Pig类
@PropertySource(value = {"pig.properties"})	//加载配置文件
public class SpringMainConfig {
    
}

1.8.3、测试
 @Test
public void testPig() throws Exception{

   	ApplicationContext ac = new AnnotationConfigApplicationContext(SpringMainConfig.class);

   	Pig pig = (Pig) ac.getBean("pig");

   	System.out.println(pig);	// 1,name
}


好书推荐

在这里插入图片描述

《Java官方入门教程(第9版·Java 17)》

本书针对Java SE 17做了全面细致的更新,将引导你轻松学习最新的核心Java编程技能。开篇讲述基础知识,内容涉及如何创建、编译和运行Java程序。此后浓墨重彩地描述构成Java语言核心的关键字、语法和结构。本书还涵盖Java的一些更高级特性,如多线程编程、泛型、lambda表达式、模块、记录、密封类和Swing。另外,还介绍了Java的交互式编程工具JShell。本书通俗易懂、简明扼要、详略得当,成为全球数百万读者的选择。

作者简介

[美]赫伯特·希尔特(Herbert Schildt)
Herbert是Java语言领域的权威专家,拥有伊利诺伊大学的学士和硕士学位。被International Developer杂志评为“全球最著名的编程书籍创作者之一”“。他撰写的编程书籍在全球范围内销售了数百万册,已被翻译 成所有主要的非英语语言。他撰写了大量Java方面的书籍,包括Java: The Complete Reference、Herb Schildt’s Java Programming Cookbook、Introducing JavaFX 8 Programming和 Swing: A Beginner’s Guide。还撰写了许多关于C、C++和C#的图书。Ed Burns在Secrets of the Rock Star Programmers: Riding the IT Crest一书中将Herbert列为明星程序员。尽管对计算机的所有方面都感兴趣,但Herbert主要关注计算机语言。

购书链接:点此进入

在这里插入图片描述

最后我们该如何学习?

1、看视频进行系统学习

这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。

另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

2、读源码,看实战笔记,学习大神思路

“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。

Spring源码深度解析:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Mybatis 3源码深度解析:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Redis学习笔记:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

Spring Boot核心技术-笔记:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

3、面试前夕,刷题冲刺

面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。

关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:

1年半经验,2本学历,Curd背景,竟给30K,我的美团Offer终于来了

只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。

人生短暂,别稀里糊涂的活一辈子,不要将就。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:xhs1999xhs (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
1、看视频进行系统学习

这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。

另外,我自己也珍藏了好几套视频资料躺在网盘里,有需要的我也可以分享给你:

[外链图片转存中…(img-E8Fi57AD-1713686639462)]

2、读源码,看实战笔记,学习大神思路

“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。阅读源码,是解决问题 + 理解事物,更重要的:看到源码背后的想法;程序员说:读万行源码,行万种实践。

Spring源码深度解析:

[外链图片转存中…(img-wQ09bHET-1713686639463)]

Mybatis 3源码深度解析:

[外链图片转存中…(img-vY2sM4mY-1713686639463)]

Redis学习笔记:

[外链图片转存中…(img-hfubbXWS-1713686639463)]

Spring Boot核心技术-笔记:

[外链图片转存中…(img-DPAv2NEw-1713686639464)]

3、面试前夕,刷题冲刺

面试的前一周时间内,就可以开始刷题冲刺了。请记住,刷题的时候,技术的优先,算法的看些基本的,比如排序等即可,而智力题,除非是校招,否则一般不怎么会问。

关于面试刷题,我个人也准备了一套系统的面试题,帮助你举一反三:

[外链图片转存中…(img-hTGUgkOL-1713686639464)]

只有技术过硬,在哪儿都不愁就业,“万般带不去,唯有业随身”学习本来就不是在课堂那几年说了算,而是在人生的旅途中不间断的事情。

人生短暂,别稀里糊涂的活一辈子,不要将就。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:xhs1999xhs (备注Java)
[外链图片转存中…(img-Dc4C4pka-1713686639464)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 26
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值