Spring基础知识

96 阅读11分钟

Spring

1、Spring是什么?

Spring是一款开源的轻量级Java框架,主要是用来提高Java开发人员的效率

Spring框架包含很多模块:自带的IoC、AOP,集成的第三方组件(任务、调度、缓存)

2、Spring核心模块?

Spring Core:最核心的模块,提供IoC依赖注入

Spring AOP:面向切面的编程实现

Spring Web:

  • Spring-Web:web功能基础支持
  • Spring-WebMvc:提供对SpringMVC的实现
  • Spring-websocket:
  • spring-webflux:

Spring Test:支持Junit

3、Spring、SpringMVC、SpringBoot的区别?

Spring MVC是Spring中的一个模块,主要提供构建MVC架构的Web程序的能力

SpringBoot是在Spring基础上做了一些简化配置的操作,也简化了Spring的开发

4、什么是IoC?

控制反转是一种设计思想。将原本在程序汇总手动创建对象的控制权交给Spring框架来管理

  • 控制:指的是对象创建的权力
  • 反转:控制权交给外部环境(Spring框架、IoC容器)

将对象之间相互依赖的关系交给IoC容器管理,并由IoC容器完成对象的注入。 ,IoC容器实际上就是一个Map(key,value)

org.springframework.beansorg.springframework.context 这两个包是 IoC 实现的基础

5、什么是AOP?

面向切面变成,将一些与业务无关,却为业务模块所共同调用的逻辑和责任(日志、事务处理、权限控制)等封装起来,减少系统的重复代码,降低耦合

 AOP是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理

6、Spring AOP和Aspect AOP的区别?

Spring AOP属于运行时增强,基于代理,AspectJAOP属于编译时增强,基于字节码

7、什么是Spring Bean?

被IoC容器管理的对象成为Spring Bean。通过配置让Spring知道,xml、注解、Java配置类等

如何将一个类声明为Spring Bean:

  • @Component:标注类是组件
  • @Respository:对应的是持久层,也就是DAO层,与数据库相关
  • @Service:对应的是服务层
  • @Controller:对应的是Spring MVC的控制层,接收用户请求并调用服务层返回给前端

8、@Component@Bean的区别?

@Component 是作用在类上的,@Bean注解作用于方法

@Component 通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中

9、使用和注入Bean的时候有哪些注解?

@Autowired:Spring 2.5+。Spring内置注解,默认注入方式是根据类型进行匹配,存在多个满足条件的选择时,会使用名称匹配的注入方式,通常是类名首字母小写

// 报错,byName 和 byType 都无法匹配到 bean
@Autowired
private SmsService smsService;
// 正确注入 按照变量名:SmsServiceImpl1 对象对应的 bean
@Autowired
private SmsService smsServiceImpl1;
// 正确注入  SmsServiceImpl1 对象对应的 bean
// smsServiceImpl1 就是我们上面所说的名称
@Autowired
@Qualifier(value = "smsServiceImpl1")     // 显示指定名称不是依赖变量的名称
private SmsService smsService;

@Resource:JDK提供的注解。默认注入方式是通过名称 byName 注入,如果通过名称无法找到的话,注入方式会变成byType

// 报错,byName 和 byType 都无法匹配到 bean
@Resource
private SmsService smsService;
// 正确注入 SmsServiceImpl1 对象对应的 bean
@Resource
private SmsService smsServiceImpl1;
// 正确注入 SmsServiceImpl1 对象对应的 bean(比较推荐这种方式),显示指定名称
@Resource(name = "smsServiceImpl1")
private SmsService smsService;

@Inject

10、Bean的作用域有哪些?

  • singleton:全局唯一bean实例,Spring 中bean默认都是单例的
  • prototype:每次请求都会创建一个新的bean实例
  • request:每一次http请求都会产生一个新的bean,在本次请求内使用
  • session:每一次来自新 session 的 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效

如何配置Bean的作用域?

