SpringBoot基础入门(尚硅谷)

SpringBoot笔记尚硅谷

1.注解

1.1Configuration

在spring中,往往在spring的xml文件中实现注入,这样子很麻烦。在SpringBoot中我们可以通过一个创建一个类(MyConfig名字自定义),给这个类加上Configuration注解声明这是一个配置类,可以在这个类中实现组件注入。
首先准备两个实体类:

package com.zhouqun.pojo;

/**
 * @author 周区区
 * @version 1.0
 * @date 2021/7/14 10:18
 */
public class Pet {
    private String petname;
    private Integer petage;

    public String getPetname() {
        return petname;
    }

    public void setPetname(String petname) {
        this.petname = petname;
    }

    public Integer getPetage() {
        return petage;
    }

    public void setPetage(Integer petage) {
        this.petage = petage;
    }
}

package com.zhouqun.pojo;

/**
 * @author 周区区
 * @version 1.0
 * @date 2021/7/14 10:17
 */
public class User {
    private String username;
    private Integer userid;

    public User(){

    }

    public User(String username, Integer userid) {
        this.username = username;
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }
}

然后通过@Configuration自定义一个配置类,通过@Bean实现组件注入,也可以通过@Bean(“别名”)来给组件自定义名称:

package com.zhouqun.config;
import com.zhouqun.pojo.Pet;
import com.zhouqun.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @author 周区区
 * @version 1.0  自定义配置类
 * @date 2021/7/14 10:19
 */
//告诉SpringBoot这是一个配置类==配置文件
@Configuration
public class MyConfig {
    /**
     * @Bean实现组件注入==<bean/>
     * 往容器中添加组件,方法名就是组件id
     * 返回值就是组件在容器中的实例
     * @return
     */
    @Bean
    public User user(){
        User user = new User("张三", 101);
        return user;
    }
    @Bean("tom")
    public Pet tomCat(){
        Pet tomcat = new Pet("tomcat", 2);
        return tomcat;
    }
}

然后在主方法中测试组件是否注入成功:

@SpringBootApplication
public class Springboot01Application {
	public static void main(String[] args) {
		//返回IOC容器
		ConfigurableApplicationContext run = SpringApplication.run(Springboot01Application.class, args);
		//从容器中获取组件
		User user = run.getBean("user", User.class);
		Pet tom1 = run.getBean("tom", Pet.class);
		Pet tom2 = run.getBean("tom", Pet.class);
		System.out.println("tom1与tom2是否是同一个实例"+(tom1==tom2));//true
	}
}

小结:

  1. 配置类也是一个组件。
  2. 配置类里面使用@Bean标签标注在方法上给容器注册组件,默认使单实例的。

1.2proxyBeanMethods

在@Configuration中,在Spring5.2之后多了个属性:proxyBeanMethods。
这个属性默认是true,这个属性的意思是:是不是代理Bean方法。

boolean proxyBeanMethods() default true;

所以@Configuration的默认写法是:

@Configuration(proxyBeanMethods=true)

Full:全配置。当proxyBeanMethods值为true时,MyConfig这个配置类就是被cglib增强的代理对象。SpringBoot总会检查容器中是否存在这个组件(user,tom调用哪个检查哪个),保持组件单实例。
Lite:轻量级配置。当proxyBeanMethods值为false时,SpringBoot不会检查,会直接创建新的实例。
这个属性的作用时为了解决组件依赖问题。
假如User中多了个Pet属性:

public class User {
    private String username;
    private Integer userid;
    private Pet pet;
}

修改MyConfig的方法:

@Configuration(proxyBeanMethods = true)
//告诉SpringBoot这是一个配置类==配置文件
 public class MyConfig {
    @Bean
    public User user(){
        User user = new User("张三", 101);
        //user组件依赖于pet组件
        // 当proxyBeanMethods=true时,这种依赖是成立的
        //当proxyBeanMethods=false时,这种依赖不成立
        user.setPet(tomCat());
        return user;
    }
    @Bean("tom")
    public Pet tomCat(){
        Pet tomcat = new Pet("tomcat", 2);
        return tomcat;
    }
}

