spring

# 仓库地址

https://gitee.com/chengheng2022/jsd2203-csmall-server.git



# Spring

## 创建项目

通过Spring创建向导来创建项目,创建参数:

- Server URL:https://start.spring.io 或 https://start.springboot.io
- Name:`jsd2203-csmall-server`(老师的后面带有`-teacher`)
- Group:`cn.tedu`
- Artifact:`csmall-server`(手动调整)
- Package Name:`cn.tedu.csmall.server`(手动调整)
- Java版本:`8`(`1.8`)

在后续的界面中,可以随意选择某个版本,并且,不勾选任何依赖项。

当项目创建成功后,打开`pom.xml`,在默认的第8行中,将版本号改为`2.5.9`。



## Spring框架的作用

主要解决了创建对象和管理对象的问题。

在使用Spring框架后,当需要某个对象时,直接通过Spring获取此对象即可。

Spring可以保证类的对象的唯一性,使得各组件出现依赖关系时,不会创建多个相同的对象。

由于Spring会创建很多个对象并管理起来,开发者需要时直接获取即可,所以,Spring也通常被称之为“Spring容器”。



## 通过Spring创建并管理对象--组件扫描

Spring提供了组件扫描的机制,它可以扫描指定的包,并查找此包及其子孙包下是否存在组件类,判定组件类的标准是类上是否存在组件注解,基础的组件注解有:

- `@Component`
- `@Controller`
- `@Service`
- `@Repository`

在Spring框架的解释中,以上4个注解是完全等效的,只是语义不同。

所以,当某个类需要被Spring框架创建对象时,需要:

1. 确保这个类在组件扫描的范围之内
2. 确保这个类添加了组件注解

提示:在Spring Boot项目中,默认就已经配置好了组件扫描,扫描的根包就是创建项目时已存在的包。



## 通过Spring创建并管理对象--@Bean方法

在Spring框架的使用中,如果某个类添加了`@Configuration`注解,则此类将是“配置类”。

注意:配置类也必须在组件扫描的范围内。

在配置类中,可以自行添加一些方法,在方法上添加`@Bean`注解,则此方法会被Spring自动调用,且方法返回的对象也会被Spring管理。

在同一个配置类中,允许存在多个`@Bean`方法。

关于方法的声明:

- 访问权限:应该是`public`
- 返回值类型:你希望Spring管理的对象的类型
- 方法体:应该正确的返回与声明匹配的对象
- 方法名称:自定义

所以,当某个类需要被Spring框架管理对象时,需要:

- 在配置类中添加`@Bean`方法,使用此方法返回需要被管理的对象



## 如何选择创建并管理对象的方式

仅自定义的类型可以使用组件扫描的方式,当然,自定义的类型也可以使用`@Bean`方法的做法,但是不推荐。

非自定义的类型不可以使用组件扫描的方式(因为你没有办法在这些类型上添加组件注解),只能使用`@Bean`方法的做法。



## 练习

在`controller`包中创建`BrandController`、`PictureController`、`AlbumController`,也都将由Spring来创建对象,并测试是否可以获取到对象



## 自动装配

当某个属性需要值时,或被Spring调用的方法需要参数值时,Spring框架会自动从容器中查找符合的对象,自动为属性或方法的参数赋值。

在属性上,添加`@Autowired`注解,即可使得Spring尝试自动装配。



## 练习

假设在项目中存在:

- `IBrandRepository`
- `BrandRepositoryImpl`
- `IBrandService`
- `BrandServiceImpl`
- `BrandController`

其依赖关系是:在`Service`组件中需要使用到`Repository`,在`Controller`组件中需要使用到`Service`。

要实现以上目标,需要:

- 以上各类和接口都应该在组件扫描的根包或其子孙包下

- `IBrandRepository`、`IBrandService`不需要添加注解,而`BrandRepositoryImpl`应该添加`@Repository`注解,`BrandServiceImpl`添加`@Service`注解,`BrandController`添加`@Controller`注解