xml形式:

<bean id = "..." class="..." scope="singleton"></bean>

注解形式

@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public Person personPrototype() {
  return new Person();
}

11、单例Bean的线程安全问题

有状态的bean:

无状态的bean:

解决办法:

  • 在Bean中避免定义可变的成员变量
  • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal

12、Bean的声明周期###

image.png

image.png

13、Spring MVC

分为三部分:Model、View、Controller,通过这种结构更清晰的实现了API的开发

SoringMVC的工作原理

image.png 流程说明(重要):

  1. 客户端(浏览器)发送请求,直接请求到 DispatcherServlet
  2. DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler
  3. 解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
  4. HandlerAdapter 会根据 Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
  5. 处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View
  6. ViewResolver 会根据逻辑 View 查找实际的 View
  7. DispaterServlet 把返回的 Model 传给 View(视图渲染)。
  8. View 返回给请求者(浏览器)

14、Spring中使用到的设计模式

  • 代理模式:Spring AOP功能的实现
  • 单例模式:Spring中bean默认都是单例的
  • 工厂模式:Spring使用工厂模式通过BeanFactoryApplicationContext 创建 bean 对象
  • 适配器模式 : Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller

Spring事务

1、Spring 管理事务的方式

  • 注解形式:@Transactional

2、事务传播行为

1) required(默认属性)

** Spring中默认传播类型**。TransactionDefinition.PROPAGATION_REQUIRED

如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。 被设置成这个级别时,会为每一个被调用的方法创建一个逻辑事务域。如果前面的方法已经创建了事务,那么后面的方法支持当前的事务,如果当前没有事务会重新建立事务。

2) Mandatory 支持当前事务,如果当前没有事务,就抛出异常。

3) Never 以非事务方式执行,如果当前存在事务,则抛出异常。

4) Not_supports 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

5) requires_new 始终新建事务,如果当前存在事务,把当前事务挂起。

6) Supports 支持当前事务,如果当前没有事务,就以非事务方式执行。

7) Nested 支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。 嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

常用的类型:required、not_supports、requires_new

常问问题:Nested与requires_new的区别?

3、事务隔离级别

5种隔离级别。

Spring事务隔离级别比数据库事务隔离级别多一个default

1) DEFAULT (默认) 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别(RR)

另外四个与JDBC的隔离级别相对应。

2) READ_UNCOMMITTED (读未提交) 这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。

3) READ_COMMITTED (读已提交) 保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。

4) REPEATABLE_READ (可重复读) 这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。

5) SERIALIZABLE(串行化) 这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻读。

4、事务回滚时机

使用方式:@Transactional(rollBackFor="Exception")

 不配置exception时,默认是遇到RuntimeException的时候才会回滚

5、不持久化一个字段方式

static String transient1; // not persistent because of static
final String transient2 = "Satish"; // not persistent because of final
transient String transient3; // not persistent because of transient
@Transient    // 使用该注解,可以将PO对象中的某个字段不持久化到数据库
String transient4; // not persistent because of @Transient

注解

5、Spring、SpringBoot常见注解

@SpringBootApplication:启动类的基础注解,作用相当于=@Configuration@EnableAutoConfiguration@ComponentScan 注解的集合

@Autowire:自动导入对象到类中

@Component @Repository @Service @Controller

@RestController @Controller@ResponseBody的合集

@Scope:声明Spring Bean的作用域

@Configuration :声明配置类,可以使用@Component注解替代

@Post、@Get、@Delete、@Put:http的请求类型

@GetMapping("users")
@RequestMapping(value="/users",method=RequestMethod.GET)

@PostMapping("users")
@RequestMapping(value="/users",method=RequestMethod.POST)

@PutMapping("/users/{userId}")
@RequestMapping(value="/users/{userId}",method=RequestMethod.PUT)

@DeleteMapping("/users/{userId}")
@RequestMapping(value="/users/{userId}",method=RequestMethod.DELETE)

