Spring&SpringBoot

一、Spring&SpringBoot

1. Spring简介

  • Spring 是一款目前主流的 Java EE 轻量级开源框架 ,是 Java 世界最为成功的框架之一。Spring 由“Spring 之父”Rod Johnson 提出并创立,其目的是用于简化 Java 企业级应用的开发难度和开发周期。

  • 2004 年 4 月,Spring 1.0 版本正式发布以来,Spring 已经步入到了第 5 个大版本,也就是我们常说的 Spring 5

  • Spring基础的是 Spring Framework,其功能有:

    • IoC – 控制反转,Spring 两大核心技术之一
    • AOP – 面向切面编程,Spring 两大核心技术之一
    • 事务 - 无需编写代码,即可实现数据库事务管理
    • 测试 - 与测试框架集成、web 单元测试
    • MVC - 开发 web 应用程序
    • 缓存 - 对缓存进行抽象
    • 调度 - 延时任务、定时任务
  • Spring Framework 在开发中的作用:

    • 分层解耦 - 让单体应用的可扩展性更强

    • 整合框架 - 整合第三方框架,使之协同工作

    • 实用技术 - 自身强大,提供各种实用功能


Spring体系结构

Spring体系分为应用层技术、中间层技术、底层核心容器和Test测试

  • 应用技术层

    • Data Access:数据访问
    • Data Integration:数据集成
    • web:Web开发
  • 中间层技术

    • AOP:面向切面编程
    • Aspects:AOP思想实现
  • 底层核心容器

    • Core Container:核心容器
  • Test测试:

    • Test:单元测试与集成测试

2. SpringBoot简介

  • Spring Boot 是 Pivotal 团队在 Spring 的基础上提供的一套全新的开源框架,其目的是为了简化 Spring 应用的搭建和开发过程。Spring Boot 去除了大量的 XML 配置文件,简化了复杂的依赖管理
  • Spring Boot 具有 Spring 一切优秀特性,**Spring 能做的事,Spring Boot 都可以做,而且使用更加简单,功能更加丰富,性能更加稳定而健壮。**随着近些年来微服务技术的流行,Spring Boot 也成了时下炙手可热的技术。
  • Spring Boot 集成了大量常用的第三方库配置,Spring Boot 应用中这些第三方库几乎可以是零配置的开箱即用(out-of-the-box),大部分的 Spring Boot 应用都只需要非常少量的配置代码(基于 Java 的配置),开发者能够更加专注于业务逻辑。

二、控制反转(IoC)

  • 控制反转:(Inversion of Control,缩写为IoC)把创建对象的权利交给Spring由Spring创建Bean对象并保存到Spring容器中,也叫IoC容器。

  • 之前对象如何来的?

    new出来的

  • 如果使用了Spring之后,对象那里来?

    由Spring创建并保存到Spring容器/IoC容器中,我们从Spring容器中获取对象

1. 加载Bean

当Spring扫描到以下注解时,就会创建Bean对象保存到Spring容器中

  • @Component –把普通类交给 Spring管理,这个类不属于三层架构中的类
  • @Controller - 把控制器类交给 Spring管理(学习SpringMVC会用到)
  • @Service - 把业务层类交给 Spring管理
  • @Repository - 把数据访问层类交给Spring管理(用得少,因为与 MyBatis 整合)

注意:Spring默认是加载引导类/启动类所在包及其子包中所有带有以上注解的类,创建这些类的对象,保存到Spring容器中。

  • 如果Bean不在引导类/启动类所在包及其子包中,那么就需要在引导类上使用@ComponentScan(“要扫描的包”)注解指定要加载哪个包中的Bean

2. 获取Bean

Spring容器启动时,会把其中的bean都创建好,如果想要主动获取这些 bean,可以使用容器的如下方法

  • 根据类型获取 bean - T getBean(Class requiredType)

    • 可以传递父类型,返回子类型
    • 可以传递接口类型,返回实现类型
  • 根据名称获取 bean - Object getBean(String name)

  • 根据名称和类型获取 bean - T getBean(String name, ClassrequiredType)

2. Bean的范围

在类上使用@scope注解定义Bean的作用域,Spring支持五种作用域,后三种在web环境才生效。