当proxyBeanMethods=true时,User的Pet和容器中的Pet是同一个,但是当proxyBeanMethods=false时,那么User的Pet和容器中的Pet不是同一个。
小结:

  1. 当proxyBeanMethods=true时,user和pet的依赖关系成立
  2. 当proxyBeanMethods=false时,user和pet的依赖关系不成立

1.3Import

给容器导入组件,可以写在任何一个配置类或者组件里面。(@Import要写在@Configuration…@Service等注解之上),通过查看Import源码可知,这是一个数组:

public @interface Import {
    Class<?>[] value();
}

所以Import的写法是:大括号数组格式

//在容器中自动创建出这两个类型的组件
@Import({User.class, DBHelper.class})

然后在启动类中测试:

//获取所有User类型的组件
		String[] beanNamesForType = run.getBeanNamesForType(User.class);
		for (String s : beanNamesForType) {
			System.out.println(s);
		}

测试结果:

=========
com.zhouqun.pojo.User//@Import导入
user//@Bean导入

可以看到通过@Import和@Bean注入的User组件都存在。
@Import导入的组件名字为全限定类名

1.4Conditional

条件装配:满足Conditional指定的条件,则进行组件注入。
Conditional的派生注解如下:
在这里插入图片描述
首先把tom组件注释掉,此时容器里面不存在tom组件了,然后给user组件加个条件:当容器中存在tom组件时,才会注入user组件:

@Configuration(proxyBeanMethods = false)
//告诉SpringBoot这是一个配置类==配置文件
 public class MyConfig {
    @ConditionalOnBean(name="tom")
    @Bean
    public User user(){
        User user = new User("张三", 101);
        user.setPet(tomCat());
        return user;
    }
//    @Bean("tom")
    public Pet tomCat(){
        Pet tomcat = new Pet("tomcat", 2);
        return tomcat;
    }

去启动类中测试一下:

//当tom组件存在时才会注入user
		boolean tom = run.containsBean("tom");
		System.out.println("容器中的tom组件是否存在"+tom);
		boolean user1 = run.containsBean("user");
		System.out.println("容器中的user组件是否存在"+user1);

测试结果:

=========
容器中的tom组件是否存在false
容器中的user组件是否存在false

可见,tom组件不存在时,user不会注入,然后去修改一下条件,当tom组件不存在时,user注入:

@ConditionalOnMissingBean(name="tom")
    @Bean
    public User user(){
        User user = new User("张三", 101);
        user.setPet(tomCat());
        return user;
    }

测试结果:

=========
容器中的tom组件是否存在false
容器中的user组件是否存在true

啊,真好用啊!
@ConditionalOnBean(name=“tom”)还可以标注在类上:

@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(name="tom")
 public class MyConfig {
    @Bean
    public User user(){
        User user = new User("张三", 101);
        user.setPet(tomCat());
        return user;
    }
    @Bean("tom")
    public Pet tomCat(){
        Pet tomcat = new Pet("tomcat", 2);
        return tomcat;
    }
}

只有在tom组件存在时,MyConfig类中的方法才会生效。
测试结果:

=========
容器中的tom组件是否存在false
容器中的user组件是否存在false

可见,程序启动时会先在容器中扫描tom组件,因为tom不存在,所以即使在MyConfig中标注了 @Bean(“tom”) MyConfig中的方法也不会执行。

1.5ImportResource

有可能项目中依旧存在spring的配置文件来实现注入,例如下面这个配置文件,注入user和pet:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user01" class="com.zhouqun.pojo.User">
        <property name="username" value="张三"/>
        <property name="userid" value="12"/>
        <property name="pet" ref="pet01"/>
    </bean>
    <bean id="pet01" class="com.zhouqun.pojo.Pet">
        <property name="petname" value="哈士奇"/>
        <property name="petage" value="3"/>
    </bean>
</beans>

当配置文件的内容非常庞大时,想要把标签挨个转换成@Bean注解的方式,这是非常麻烦的。也有可能引入的第三方包,也是使用配置文件方式来注入组件。这时可以通过@ImportResource注解来引入配置文件,并重新解析配置文件。

@Configuration(proxyBeanMethods = false)
@ImportResource("classpath:spring.xml")
 public class MyConfig {
    @Bean
    public User user(){
        User user = new User("张三", 101);
        user.setPet(tomCat());
        return user;
    }
    @Bean("tom")
    public Pet tomCat(){
        Pet tomcat = new Pet("tomcat", 2);
        return tomcat;
    }
}

去启动类测试容器中是否存在user、tom、user01、pet01:

=========
容器中的tom组件是否存在true
容器中的user组件是否存在true
容器中的user01组件是否存在true
容器中的pet01组件是否存在true

妙蛙妙蛙!

1.6配置绑定

我们习惯将经常变化的东西放在配置文件中,最常见的就是数据库连接,端口号,ip等,在需要使用的进行解析。

  1. @Component+@ConfigurationProperties(prefix = “配置文件中的对象名”) (写在实体类Car上)
  2. @EnableConfigurationProperties(写在配置类MuConfig上)开启Car配置绑定功能;将Car自动注入到容器

首先新建一个Car类:

public class Car {
    private String brand;
    private Integer price;
    }

然后将属性brand和price的值写到SpringBoot的配置文件中:application.properties:

mycar.brand=BYD
mycar.price=10000

@Component+@ConfigurationProperties(prefix = “配置文件中的对象名”)
给Car添加两个注解解析配置文件:

@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
    private String brand;
    private Integer price;
}