@PathVariable用于获取路径参数,@RequestParam用于获取查询参数。

@RequestBody :用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。一个请求只能有一个**@RequestBody,但是可以有多个@RequestParam@PathVariable**

6、读取配置文件

@Value(${property})

@ConfigurationProperties(prefix = "library")

7、返回Json数据的一些处理

@JsonIgnoreProperties 作用在类上用于过滤掉特定字段不返回或者不解析。

@JsonIgnore一般用于类的属性上

Spring自动装配原理

1、什么是 SpringBoot 自动装配?

通过注解或者一些简单的配置就能在Spring Boot的帮助下实现某种功能

需要引入依赖:spring-boot-starter-XXX

2、SpringBoot 是如何实现自动装配的?如何实现按需加载?

@SpringBootApplication注解,该注解包含三部分:

1、@EnableAutoConfiguration:重点!!!启动SpringBoot的自动配置机制。@EnableAutoConfiguration底层也是通过AutoConfigurationImportSelector类实现的

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

 @EnableAutoConfiguration -> AutoConfigurationImportSelector.class -> ImportSelector 接口 -> selectImports()方法

该方法用于获取所有符合条件的类全限定名,这些类需要被加载到IoC容器中

该类的实现流程:

private static final String[] NO_IMPORTS = new String[0];

public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // <1>.判断自动装配开关是否打开
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
          //<2>.获取所有需要装配的bean
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);     // 重点!!!
            return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
        }
}

private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();

// getAutoConfigurationEntry 的具体实现
AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
        //<1>.
        if (!this.isEnabled(annotationMetadata)) {    // 判断自动装配开关是否打开?默认spring.boot.enableautoconfiguration=true
            return EMPTY_ENTRY;
        } else {
            //<2>.
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);  // 获取EnableAutoConfiguration注解中配置的 exclude 和 excludeName
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);  // 重点!!!
            //<4>.
            configurations = this.removeDuplicates(configurations);

            // 获取SpringBootApplication注解配置上的exclude的配置类,过滤掉
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
          
            // 过滤一遍
            configurations = this.filter(configurations, autoConfigurationMetadata);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

List configurations = this.getCandidateConfigurations(annotationMetadata, attributes); // 重点!!! 例如项目有XXX-starter的依赖,这个依赖下的META-INF/spring.factories被读取到,整个Spring Boot Starter 下的META-INF/spring.factories都会被读取到

每次读取到的XXXConfiguration 也会经过一次过滤

2、@Configuration:允许在上下文中注册额外的bean或者导入其配置

3、@ComponentScan:扫描被@Service、@Component、@Controller注解标注的Bean,默认会扫描启动类本身所在包下所有的类,

@ComponentScan(excludeFilters = {     // 可以指定剔除不加载某些class
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
  • 如何实现一个 Starter?

S1:创建一个模块

S2:定义一个XXXAutoConfiguration的类,使用@Configuration注解标注

S3:模块下resources目录下创建META-INF目录,该目录下添加spring.factories文件,文件中添加org.springframework.boot.autoconfigure.EnableAutoConfiguration=XXXAutoConfiguration(类的全路径名)

Spring 中的设计模式

工厂模式:Spring 使用工厂模式可以通过BeanFactory 或者ApplicationContext创建bean对象

  • BeanFactory :延迟注入(使用到某个 bean 的时候才会注入),相比于ApplicationContext 来说会占用更少的内存,程序启动速度更快。
  • ApplicationContext :容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持,ApplicationContext 扩展了 BeanFactory ,除了有BeanFactory的功能还有额外更多功能,所以一般开发人员使用ApplicationContext会更多。

单例模式:

Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式

private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);  // key是beanName,value是Object对象

Spring Cloud

什么是Spring Cloud?

微服务系统架构的一站式解决方案。提供了一套简易的编程模型:支持服务注册发现、配置中心、消息总线、负载均衡、数据监控等

\