- 在`BrandServiceImpl`中声明`BrandRepositoryImpl`类型的变量(暂时声明为`public`)

  - 【测试】在没有添加`@Autowired`之前,此变量的值为`null`

    - 可以在测试类中自动装配`BrandServiceImpl`,并在测试方法中输出`BrandRepositoryImpl`变量的值,例如:

    - ```java
      @Autowired
      BrandServiceImpl brandService;
      
      @Test
      public void testBrandAutowired() {
          System.out.println(brandService.brandRepositoryImpl);
      }
      ```

  - 【测试】当已经添加`@Autowired`之后,此变量的值为`BrandRepositoryImpl`类型的对象

- 使得`BrandRepositoryImpl`实现`IBrandRepository`接口

  - 【测试】将`BrandServiceImpl`中,原本声明为`BrandRepositoryImpl`类型的变量,改为`IBrandRepository`类型,再次观察,此变量的值不变

- 在`BrandController`中声明`BrandServiceImpl`类型的变量

  - 【测试】在没有添加`@Autowired`之前,此变量的值为`null`
  - 【测试】当已经添加`@Autowired`之后,此变量的值为`BrandServiceImpl`类型的对象

- 使得`BrandServiceImpl`实现`IBrandService`接口

  - 【测试】将`BrandController`中,原本声明为`BrandServiceImpl`类型的变量,改为`IBrandService`类型,再次观察,此变量的值不变



## 练习

假设在项目中存在:

- `IAlbumRepository`
- `AlbumRepositoryImpl`
- `IAlbumService`
- `AlbumServiceImpl`
- `AlbumController`

其依赖关系是:在`Service`组件中需要使用到`Repository`,在`Controller`组件中需要使用到`Service`。

案例目标:

- Spring能自动创建`AlbumRepositoryImpl`类的对象

  - 在`repo.impl`包下创建此类,并且,在此类上添加`@Repository`
  - 检验方式:添加构造方法并输出;在测试类中,自动装配此类型的对象,并输出

- Spring能自动创建`AlbumServiceImpl`类的对象

  - 同上,此类应该在`service.impl`包下(`impl`包不存在,需创建)

- 在`AlbumServiceImpl`类有`AlbumRepositoryImpl`的属性,并自动装配

  - 在`AlbumServiceImpl`内部,声明`AlbumRepositoryImpl`类型的变量,并添加`@Autowired`注解
  - 检查方式:在测试类中,输出`AlbumServiceImpl`对象的`AlbumRepositoryImpl`属性,应该是有值的

- 创建`IAlbumRepository`接口,使得`AlbumRepositoryImpl`实现`IAlbumRepository`接口,并且,在`AlbumServiceImpl`应该是基于接口编程的,所以,原本声明为`AlbumRepositoryImpl`的变量,改为`IAlbumRepository`接口类型的声明

- 实现在`Controller`组件中需要使用到`Service`,则需要先创建`AlbumController`类,并添加`@Controller`注解,然后,在`AlbumController`内部,声明`public AlbumServiceImpl albumService;`,并在此属性上添加`@Autowired`,则此属性将被Spring自动装配值,如果要调整为基于接口的编程,还需要创建`IAlbumService`接口,并使得`AlbumServiceImpl`实现此接口,最后,在`AlbumController`中,原本的声明`public AlbumServiceImpl albumService;`改为`public IAlbumService albumService;`即可

  - 检查方式:在测试类中自动装配`AlbumController`,在测试方法中输出`AlbumController`变量中的`albumService`属性的值,应该会输出有效值

  - ```java
    @Autowired
    AlbumController albumController;
    
    @Test
    public void testAlbumControllerAutowired() {
        System.out.println(albumController.albumService);
    }
    ```



## DAY01--当日小结

你应该:

- 使得自定义的类被Spring管理对象
  - 确保类在组件扫描的包下,且在类上添加组件注解
- 认识4个基础的组件注解
  - `@Component` / `@Controller` / `@Service` / `@Repository`
- 了解Spring的自动装配
  - 在属性上添加`@Autowired`,则Spring会自动尝试为此属性赋值,是否成功,取决于Spring容器中是否存在合适的对象
- 理解组件之间的调用关系
  - Controller >>> Service >>> Repository
- 理解基于接口的编程的思想