@Scope(""):
使用位置:写在类上
作用:指定Bean的作用范围。singleton表示单例bean,默认值。prototype表示多例bean。
  • singleton - 容器内同名称的 bean 只有一个实例(默认)(单例bean)
  • prototype - 每次使用该 bean 时会创建新的实例(多例bean)
  • request - 在 web 环境中,每个请求范围内会创建新的实例
  • session - 在 web 环境中,每个会话范围内会创建新的实例
  • application- 在 web 环境中,每个应用范围内会创建新的实例

4. Bean的生命周期

  • 标注了 @PostConstruct 的方法是初始化方法,会在bean被创建之后调用。
  • 标注了 @PreDestroy 的方法是销毁方法,singleton范围的bean的销毁方法会在容器关闭前被调用
  • 默认情况下singleton范围的bean是容器创建时就会创建,但是可以配置延迟初始化
    • 如果希望用到时才创建,可以使用 @Lazy 注解标注在类上来延迟创建

5. 第三bean管理

如果要管理的对象来自于第三方,这时是无法用@Component等注解来实现的,解决方案:使用**@Configuration注解定义配置类,在配置类中定义方法使用@Bean**注解将方法返回的对象保存到Spring容器中。

@Configuration
//该类是一个配置类,spring会创建配置类对象保存到Spring容器中,会序会被自动调用配置类中被@Bean注解标注方法
public class DataSourceConfig {
    @Bean
    //spring调用该方法,将该方法的返回值保存到spring容器中
    public DruidDataSource druidDataSource() {
        //1.手动创建DruidDataSource对象
        DruidDataSource dataSource = new DruidDataSource();
        //2.设置连接参数
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///db1?useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        //3.返回连接池对象,保存到spring容器中
        return dataSource;
    }
}

三、依赖注入(DI)

依赖注入:Dependency Injection,缩写为DI。就是指被 Spring管理的Bean对象之间的依赖关系。由Spring容器完成对象属性赋值

1. 给对象类型的属性赋值

@Autowired:按照类型自动注入,如果Spring容器中同类型的对象有多个,可能注入失败,需要使用@Qualifier注解指定要注入的Bean的名称。

作用:给对象类型的属性赋值,可以用在成员变量、成员方法、构造方法上

  • 加在成员变量上,根据成员变量的类型到容器中找类型匹配的bean进行注入(赋值)
@Controller
public class UserController {
    @Autowired
    private UserService userService;
    
    public void foo() {
        System.out.println("UserController.foo().......");
        userService.foo();
    }
}
  • 加在普通方法上,根据方法的参数类型到容器中找类型匹配的bean进行注入(赋值)
	@Autowired
    public void foo() {
        System.out.println("UserController.foo().......");
        userService.foo();
    }
  • 加在构造方法上,根据构造方法的参数类型到容器中类型匹配的bean进行注入(赋值)
//要求:有参构造方法唯一。如果有空参构造,则Spring默认使用空参构造创建对象
public UserController(@Autowired UserService userService) {
    this.userService = userService;	
}

@Qualifier:结合@Autowired注解一起使用,指定要注入的Bean的名称。

  • UserServiceImplA
@Service("userServiceImplA")  //给UserServiceImplA取个名称
public class UserServiceImplA implements UserService {
    @Override
    public void foo() {
        System.out.println("UserServiceImpl.foo()-AAA执行了...");
    }
}
  • UserServiceImplB
@Service("userServiceImplB")  //给UserServiceImplB取个名称
public class UserServiceImplB implements UserService {BB
    @Override
    public void foo() {
        System.out.println("UserServiceImpl.foo()-BBB执行了...");
    }
}
  • UserController
@Controller
public class UserController {
    @Autowired
    @Qualifier("userServiceImplA")//根据名称指定要注入的Bean
    private UserService userService;
}

2. 给普通类型的属性赋值

@Value:常写在成员变量上,给成员变量注入普通类型的数据

  • 作用:给普通类型(基本类型、包装类类型、Sring类型)的属性赋值。

  • 应用场景:变化的配置信息写死在java代码中不好,建议放入配置文件,Spring Boot采用application.properties 作为配置文件,可以使用 @Value注解结合EL表达式根据key读取配置文件中对应的value值。