注意:一定要加@Component,因为只有将car作为组件注入,才能使用SpringBoot的强大功能。
去测试类中测试一下是否能拿到配置文件中的值:

@SpringBootTest
class Springboot01ApplicationTests {
	@Autowired
	Car car;
	@Test
	void contextLoads() {
		System.out.println(car);
	}
}

测试结果:

Car{brand='BYD', price=10000}

@EnableConfigurationProperties

@ConfigurationProperties(prefix = "mycar")
public class Car {
    private String brand;
    private Integer price;
    }
@Configuration(proxyBeanMethods = false)
@ImportResource("classpath:spring.xml")
@EnableConfigurationProperties(Car.class)
 public class MyConfig {
    //注入user、pet....
    }

测试结果:

Car{brand='BYD', price=10000}

注意:Car上面的@ConfigurationProperties(prefix = “mycar”)不能去掉,否则绑定不了配置文件。这两种方法读取的都是SpringBoot项目中的application.yml或application.properties核心配置文件,不能随便绑定一个文件。

2.自动配置原理入门

SpringBoot的启动类上有一个注解:

@SpringBootApplication

查看这个注解的源码可以发现这是由其他三个核心注解组合而来的:

在这里插入图片描述

2.1引导加载自动配置类

1.@SpringBootConfiguration
点进这个注解看源码可以发现这个类实际上是一个@Cionfiguration,这是一个配置类。
在这里插入图片描述
2.@ComponentScan
包扫描注解,指定扫描哪些包,不过多研究
3.@EnableAutoConfiguration(核心)
主要是最后两个注解:
在这里插入图片描述
1)首先我们进入到@AutoConfigurationPackages,可以发现它实际上是通过@Import导入了一个Registrar组件:
在这里插入图片描述
去查看Registrar是个什么东西:
在这里插入图片描述
通过Registrar给容器批量注入组件,注入哪些组件?
先打个断点然后debug启动:
在这里插入图片描述
首先看断点方法的两个参数:metadata:这个是注解(@AutoConfigurationPackages)的源信息,代表这个注解标在哪。通过deBug可知这个注解作用在启动类上:
在这里插入图片描述
于是,打断点的这行代码可以理解为:利用注解(@AutoConfigurationPackages)源信息,获取到一个包名,然后把获取到的信息存进数组。
获取到什么包名呢?可以利用Evaluate查看一下(debug体条件下才能用):首先选中"new PackageImports(metadata).getPackageNames()" 然后快捷键“alt+f8”,可以看到获取到的包名为“com.zhouqun”。所以就是将这个包及其子包下的组件导入进来。
注意: 这就是为什么新建的包要在启动类所在包下面,因为出了启动类所在包的范围,就扫描不到了!!
在这里插入图片描述
在这里插入图片描述
2)接下来查看@Import(AutoConfigurationImportSelector.class)注解,利用Selector机制批量导入组件,导入什么组件呢,去AutoConfigurationImportSelector中看一看:
在这里插入图片描述
这个类中有一个方法叫selectImports(),所有的组件都是靠getAutoConfigrationEntry()方法拿到所有的配置,然后转成String数组返回。
我们进入getAutoConfigrationEntry()看拿到哪些组件,首先打个断点:
在这里插入图片描述
往下走两行看到一个方法getCandidateConfigrations(),拿到所有候选配置:configurations。往下可以看到对configurations进行了一系列筛选操作后封装返回。而这个configurations的长度为131,表示有131个组件都是要返回加载的:
在这里插入图片描述
它怎么知道是这些类呢?规则是什么?我们进入getCandidateConfigrations()方法看一看:
在这里插入图片描述
可以看到是利用Spring的工厂加载器来加载一些东西,进入loadFactorNames()继续看:
在这里插入图片描述