## 你可能需要知道的

### 组件扫描

在Spring框架中,通过`@ComponentScan`注解,即可配置组件扫描

在Spring Boot项目中,默认即存在的类(有`main()`方法的那个类)上添加了`@SpringBootApplication`注解,此注解的源代码中包含`@ComponentScan`。

在Spring Boot项目中,无论是执行默认即存在的类的`main()`方法,还是执行带`@SpringBootTest`注解的类中的测试方法,都会加载整个项目的配置,所以,组件扫描是已启动的。

> 在`@SpringBootApplication`的声明上有`@ComponentScan`,则`@SpringBootApplication`具有`@ComponentScan`的效果。
>
> 在`@SpringBootApplication`的声明上有`@ComponentScan`,则`@ComponentScan`可称之为`@SpringBootApplication`的**元注解**。

### 自动装配

当Spring尝试实现自动装配时,会从Spring容器中查找合适的对象,关于“合适”的判定标准,首先,类型必须匹配,如果匹配类别的Bean有多个,必须保证名称匹配才可以正确装配。

关于名称匹配:被自动装配的属性名称,与Bean的名称相同。

关于Bean的名称:如果类名的第1个字母是大写的,且第2个字母是小写的,则Bean的名称是将类名首字母改为小写,例如`BrandRepositoryImpl`的Bean名称就是`brandRepositoryImpl`,否则,Bean名称就是类名。



## 练习

使得Spring框架创建以下类型的对象(在以下各类的构造方法中添加输出语句):

- `cn.tedu.csmall.server.repo.impl.AttributeRepositoryImpl`
- `cn.tedu.csmall.server.repo.impl.AttributeTemplateRepositoryImpl`
- `cn.tedu.csmall.server.repo.impl.SkuRepositoryImpl`
- `cn.tedu.csmall.server.repo.impl.SpuRepositoryImpl`
- `cn.tedu.csmall.server.service.impl.AttributeServiceImpl`
- `cn.tedu.csmall.server.service.impl.AttributeTemplateServiceImpl`
- `cn.tedu.csmall.server.service.impl.SkuServiceImpl`
- `cn.tedu.csmall.server.service.impl.SpuServiceImpl`
- `cn.tedu.csmall.server.controller.AttributeController`
- `cn.tedu.csmall.server.controller.AttributeTemplateController`
- `cn.tedu.csmall.server.controller.SkuController`
- `cn.tedu.csmall.server.controller.SpuController`

并创建`repo`下对应的各接口:

- `cn.tedu.csmall.server.repo.IAttributeRepository`
- `cn.tedu.csmall.server.repo.IAttributeTemplateRepository`
- `cn.tedu.csmall.server.repo.ISkuRepository`
- `cn.tedu.csmall.server.repo.ISpuRepository`

实现各Service中通过接口声明Repository组件,并实现自动装配。

在`service`下创建对应的各接口:

- `cn.tedu.csmall.server.service.IAttributeService`
- `cn.tedu.csmall.server.service.IAttributeTemplateService`
- `cn.tedu.csmall.server.service.ISkuService`
- `cn.tedu.csmall.server.service.ISpuService`

实现各Controller中通过接口声明Service组件,并实现自动装配。







# 关于Spring框架的异常

## NoSuchBeanDefinitionException

**无此Bean的异常**

在异常信息中会提示到底是缺少哪个Bean,例如以下提示的`cn.tedu.csmall.server.controller.CategoryController`,然后,再结合你的配置来检查!

创建对象的方式只有2种,要么是组件扫描,要么是`@Bean`方法,检查对应的代码即可。

如果提示的类型并不是自已配置的,且应该是正常的可用的,可考虑为依赖项错误的问题,则参考《前置技术清单中第3条来解决》。

```
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.tedu.csmall.server.controller.CategoryController' available
```



## NoUniqueBeanDefinitionException

**不唯一的Bean的异常**

当尝试自动装配时,匹配类型的Bean超过1个

```
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.tedu.csmall.server.repo.IBrandRepository' available: expected single matching bean but found 2: brandRepositoryImpl,brandRepositoryImpl2
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值