@Configuration
//该类是一个配置类,spring会创建配置类对象保存到Spring容器中,会序会被自动调用配置类中被@Bean注解标注方法
public class DataSourceConfig {
    @Value("${druid.driverClassName}")
    private String driverClassName;
    @Value("${druid.username}")
    private String username;
    @Value("${druid.url}")
    private String url;
    @Value("${druid.password}")
    private String password;
}

application.properties

# 配置Druid连接池的连接参数
druid.driverClassName=com.mysql.jdbc.Driver
druid.url=jdbc:mysql:///db1?useSSL=false
druid.username=root
druid.password=root

@ConfigurationProperties:写在类上,给Bean的属性批量注入普通类型数据。

  • 应用场景:常用来读取配置文件中的信息
@ConfigurationProperties(prefix = "druid")
//作用:给普通类型的属性按照指定前缀
@Configuration
//该类是一个配置类,spring会创建配置类对象保存到Spring容器中,会序会被自动调用配置类中被@Bean注解标注方法
public class DataSourceConfig {
    private String driverClassName;
    private String username;
    private String url;
    private String password;
}

四、整合Junit单元测试

  1. 其实我们创建的SpringBoot工程已经整合了Junit单元测试,并且使用的是Junit5的版本,好处是测试方法不需要使用public修饰。
		<dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
  1. 测试类上的@SpringBootTest注解表示该类是一个SpringBoot单元测试类,在该测试类中可以直接使用@Autowired注解注入要使用对象。
import org.junit.jupiter.api.Test;//junit5的导包
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest//表示该类是一个SpringBootTest单元测试类
class Spring01ApplicationTests {
    @Autowired//从容器中获取同类的bean对象赋值给成员变量
    private UserController userController;
    
    @Test
    void contextLoads() {
        userController.foo();
    }
}
  1. 注意:单元测试类所在包要在引导类所在包及其子包下,否则需要指定引导类:
//@SpringBootTest(classes = Spring01Application.class)//springboot测试程序入口

五、lombok工具包

作用:使用了lombok工具包,就不需要手动 Alt Insert 生成构造方法、getter和setter方法、toString等方法

  • 导入依赖
	 
        
            org.projectlombok
            lombok
        

1. JavaBean相关注解

  • @NoArgsConstructor:生成空参构造
  • @AllArgsConstructor:生成全参构造
  • @Getter:生成getter方法
  • @Setter:生成setter方法
  • @EqualsAndHashCode:生成hashCode和equals方法
  • @ToString:生成toString方法
  • @Data:生成以上所有方法(除了全参构造方法)
@Data//生成getter构造、setter构造、hashCode和equals方法、toString方法、空参构造
@AllArgsConstructor     //生成全参构造
@NoArgsConstructor      //生成空参构造
public class User {
    private String name;
    private Integer age;
    private Date birthday;
}

2. 日志输出注解

使用@Slf4j注解,然后使用log对象进行日志输出,代替System.out.println()输出。

  • @Slf4:类中会生成一个log对象,用于输出日志
@Slf4j
class Spring01ApplicationTests {
	 @Test
    void contextLoads() {
        userController.foo();
        log.info("userController = {}", userController);
    }

六、Spring循环依赖

现象:A对象内部注入了B对象,B对象内部注入了A对象,此现象就成为循环依赖。

1. set方式循环依赖

  • bean 从创建到初始化三个阶段,此顺序不能颠倒,并且只发生一次!

  • set方式循环依赖现象:
    Spring&SpringBoot_第1张图片

  • Springboot2.6.0之前,set循环依赖无需任何配置,Spring 会自动调整执行顺序

  • 解决:springboot2.6.0及以后版本需要在application.properties开启运行set方法循环依赖:

    # 允许set方式循环依赖
    spring.main.allow-circular-references=true
    

2. 构造方式循环依赖

  • 构造方法循环依赖
    Spring&SpringBoot_第2张图片
    Spring&SpringBoot_第3张图片

  • 异常信息:The dependencies of some of the beans in the application context form a cycle.

    翻译过来也就是:应用程序上下文中一些bean的依赖关系形成了一个循环。
    Spring&SpringBoot_第4张图片

  • 只要能打破循环依赖的局面,让一个对象先初始化完就行了

Spring&SpringBoot_第5张图片

