Spring Boot是一个开源的Java框架,它简化了基于Spring的应用程序的配置和部署过程。它的工作原理可以概括为以下几个步骤:
自动配置:Spring Boot根据项目中的依赖和配置信息,自动配置应用程序所需的各种组件和功能。
启动类:Spring Boot应用程序的入口点是一个特殊的启动类,通常使用@SpringBootApplication
注解来标记。该注解会开启自动配置,并扫描注解的包及其子包中的组件。
组件扫描:Spring Boot会自动扫描并注册被@Component
、@Service
、@Controller
等注解标记的组件。这些组件会被Spring容器管理,可以通过依赖注入的方式来使用。
属性配置:Spring Boot提供了一种方便的方式来配置应用程序的属性。可以通过在application.properties
或application.yml
文件中定义属性,或者使用@ConfigurationProperties
注解将属性绑定到Java对象上。
Web应用:如果应用程序是一个Web应用,Spring Boot会自动配置内嵌的Tomcat服务器,并根据类路径中存在的依赖自动配置Spring MVC。可以使用@RestController
、@RequestMapping
等注解来定义RESTful API。
自动装配:Spring Boot通过条件注解和自动配置类实现自动装配。自动配置类根据条件判断是否需要进行自动配置,如果满足条件,则会将相应的组件注册到Spring容器中。
启动应用:Spring Boot应用程序可以通过命令行、IDE或打包成可执行的JAR文件来启动。在启动过程中,Spring Boot会加载自动配置,并根据配置信息初始化应用程序所需的各种组件。
总的来说,Spring Boot通过自动配置和约大于配置的原则,简化了开发人员的工作,使得开发和部署Spring应用程序更加简单和高效。它提供了一种快速搭建和开发Java应用程序的方式,同时也保留了Spring框架的灵活性和扩展性。
事务在逻辑上是一组操作,要么执行,要不都不执行。主要是针对数据库而言的,比如说 MySQL。
为了保证事务是正确可靠的,在数据库进行写入或者更新操作时,就必须得表现出 ACID 的 4 个重要特性:
原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
事务隔离(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
其中,事务隔离又分为 4 种不同的级别,包括:
读未提交(Read uncommitted),最低的隔离级别,允许“脏读”(dirty reads),事务可以看到其他事务“尚未提交”的修改。如果另一个事务回滚,那么当前事务读到的数据就是脏数据。
读已提交(read committed),一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。
可重复读(repeatable read),一个事务可能会遇到幻读(Phantom Read)的问题。幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
串行化(Serializable),最严格的隔离级别,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。虽然 Serializable 隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用 Serializable 隔离级别。
需要格外注意的是:事务能否生效,取决于数据库引擎是否支持事务,MySQL 的 InnoDB 引擎是支持事务的,但 MyISAM 就不支持。
Spring 事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring 是无法提供事务功能的。Spring 只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过数据库自己的事务机制实现。
Spring 支持编程式事务管理和声明式事务管理两种方式:
后者最常见,通常情况下只需要一个 @Transactional 就搞定了
1.编程式事务
编程式事务管理使用 TransactionTemplate,需要显式执行事务。
编程式事务是指将事务管理代码嵌入嵌入到业务代码中,来控制事务的提交和回滚。
就编程式事务管理而言,Spring 更推荐使用 TransactionTemplate。
在编程式事务中,必须在每个业务操作中包含额外的事务管理代码,就导致代码看起来非常的臃肿,但对理解 Spring 的事务管理模型非常有帮助。
声明式事务
声明式事务管理建立在 AOP 之上的。其本质是通过 AOP 功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务
优点是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过 @Transactional 注解的方式,便可以将事务规则应用到业务逻辑中,减少业务代码的污染。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
**1. 编程式事务 当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务。
脏读、不可重复读、幻象读概念说明:
a.脏读:指当一个事务正字访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
b.不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。
c.幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中)
Spring框架是一个强大而灵活的Java开发框架,具有以下主要特性:
轻量级和非侵入性:Spring框架采用轻量级设计,不依赖于任何特定的容器或服务器。它可以与其他框架和库无缝集成,并且没有硬性规定的代码结构。
控制反转(IoC):Spring通过控制反转实现了松耦合的组件之间的依赖关系管理。它将对象的创建和依赖注入交给了Spring容器来管理,通过配置文件或注解来描述组件之间的关系。
面向切面编程(AOP):Spring提供了AOP支持,使得开发者能够将应用程序的关注点(例如日志记录、事务管理等)与核心业务逻辑分离,提高代码的可维护性和复用性。
面向切面编程(AOP):Spring 支持面向切面编程,可以用来实现功能的横切,比如日志记录、性能统计、安全检查等。
容器管理:Spring框架提供了一个容器来管理和配置Java对象的生命周期以及依赖关系。这个容器可以在应用程序中加载并管理bean,实现了对象的创建、初始化、销毁和依赖注入等功能。
数据访问支持:Spring框架提供了对各种数据访问技术的支持,包括JDBC、ORM框架(如Hibernate、MyBatis)、JPA等。它简化了数据访问层的开发,提供了事务管理、连接池和异常处理等功能。
MVC框架:Spring框架提供了一个灵活的MVC框架,用于构建Web应用程序。它基于**模型-视图-控制器(MVC)**设计模式,通过分离业务逻辑和展示逻辑,使得Web应用程序的开发更加简单和可维护。
安全性:Spring框架提供了全面的安全性支持,包括认证、授权、加密和访问控制等它可以集成到各种应用中,保护应用程序免受潜在的攻击和威胁。
总结起来,Spring框架具有轻量级、非侵入性、IoC、AOP、容器管理、数据访问支持、MVC框架和安全性等重要特性,使得Java开发变得更加简单、高效和可扩展。
实现AOP的技术,主要分为两大类:
一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
AOP(面向切面编程)是一种编程范式,旨在通过将横切关注点(Cross-cutting Concerns)与核心业务逻辑分离,来提高代码的可维护性和复用性。
在传统的面向对象编程中,程序的功能被组织成一个个类和方法。然而,某些功能并不只属于单个类或方法,它们跨越多个类和方法,称为横切关注点。例如,日志记录、事务管理、安全性检查等都是横切关注点。这些横切关注点通常散布在整个应用程序中,导致代码的重复和耦合性增加。
AOP通过将这些横切关注点从核心业务逻辑中分离出来,以模块化的方式进行管理。它通过在程序执行过程中动态地将额外的功能(称为切面)织入到横切关注点所在的位置上,实现了对核心业务逻辑的增强。这样,我们就可以将这些横切关注点的实现逻辑放在一个或多个切面中,而不需要在每个类或方法中重复编写相同的代码。
AOP的核心概念包括切面(Aspect)、连接点(Join Point)、切点(Pointcut)、通知(Advice)和织入(Weaving)等:
AOP可以与各种编程语言和框架结合使用,例如Java中的Spring框架和.NET中的AspectJ。它提供了一种灵活、可重用和模块化的方式来处理横切关注点,使得代码更加清晰、可维护和可测试。
Filter:
过滤器基于函数回调;
过滤器依赖于servlet容器;
过滤器几乎对所有的请求都起作用;
过滤器只能在容器初始化时被调用一次;
interceptor:
拦截器是基于java的反射机制;
拦截器只能对action请求起作用;
在action的生命周期中,拦截器可以多次被调用;
Filter是在servlet规范中定义的,是Servlet容器支持的,而拦截器是在spring容器内的,是spring框架支持的。
①:拦截器是基于java的反射机制,而过滤器基于函数回调。
②:过滤器依赖于servlet容器,拦截器不依赖于servlet容器。
③:拦截器只能对action请求起作用,而过滤器几乎对所有的请求都起作用。
④:拦截器可以访问action上下文,值栈里的对象,而过滤器不能。
⑤:在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
1、@Controller:用于标注控制器层组件
2、@Service:用于标注业务层组件
3、@Component : 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称
4、@Repository:用于标注数据访问组件,即DAO组件
5、@Bean:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = “beanID”)指定组件名
6、@Scope(“prototype”):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。
由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。
7、@Autowired:默认按类型进行自动装配。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
8、@Resource:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按类型装配。
简单点说,就是,能够明确该类是一个控制器类组件的,就用@Controller;能够明确是一个服务类组件的,就用@Service;能够明确该类是一个数据访问组件的,就用@Repository;不知道他是啥或者不好区分他是啥,但是就是想让他动态装配的就用@Component。
@Controller、@Service、@Component、@Repository都是类级别的注解,如果一个方法也想动态装配,就用@Bean。
当我们想按类型进行自动装配时,就用@Autowired;当我们想按名称(beanID)进行自动装配时,就用@Resource;当我们需要根据比如配置信息等来动态装配不同的组件时,可以用getBean(“beanID”)。
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写。它基于JavaScript语法,但可以被多种编程语言使用。JSON采用键值对的方式组织数据,常用于Web应用程序中的数据传输和存储。
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于前后端之间的数据传输。它以键值对的形式组织数据,并使用大括号 {}
来表示一个对象。
JSON无论对于人,还是对于机器来说,都是十分便于阅读和书写的,而且相比 XML(另一种常见的数据交换格式),文件更小,因此迅速成为网络上十分流行的交换格式。
实例化:抽象类不能被直接实例化,只能作为父类被继承。子类需要继承抽象类并实现其中的抽象方法,才能创建实例。接口也不能被直接实例化,但是可以通过实现接口的类来实例化。
①抽象类可以定义构造器但接口不行;
②抽象类里面可以定义抽象方法也可以定义具体方法,但**接口里面只能定义抽象方法;**不能实现方法
③一个类可以实现多个接口但只能继承一个抽象类;
④接口中不能有静态方法,且定义的变量均为常量,抽象类中可以有静态方法且可以定义成员变量;
⑤接口中的方法必须是public的,而抽象类可以有其它属性;
后端接收参数的几种方式和注解
第一种:@RequestParam注解
作用:将指定的请求参数赋值给方法中的形参。
接收形式:Get传参请求
属性:
1、value:绑定请求的参数名,默认绑定为同名的形参。
2、required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报错。
3、defaultValue:默认值,表示如果请求中没有接收到值时的默认值。
用法示例:
@GetMapping("/test")
public void test(@RequestParam(required = true)String name,@RequestParam(defaultValue = "20")Integer age) {
System.out.println("name:"+name+",age:"+age);
}
@RestController
public class UserController {
@GetMapping("/user")
public String getUserInfo(@RequestParam("username") String username,
@RequestParam("password") String password){
return username+"\n"+password;
}
}
第二种:@PathVariable注解
作用:接收请求路径中占位符的值。
接收形式:Get路径请求。
属性:value:String类型,绑定请求的参数名,默认绑定为同名的形参。
用法示例
@GetMapping("/selectOne/{id}")
public void test(@PathVariable Integer id) {
System.out.println("id:"+id);
}
第三种:@RequestBody注解
作用:接收前端传递的Json对象的字符串
接收形式:Post请求
示例
@PostMapping("/test")
public void test(@RequestBody User user){
System.out.println("user:"+user);
}
加锁
Lock锁机制
通过创建Lock对象,采用lock()加锁,unlock()解锁,来保护指定的代码块
同步方法
使用同步方法(synchronized method):将需要保证线程安全的方法声明为synchronized
,这样只有一个线程能够进入该方法,其他线程需要等待。例如:
public synchronized void increment() {
// 线程安全的操作
}
同步代码块
使用同步代码块(synchronized block):使用synchronized
关键字对需要保证线程安全的代码块进行同步。例如:
public void increment() {
synchronized (this) {
// 线程安全的操作
}
}
使用原子类(Atomic classes):使用java.util.concurrent.atomic
包中的原子类来执行线程安全的操作。原子类提供了一些基本的原子操作,例如增加、减少和更新等。例如:
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
使用线程安全的集合(Thread-safe collections):Java提供了一些线程安全的集合类,例如java.util.concurrent.CopyOnWriteArrayList
、java.util.concurrent.ConcurrentHashMap
等。这些集合类在多线程环境下提供了安全的访问和修改操作。