先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
依赖注入的过程?
getBean方法获取Bean实例,该方法调用doGetBean,doGetBean真正实现从IOC容器获取Bean的功能,也是触发依赖注入的地方。
具体创建Bean对象的过程是由ObjectFactory的createBean完成的,该方法主要通过createBeanInstance方法生成Bean包含的Java对象实例和populateBean方法对Bean属性的依赖注入进行处理。
在populateBean方法中,注入过程主要分为两种情况:
1.属性值类型不需要强制转换时,不需要强制类型转换时,不需要解析属性值,直接进行依赖注入。
2.属性类型需要强制转换时。
-
首先解析属性值;
-
然后对解析后的属性值进行依赖注入。
-
依赖注入的过程就是将Bean对象实例设置到它所依赖的Bean对象的属性上。
-
真正的依赖注入是通过setPropertyValues方法实现的,该方法使用了委派模式。
BeanWrapperImpl类负责对完成初始化的Bean对象进行依赖注入
-
对于非集合类型属性,使用JDK反射,通过属性的setter方法为属性设置注入后的值;
-
对于集合类型的属性,将属性值解析为目标类型的集合直接赋值给属性。
当容器对Bean的定位、载入、解析和依赖注入完成后就不再需要手动创建对象,IOC容器会自动为我们创建对象并且依赖注入。
Bean的生命周期
=========
-
Spring容器读取XML配置文件中bean定义并实例化Bean;
-
Spring根据Bean的定义设置属性值;
-
如果该Bean实现了BeanNameAware接口,Spring将Bean的id传递给setBeanName()方法;
-
如果该Bean实现了BeanFactoryAware接口,Spring将BeanFactory传递给setBeanFactory()方法;
-
如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
-
如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
-
如果bean实现了InitializingBean接口,Spring将调用它们的after-PropertiesSet()方法。类似地,如果bean使用initmethod声明了初始化方法,该方法也会被调用。
此时Bean就已经准备就绪了,可以被应用程序使用了,他们一直驻留在容器中,直到容器被销毁。
- 果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
自己定制初始化和注销方法
XML 方式通过配置 bean 标签中的 init-Method 和 destory-Method 指定自定义初始化和销毁方法。
注解方式通过 @PreConstruct 和 @PostConstruct 注解指定自定义初始化和销毁方法。
Bean的作用范围
通过scope属性指定bean的作用范围,包括:
-
singleton:单例模式,是默认作用域,不管收到多少Bean请求每个容器中只有一个唯一的Bean实例
-
prototype:原型模式,和singleton相反,每次Bean请求都会创建一个新的实例
-
request:每次HTTP请求都会创建一个新的Bean并把它放到request域中,在请求完成之后Bean会失效并被垃圾收集器回收
session:和request类似,确保每个session中有一个Bean实例,session过期后Bean会随之失效
- global session:当应用部署在Portlet容器时,如果想让Portlet公用全局存储变量,那么该变量需要存储在global session中
Bean线程安全性
Spring的单例Bean不是线程安全的
Spring中的Bean默认是单例模式,Spring框架中没有对单例Bean进行多线程的封装处理。
实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
-
有状态:有数据存储功能
-
无状态:不会保存数据
Spring如何处理线程并发问题
只有无状态的Bean才会在多线程下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据访问的冲突,因为每一个线程都拥有自己的变量副本,从而就没有必要对该变量进行同步,ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
扩展问题
====
创建Bean的方式
xml
-
默认无参构造方法,只需要指明 bean 标签中的 id 和 class 属性,如果没有无参构造方***报错。
-
静态工厂方法,通过 bean 标签中的 class 属性指明静态工厂,factory-method 属性指明静态工厂方法。
-
实例工厂方法,通过 ean 标签中的 factory-bean 属性指明实例工厂,factory-method 属性指明实例工厂方法。
注解
@Component 把当前类对象存入 Spring 容器中,相当于在 xml 中配置一个 bean 标签。value 属性指定 bean 的 id,默认使用当前类的首字母小写的类名。
@Controller,@Service,@Repository 三个注解都是 @Component 的衍生注解,作用及属性都是一模一样的。只是提供了更加明确语义,@Controller 用于表现层,@Service用于业务层,@Repository用于持久层。如果注解中有且只有一个 value 属性要赋值时可以省略 value。
如果想将第三方的类变成组件又没有源代码,也就没办法使用 @Component 进行自动配置,这种时候就要使用 @Bean 注解。被 @Bean 注解的方法返回值是一个对象,将会实例化,配置和初始化一个新对象并返回,这个对象由 Spring 的 IoC 容器管理。
name 属性用于给当前 @Bean 注解方法创建的对象指定一个名称,即 bean 的 id。当使用注解配置方法时,如果方法有参数,Spring 会去容器查找是否有可用 bean对象,查找方式和 @Autowired 一样。
BeanFactory、FactoryBean和ApplicationContext的区别?
==============================================
BeanFactory(”低级容器")
BeanFactory是一个Bean工厂,使用简单工厂模式,是Spring IOC容器的顶级接口,可以理解为含有Bean集合的工厂,作用是管理Bean,包括实例化、定位、配置对象及建立这些对象间的依赖。BeanFactory 实例化后并不会自动实例化 Bean,只有当 Bean 被使用时才实例化与装配依赖关系,属于延迟加载,适合多例模式。
FactoryBean
FactoryBean是一个工厂Bean,使用了工厂方法模式,作用是生产其他Bean实例,可以通过实现该接口,提供一个工厂方法来自定义实例化Bean的逻辑,FactoryBean接口有BeanFactory中的配置实现,,这些对象本身就是用于创建对象的工厂,如果一个 Bean 实现了这个接口,那么它就是创建对象的工厂 Bean,而不是 Bean 实例本身。
ApplicationContext(”高级容器“)
ApplicationContext是BeanFactory的子接口,扩展了BeanFactory的功能,提供了支持国际化的文本消息,统一的资源文件读取方式,事件传播以及应用层的特别配置等。该接口定义了一个refresh方法,用于刷新整个容器,即重新加载/刷新所有的bean。容器会在初始化时对配置的 Bean 进行预实例化,Bean 的依赖注入在容器初始化时就已经完成,属于立即加载,适合单例模式,一般推荐使用。
实现类:
-
ClassPathApplicationContext:只能读取路径下的配置文件(推荐使用)。
-
FileSystemXmlApplicationContext:可以读取任意硬盘路径的配置文件,你可以点击根目录下的文件的属性查看他在本地硬盘的位置。
-
AnnotationConfigApplicationContext:读取注解配置类。
Spring AOP
==========
AOP是什么?
AOP(Aspect-Oriented Programming)即面向切面编程,简单地说就是将代码中重复的部分抽取出来,在需要执行的时候使用动态代理技术,在不修改源码的基础上对方法进行增强,减少了系统的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
常见的场景包括:权限认证、自动缓存、错误处理、日志、调试和事务。
动态代理
====
JDK
Spring根据类是否实现接口来判断动态代理的方式,如果实现接口会使用JDK动态代理,核心是InvocationHandler接口和Proxy类,JDK动态代理主要通过重组字节码实现,首先获得被代理对象的引用和所有接口,生成新的类必须实现代理类的所有接口,动态生成Java代码后编译生成新的.class文件并重新加载到JVM运行。JDK代理直接写Class字节码。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入口, 在方法反射调用时使用。
CGLIB
-
如果代理类没有实现InvocationHandler接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
-
CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中的特定方法并添加增强代码。
-
采用ASM框架写字节码,生成代理类的效率低,但是CGLIB调用方法的效率高,因为JDK使用反射调用方法。
-
CGLIB使用FastClass机制为代理类和被代理类各生成一个子类,这个类会为代理类或者被代理类的方法生成一个index,这个index可以作为参数直接定位要调用的方法。
-
如果没有实现接口会使用CGLIB是运行时动态生成某个类的子类,如果某个类被标记为final,不能使用CGLIB。
AOP相关术语
Aspect:切面是通知和切点的结合。通知和切点共同定义了切点的全部内容,在Spring AOP中,切面可以使用通用类(基于模式的风格)或者在普通类中以@AspectJ注解来实现。
Joinpoint:指连接点,在SpringAOP中,一个连接点总是代表一个方法的执行。应用可能有数以千计应用通知。这些时机被称为连接点。连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
Advice:通知,指切面对于某个连接点所产生的动作,包括:
-
前置通知(Before)
-
后置通知(After)
-
返回后通知(AfterReturning)
-
异常通知(AfterThrowing)
-
环绕通知(Around)
Pointcut:切入点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或是利用正则表达式定义所匹配的类和方法名称来指定这些切点。
Proxy:代理,Spring AOP 中有 JDK 动态代理和 CGLib 代理,目标对象实现了接口时采用 JDK 动态代理,反之采用 CGLib 代理。
Target:代理的目标对象,指一个或多切面所通知的对象。
Weaving :织入,指把增强应用到目标对象来创建代理对象的过程。
-
编译期:切面在目标类编译时被织入。AspectJ的织入编译器是以这种方式织入切面的。
-
类加载期:切面在目标类加载到JVM时被织入。需要特殊的类加载器,它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入就支持以这种方式织入切面。
-
运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面。
AOP的过程
SpringAOP由BeanPostProcessor后置处理器开始,这个后置处理器是一个监听器,可以监听容器触发的Bean生命周期事件,向容器注册后置处理器以后,容器中管理的Bean就具备了接收IOC容器回调事件的能力。BeanPostProcessor 的调用发生在 Spring IoC 容器完成 Bean 实例对象的创建和属性的依赖注入后,为 Bean 对象添加后置处理器的入口是 initializeBean 方法。
AOP工作中心在于如何将增强编织到目标对象的连接点上,这里包含两个动作
-
如何通过pointcut和advice定位到特定的joinpoint上
-
如何在advice中编写代码
扩展问题
====
AOP有哪些实现方式
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表是AspectJ,动态代理则以SpringAOP为代表。
SpringAOP 和 AspectJ AOP有什么区别
-
AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强的AOP对象。
-
Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时,在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理。
Spring注解
========
基于Spring注解配置
基于Java的配置,允许在少量Java注解的帮助下,进行大部分Spring的配置而非通过xml文件。
- @Configuration:用于指定当前类是一个Spring配置类,标记类可以当做一个Bean的定义,被IOC容器使用。
value属性用于指定配置类的字节码文件。
-
@Bean:表示此方法要返回一个对象,作为一个Bean注册到Spring应用上下文中。
-
@ComponentScan:用于指定Spring在初始化容器时要扫描的包,basePaceages属性用于指定要扫描的包。
-
@PropertySource:用于加载.properties 文件中的配置。value 属性用于指定文件位置,如果是在类路径下需要加上 classpath。
-
@Import 用于导入其他配置类,在引入其他配置类时可以不用再写 @Configuration 注解。
对象注解
@Component:将java标记为Bean,它是任何Spring管理组件的通用构造型,Spring的组件扫描机制可以将其拾取并拉入容器中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IOC 容器中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。
依赖注入(DI)的相关注解
@Required(已过时):这个注解表明Bean的属性,必须在配置的时候设置,通过一个Bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出
BeanInitializationException。
@Autowired:自动按类型注入,如果有多个匹配则按照指定 Bean 的 id 查找,查找不到会报错,默认情况下,要求对象必须存在(可以设置required为false),可用于构造函数、成员变量、Setter方法。
@Qualifier:在自动按照类型注入的基础上再按照 Bean 的 id 注入,给变量注入时必须搭配,当创建多个相同类型的Bean,并希望仅使用属性装配其中一个 Bean时,您可以使用@Qualifier 注解和 @Autowired 通过指定应该装配哪个确切的 Bean来消除歧义。
@Resource :直接按照 Bean 的 id 注入,当找不到与名称匹配的Bean才会按照类型来装配注入,只能注入 Bean 类型。
@Value :用于注入基本数据类型和 String 类型。
@AutoWired注解自动装配的过程
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />
在启动容器时,容器自动装载了一个
AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowired、@Resource时就会在IOC容器自动查找需要的Bean,并装配给该对象属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
-
如果查询结果刚好为一个,就将该Bean装配给@Autowired指定的数据;
-
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
-
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。
自动装配有哪些局限性?
自动装配的局限性是:
-
重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。
-
基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
-
模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。
AOP的相关注解有哪些?
@Aspect:声明被注解的类是一个切面Bean;
@Before:前置通知,指定某个连接点之前执行的通知;
@After:后置通知,指定某个连接点退出是执行的通知(不论正常返回还是退出);
@AfterReturning:返回后通知,指某连接点正常完成之后的通知,返回值使用returning属性接收;
@AfterThrowing:异常通知,指方法抛出异常导致退出是执行的通知,和@AfterReturning只会有一个执行,异常使用throwing属性接受。
最后的话
无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。
同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!
部分截图:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
,指某连接点正常完成之后的通知,返回值使用returning属性接收;
@AfterThrowing:异常通知,指方法抛出异常导致退出是执行的通知,和@AfterReturning只会有一个执行,异常使用throwing属性接受。
最后的话
无论是哪家公司,都很重视Spring框架技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。
同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,好了希望这篇文章对大家有帮助!
部分截图:
[外链图片转存中…(img-ngwmSqqp-1713418420669)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-jfcNAQEu-1713418420669)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!