先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
- @ModelAttribute:该Controller的所有方法在调用前,限制性此方法,可用于注解和方法参数中,可以把这个ModelAttribute特性,应用在BaseController中,所有的Controller继承BaseCotroller,即可实现在调用Controller时,先执行@ModelAttribute方法。
@RestController与@Controller的区别是什么?
Controller 返回一个页面:单独使用 @Controller 不加 @ResponseBody的话一般使用在要返回一个视图的情况,这种情况属于比较传统的Spring MVC 的应用,对应于前后端不分离的情况。
@RestController (等价于@Controller +@ResponseBody)返回JSON 或 XML 形式数据:@RestController只返回对象,对象数据直接以 JSON 或 XML 形式写入 HTTP 响应(Response)中,这种情况属于 RESTful Web服务,这也是目前日常开发所接触的最常用的情况(前后端分离)。
@ResponseBody 注解的作用是将 Controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到HTTP 响应(Response)对象的 body 中,通常用来返回 JSON 或者 XML 数据,返回 JSON 数据的情况比较多。
RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
RequestMapping注解有六个属性:
-
value: 指定请求的实际地址,指定的地址可以是URI Template 模式;
-
method: 指定请求的method类型, GET、POST、PUT、DELETE等;
-
consumes: 指定处理请求的提交内容类型(Content-Type),例如application/json,text/html;
-
produces: 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回;
-
params: 指定request中必须包含某些参数值是,才让该方法处理。
-
headers: 指定request中必须包含某些指定的header值,才能让该方法处理请求
-
作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。
-
@Component通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中)。@Bean 注解通常是我们在标有该注解的方法中定义产生这个 bean,@Bean告诉了Spring这是某个类的示例,当我需要用它的时候还给我。
-
@Bean 注解比 Component 注解的自定义性更强,而且很多地方我们只能通过 @Bean 注解来注册bean。比如当我们引用第三方库中的类需要装配到 Spring容器时,则只能通过 @Bean来实现。
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
//上面的代码相当于下面的 xml 配置
@PathVariable和@RequestParam的区别
-
请求路径上有个id的变量值,可以通过@PathVariable来获取
@RequestMapping(value =“/page/{id}”, method = RequestMethod.GET)
-
@RequestParam用来获得静态的URL请求入参 spring注解时action里用到。
-
@Autowired可用于:构造函数、成员变量、Setter方法,@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
-
@Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入。
Bean Factory和 Application Context有什么区别?
Applicationcontext是 Beanfactory的子接口,ApplicationContext提供了更完整的功能:
-
①继承 Messagesource,因此支持国际化
-
②统一的资源文件访问方式。
-
③提供在监听器中注册bean的事件。
-
④同时加载多个配置文件。
-
⑤载入多个(有继承关系)上下文,使得每个上下文都专注于一个特定的层次,比如应用的web层。
加载方式:
- Bean Factroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时调用 getbean(),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的 Spring的配置问题。如果Bean的某一个属性没有注入, Beanfacotry加载后,直至第一次使用调用 getbean方法才会抛出异常。
- Applicationcontext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现 spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 Applicationcontext启动后预载入所有的单实例Bean,通过预载入单实例bean,确保当你需要的时候,不需要等待,直接使用。
创建方式:
Bean Factory通常以编程的方式被创建, Applicationcontext还能以声明的方式创建,如使用ContextLoader。
注册方式:
Bean Factory和 Application Context,都支持 Bean Postprocessor、 Beanfactory Postprocessor的使用,但两者之间的区别是: Beanfactory需要手动注册,而 Applicationcontext则是自动注册。
相对于基本的 Beanfactory, Applicationcontext唯的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。
-
FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。
-
ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。
-
WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean
解析类-》加载对象-》依赖注入-》回调Aware方法-》后置处理器处理(初始化及初始化前后)-》使用-》销毁
-
Bean 容器解析类得到配置文件中 Spring Bean 的定义(BeanDefinition)。(解析)
-
Bean 容器利用 Java Reflection API 创建一个Bean的实例。(加载对象)
-
如果涉及到一些属性值(加了@Autowride注解的属性)利用 set()方法给对象设置属性。(依赖注入)
-
回调Aware方法:如果实现了其他
*.Aware
接口,就调用相应的方法。(回调Aware方法)
①如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。
②如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
-
如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor对象,执行postProcessBeforeInitialization() 方法。(后置处理器初始化前方法)
-
如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。(初始化方法)
-
如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
-
如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法。(后置处理器初始化后方法,会进行AOP)
-
当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
-
当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。
图示:
后置处理器BeanPostProcessor :在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。后置处理器分为 Bean Factory后置处理器(视线了Spring的扫描)和Bean后置处理器(实现了@ Autowired注解的属性自动赋值、AOP)
bean 标签有两个重要的属性(init-method和destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解
-
singleton(单例模式,默认) : 每个容器中只有一个bean的实例,单例的模式由 Beanfactory自身来维护。该对象的生命周期是与 Spring IOC容器一致的(但在第一次被注入时才会创建)。
-
prototype (原型模式): 每次请求都会创建一个新的 bean 实例。在每次注入时都会创建个新的对象
-
request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
-
session:每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
-
application:bean被定义为在 Servletcontext的生命周期中复用一个单例对象(可以实现跨容器)
-
global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。
存在安全问题的。Spring中的bean默认是单例模式的,框架并没有对bean进行多线程的封装处理,当多个线程操作同一个对象的时候,对这个对象的成员变量的写操作会存在线程安全问题。
但是大多数bean都是无状态的(不具有数据存储功能),比如说controller、 service和dao层,我们一般只是调用里面的方法,多线程调用一个实例的方法,会在内存中复制变量,这是自己的线程的工作内存,是安全的。但是dao层会操作数据库 Connection, Connection是带有状态的,比如说数据库事务, Spring的事务管理器,需要我们进行处理。
因此,不要在bean中声明任何有状态的实例变量或类变量,如果必须如此,可以参考一下方案:
-
使用 Threadloca把变量变为线程私有的,比如在dao层,可以使用Threadlocal为不同线程维护了一套独立的 connection副本,保证线程之间不会互相影响。
-
改变 Bean 的作用域为 “prototype”:每次请求都会创建一个新的 bean 实例,自然不会存在线程安全问题。
-
如果bean的实例变量或类变量需要在多个线程之间共享,那么就只能使用 synchronized、OCK、CAS等这些实现线程同步的方法了。
-
工厂设计模式: 由一个工厂类根据传入的参数,动态决定创建那个产品类。Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建bean 对象。
-
单例设计模式 : 保证一个类仅有一个实例,并提供一个访问它的全局访问点。Spring 中的 Bean 默认都是单例的。
-
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式(HandlerAdapter)适配Controller,对应的每一种Controller都有一种对应的适配器实现类。
-
代理设计模式 : Spring AOP 功能的实现。AOP把切面应用到对象并创建新的代理对象。
-
观察者模式:Spring的事件驱动模型使用的是观察着模式,Spring中Observer模式常用的地方是Listener的实现。
-
策略模式:Spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力,Spring框架本身大量使用了Resource的接口来访问底层资源。
-
装饰器模式:动态地给一个对象添加额外的职责。Spring中类名包括Wrapper或Decorator使用了装饰器模式。
-
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。
-
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
Spring 管理事务的方式有几种?
-
编程式事务,在代码中硬编码。(不推荐使用)
-
声明式事务,在配置文件中配置(推荐使用)
声明式事务又分为:
-
基于XML的声明式事务
-
基于注解的声明式事务
说一下 Spring的事务机制
-
spring事务底层是基于数据库事务和AOP机制的(事务这个概念是数据库层面的, Spring只是基于数据库中的事务进行了扩展)
-
首先对于使用了@Transactional注解的bean,Spring会创建一个代理对象作为Bean
-
当调用代理对象的方法时,会先判断该方法上是否加了@ Transactional注解
-
如果加了,那么则利用事务管理器创建一个数据库连接,并把事务的自动提交设置为 false,然后再去执行原本的业务逻辑方法(sql)。
-
如果执行业务逻辑方法没有出现异常,那么代理逻辑中就会将事务进行提交
-
如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚
-
针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的 rollbackfor属性进行配置,默认情况下会对 Runtimeexception和Error进行回滚。
-
Spring事务的隔离级别对应的就是数据库的隔离级别
-
Spring事务的传播机制是 Spring事务自己实现的,也是 Spring事务中最复杂的
-
Spring事务的传播机制是基于数据库连接来做的,一个数据库连接一个事务,如果传播机制配置为需要新开个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql
Exception分为运行时异常RuntimeException和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
当@Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
@Transactional(rollbackFor = Exception.class):
在@Transactional注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。
spring事务的原理是AOP,进行了切面增强,那么失效的根本原因是这个AOP不起作用了。常见情况有如下几种:@Transactional标识的方法只有被代理对象调用时,注解才会生效
-
发生自调用,类里面使用this调用本类的方法,此时这个this对象不是代理类,而是Userservice对象本身(解决方法很简单,让那个this变成 Euserservice的代理类即可)
-
方法不是public的,Transactional只能用于public的方法上,否则事务不会失效,如果要用在非public方法上,可以开启( Aspectj代理模式)。
-
异常被吃掉,事务不会回滚或者抛出的异常没有被定义,默认为 RuntimeException。
spring事务隔离级别就是数据库的隔离级别:外加一个默认级别
-
isolation_default(默认级别):使用后端数据库默认的隔离级别
-
read_uncommitted(读未提交读):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
-
read_committed(读以提交、不可重复读):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
-
repeatable_read(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
-
serializable(可串行化):最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
数据库的配置隔离级别是 Read Commited,而 Spring配置的隔离级别是 Repeatable Read,请问这时隔离级别是以哪个为准?
以 Spring配置的为准,如果 spring设置的隔离级别数据库不支持,效果取决于数据库
多个事务方法相互调用时事务如何在这些方法间传播:
方法A是一个事务的方法,方法A执行过程中调用了方法B,那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响,同时方法A的事务对方法B的事务执行也有影响,这种影响具体是什么就由两个方法所定义的事务传播类型所决定。
-
REQUIRED(Spring默认的事务传播类型):如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务
-
SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行
-
MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则拋出异常
-
REQUIRES_NEW:创建一个新事务,如果存在当前事务,则挂起该事务
-
NOT_SUPPORTED:以非事务方式执行如果当前存在事务,则挂起当前事务
-
NEVER:不使用事务,如果当前事务存在,则抛出异常
-
NESTED:如果当前事务存在,则在嵌套事务中执行,否则 REQUIRED的操作一样(开启一个事务)
NESTED和 REQUIRES_NEW的区别:
REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关,而 NESTED则是当前存在事务时(我们把当前事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。在 NESTED情况下父事务回滚时,子事务也会回滚,而在REQUIRES_NEW情况下,原有事务回滚,不会影响新开启的事务
NESTED和 REQUIRED的区别:
REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一事务,那么被调用方出现异常时,由于共用一个事务,所以无论调用方是否 catch其异常,事务都会回滚而在 NESTED情况下,被调用方发生异常时,调用方可以 catch其异常,这样只有子事务回滚,父事务不受影响。
最后
每年转战互联网行业的人很多,说白了也是冲着高薪去的,不管你是即将步入这个行业还是想转行,学习是必不可少的。作为一个Java开发,学习成了日常生活的一部分,不学习你就会被这个行业淘汰,这也是这个行业残酷的现实。
如果你对Java感兴趣,想要转行改变自己,那就要趁着机遇行动起来。或许,这份限量版的Java零基础宝典能够对你有所帮助。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
用方是否 catch其异常,事务都会回滚而在 NESTED情况下,被调用方发生异常时,调用方可以 catch其异常,这样只有子事务回滚,父事务不受影响。
最后
每年转战互联网行业的人很多,说白了也是冲着高薪去的,不管你是即将步入这个行业还是想转行,学习是必不可少的。作为一个Java开发,学习成了日常生活的一部分,不学习你就会被这个行业淘汰,这也是这个行业残酷的现实。
如果你对Java感兴趣,想要转行改变自己,那就要趁着机遇行动起来。或许,这份限量版的Java零基础宝典能够对你有所帮助。
[外链图片转存中…(img-xzbie7i6-1713420027933)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-NYth9xmY-1713420027933)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!