  • 解决:需要在启动一个Bean构造方法中使用@Lazy注解,表示创建依赖对象的代理对象而不是真实对象进行注入。
@Component
public class C {
    private D d;
    public C(@Lazy D d) {//此处@Lazy表示创建D的代理对象而不是真实对象
        this.d = d;
        System.out.println("C对象创建了,d的class对象为"+d.getClass());
    }
}
@Component
public class D {
    private C c;
    public D(C c) {
        this.c = c;
        System.out.println("D对象创建了,c的class对象为"+c.getClass());
    }
}

小结

注解名称 位置 注解作用 备注
@SpringBootApplication 引导类 标识 SpringBoot 程序入口 每个项目(module)只能有一个引导类
@SpringBootTest 测试类 标注测试入口 与引导类要同包
@Component 标注该注解的类由Spring管理 必须处于扫描范围内
@Controller 同上,特定用于控制器类
@Service 同上,特定用于业务逻辑类
@Repository 同上,特定用于数据访问类
@ComponentScan 控制扫描范围 隐含在 @SpringBootApplication 中
@Scope 控制 scope 取值常见的有 singleton 与 prototype
@PostConstruct 成员方法 表示该方法为初始化方法 方法需无参,无返回值
@PreDestroy 成员方法 表示该方法未销毁方法 方法需无参,无返回值
@Lazy 表示该类延迟创建 用到时才会创建和初始化
@Bean 成员方法 方法的返回结果由Spring管理 方法参数带按类型装配功能
@Autowried 成员方法 方法参数根据类型装配
@Autowried 构造方法 方法参数根据类型装配 如果只有一个有参构造可以省略
@Autowried 成员变量 成员变量根据类型装配
@Value 成员变量 成员变量根据 ${key} 找 value 键值信息存于 application 配置文件中
@Value 参数 方法参数根据 ${key} 找 value 键值信息存于 application 配置文件中
@ConfigurationProperties 类的成员与 key 绑定 键值信息存于 application 配置文件中
@Data 生成空参构造/getter/setter/toString等方法
@Slf4j 生成log对象,log.info(“”)进行日志输出

@Controller、@Service、@Component、@Configuration、@Bean、@Autowired、@Value、@ConfigurationProperties写在哪?作用是什么?

  • @Controller
    • 写controller类上,把controller层交给Spring管理。
  • @Service
    • 写Service类上,把service层交给Spring管理
  • @Component
    • 写类上,将普通类交给Spring管理,这个类非三层架构中的类

作用:告诉Spring创建Bean对象


  • @Configuration
    • 表示该类是一个配置类,由SpringBoot自动扫描加载
  • @Bean
    • 默认将该方法的返回值保存到spring容器中(首字母小写)

作用:管理第三方Bean


  • @Autowired
    • 给对象类型的属性赋值,按照类型自动注入,如果Spring容器中同类型的对象有多个,可能注入失败,需要加上@Qualifier注解指定要注入的Bean的名称

作用:从容器中获取同类的bean对象赋值给成员变量


  • @Value

    • 给普通类型的属性赋值,常写在成员变量上,给成员变量注入普通类型的数据
  • @ConfigurationProperties

    • 给普通类型的属性赋值,写在类上,给Bean的属性批量注入普通类型数据

上,把service层交给Spring管理

  • @Component
    • 写类上,将普通类交给Spring管理,这个类非三层架构中的类

作用:告诉Spring创建Bean对象


  • @Configuration
    • 表示该类是一个配置类,由SpringBoot自动扫描加载
  • @Bean
    • 默认将该方法的返回值保存到spring容器中(首字母小写)

作用:管理第三方Bean


  • @Autowired
    • 给对象类型的属性赋值,按照类型自动注入,如果Spring容器中同类型的对象有多个,可能注入失败,需要加上@Qualifier注解指定要注入的Bean的名称

作用:从容器中获取同类的bean对象赋值给成员变量


  • @Value

    • 给普通类型的属性赋值,常写在成员变量上,给成员变量注入普通类型的数据
  • @ConfigurationProperties

    • 给普通类型的属性赋值,写在类上,给Bean的属性批量注入普通类型数据

作用:用来读取配置文件中的信息

你可能感兴趣的:(spring框架,spring,spring,boot,java)