继续进入loadSpringFactories():
在这里插入图片描述
到头了,加载META-INF/spring.factories。所有启动要加载的配置类都在这个文件里面写死了。
这个文件的位置:
在这里插入图片描述
虽然写死了,springboot一启动就要加载所有配置类,但并不是所有的配置都生效。这就涉及到按需开启。

2.2自动按需加载

什么是自动按需加载,我们随便点进一个包:
在这里插入图片描述
这个类在spring.factories中,启动就加载,但是可以看到Advice.class是红的,因为这个类在容器中并不存在,所以条件不成立,所以这个注解下的这个类虽然加载但并没有生效。我们可以看上面导的包:
在这里插入图片描述
因为Advice所在的包没有导入,所以Advice不存在,这个类不生效。
雷神:自动装配流程
雷神的这集自动装配流程值得反复观看。

3.最佳实践

在以后的开发中,只需要遵循以下步骤。

  1. 引入场景依赖:springboot的starter启动器
  2. 查看自动配置了什么(底层原理,不需要过于关心)
    在application.properties或者application.yml文件中,加入:
debug=true

然后启动项目,控制台会打印出哪些配置类生效,哪些没生效。
在这里插入图片描述

  1. 是否需要修改:参照文档修改配置项
  2. 自定义加入或替换组件:@Bean、@Component
  3. 自定义器:xxxxCustomizer

4.开发小技巧

4.1Lombok

可以简化javabean的开发。SpringBoot已经管理了Lombok的版本,我们只需要在pom.xml文件中引入依赖(也可以创建项目时勾选Lombok):

<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
</dependency>

然后安装Lombok插件:
在这里插入图片描述
然后在实体类上添加lombok的注解:

    @Data  //生成无参构造器、get、set、equals、hashCode、toString方法
    @AllArgsConstructor  //生成有参构造
    @NoArgsConstructor  //生成无参构造
    @ToString  //生成toString

lombok还有个日志注解:

@Slf4j
//使用方法
log.info("这是Slf4j");

缺点:一个人用,整个团队都得用

4.2dev-tools

热更新:Springboot-develop-tools
导入官方依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

然后需要更新的时候就按【ctrl+f9】也就是Build Project(其实就是重启restart),Spring官方说如果想用纯正的热更新就去用【 JRebel 】,要付钱= =

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值