当前位置: 首页 > article >正文

SpringBoot 基础(Spring)

SpringBoot 基础(Spring)

Bean 注解标记和扫描 (IoC)


配置类概念

  • @SpringBootConfiguration 或者 @Configuration 注解标注的类就是配置类
  • 配置类本身也会加入 IoC 容器*
@Configuration
public class configuration1 {

}

@SpringBootConfiguration
public class configuration1 {

}

标记 Bean

Spring 提供多种注解用于定义 Bean:

  • @Component:通用注解,标记类为 Spring Bean,可用于各层,如 Service、Dao 等,直接标注在类上即可。
  • @Repository:专用于 Dao 层类,
  • @Service:用于 Service 层类,
  • @Controller:用于 Controller
    .

注意: 源码显示,@Controller、@Service、@Repository 基于 @Component 起名,对 Spring IOC 管理无实质区别,仅为方便开发者区分组件作用。虽本质相同,但为保证代码可读性与结构严谨性,不可随意标注。

@Component
public class CommonComponent {}

@Controller
public class XxxController {}

@Repository
public class XxxDao {}

@Service
public class XxxService {}

扫描 Bean

SpringBoot 主程序的 @SpringBootApplication 会自动扫描 Bean

SpringBootAplication 整合了以下注解

  • @SpringBootConfiguration —— 表示这个类本身是个配置类
  • @EnableAutoConfiguration —— 自动加载其他的配置类
  • @ComponentScan 默认是扫描当前类所在的包和子包
    • 自定义一个 @ComponentScan(basePackages = "包1", "包2")
    • 或者 @SpringBootApplication(scanBasePackages = "包1", "包2")
//@SpringBootConfiguration //表示这个类本身是个配置类
//@EnableAutoConfiguration //自动加载其他的配置类
//@ComponentScan //默认是扫描当前类所在的包和子包
@SpringBootApplication
public class Boot302DemoApplication {

    public static void main(String[] args) {

        var ioc = SpringApplication.run(Boot302DemoApplication.class, args);
        
    }

}

第三方组件加入 IoC 容器

第一种方法:@Bean

第三方 jar 我们不可能直接在源码加 @Component 所以需要用 @Bean 标签

  • @Bean:方法返回值作为 Bean 类型:在使用 @Bean注解 的方法中,方法的返回值类型决定了 Bean 的类型。
  • 例如,如果方法返回一个DataSource 类型的对象,那么这个 BeanSpring 容器中的类型就是 DataSource。这个类型可以是 具体的类,也可以是 接口 或者 抽象类

.
注意:@Bean 只能在配置类里面写。当然不仅是第三方 jar 普通的也行

@Configuration
public class AppConfig {
	
    //
    @Bean
    public FastsalException fastsalException() {
		return new FastsqlException();
    }
}
第二种方式:@Import

快速把类放入 IoC 容器 (第三方或者自己的类都可以)。常用于整合配置类等操作。

  • 配置类放进 IoC 容器相比与配置类配置的所有组件都会放进 IoC 容器

  • 也只能在配置类中使用

@Configuration
@Import(FastsalException.class) //快速把第三方地 FastsalException类放入 IoC 容器
public class AppConfig {
	
}

BeanBeanName 问题

@ComponentBeanName

  • 默认情况:和首字母小写的类名相同。 例如:SoldierController 类对应的 bean 的 id 就是 soldierController
  • 自己指定:@Controller( value = "BeanName")

@BeanBeanName

  • 默认情况:和方法名相同
  • 自己指定:@Bean("BeanName")

Bean 的初始化和销毁方法

我们可以在组件类中定义方法,然后当 IoC 容器 实例化和销毁组件 对象的时候进行自动调用!这两个方法我们称为为生命周期方法!
.
类似于Servlet的 init/destroy 方法, 我们可以在周期方法完成初始化和释放资源等工作。

第一种:直接声明

//只要有 Bean 初始化和销毁了就执行这里的两个方法
public class BeanOne {

  //周期方法要求: 方法命名随意,但是要求方法必须是 public void 无形参列表
  @PostConstruct  //注解制指定初始化方法
  public void init() {
    // 初始化逻辑
  }
   
  @PreDestroy //注解指定销毁方法
  public void cleanup() {
    // 释放资源逻辑
  }
    
}

第二种:通过 @Bean 指定

public class BeanOne {

  public void init() {
    // initialization logic
  }
}

public class BeanTwo {

  public void cleanup() {
    // destruction logic
  }
}

@Configuration
public class AppConfig {

  @Bean(initMethod = "init")
  public BeanOne beanOne() {
    return new BeanOne();
  }

  @Bean(destroyMethod = "cleanup")
  public BeanTwo beanTwo() {
    return new BeanTwo();
  }
}

Bean 的单例和多例问题

取值含义创建对象的时机默认值
singleton在 IOC 容器中,这个 bean 的对象始终为单实例IOC 容器初始化时
prototype这个 bean 在 IOC 容器中有多个实例获取 bean 时

第一种方式:全名声明

//ConfigurableBeanFactory.SCOPE_PROTOTYPE 就是多例
//单例模式就是只要实例化一个 bean 就执行一次
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 单例
@Component
public class JavaBean {


}

第二种方式:简洁声明

@Scope("prototype") // 单例
@Component
public class JavaBean {


}

两者区别

  • @Scope("prototype")
    • 对于初学者或简单项目,使用字符串的方式可能更容易理解和书写,但是在大型项目中,如果作用域名称拼写错误(例如写成 “prototyp”),编译器不会给出错误提示,可能导致运行时问题。
  • @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    • 使用 ConfigurableBeanFactory.SCOPE_PROTOTYPE 常量可以避免拼写错误,因为 IDE 会在编译时检查该常量是否存在,同时也更符合 Java 编程的最佳实践,即使用常量而不是硬编码字符串。

Bean 依赖注入:引用类型自动装配(DI)


前提条件:参与自动装配的组件,无论是要被装配的还是提供装配的,都必须在 IoC 容器里,并且 IoC 容器的实现方式(XML 配置或者注解方式)对此没有影响。

@Autowired:按照类型装配

  • @Autowired 注解使用方法:可以直接在成员变量上标记 @Autowired 注解 来自动注入对象,在实际项目中我们通常采用这种方式。甚至第三方类放入容器后,也能使用此注解来实现自动装配。

  • 原理

    • 在 ioc 容器中查找符合类型的组件对象
    • 设置给当前属性(di)
  • @Autowired 标记的位置:成员变量,get方法, 构造器

  • Bean
@Repository
public class UserDao {

}

@Service
public class UserService {
 
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }
}
  • @Autowired 注入
@Service
public class UserService {

    //这里相当于注入了 UserDao 类型的对象
    @Autowired
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }
}

@Autowired 装配流程
·
在这里插入图片描述

@Qualifier:指定 BeanName 装配

根据 @Qualifier 注解中指定的名称作为 BeanName 进行匹配。需要配合 @Autowired

@Repository
public class UserDao {
    
    private UserDao userDao;

	//匹配 BeanName 为 userDao 进行装配
	//value 可以省略
	@Autowired
    @Qualifier(value = "userDao")
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

@Resource:多功能装配

  • 如果没有指定 name, 先根据 属性名 查找 IoC 中组件
  • 如果没有指定 name, 并且属性名没有对应的组件, 会根据 属性类型 查找
  • 如果指定name名称查找。Resource(name='test') == @Autowired + @Qualifier(value='test')
Repository
public class UserDao {
    
    @Resource(name = "userDao")
    private UserDao userDao;

	
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

@Bean 声明组件之间的装配

第一种方式:直接调用方法

如果其他组件也是 @Bean 方法 也可以 直接的调用方法这个本质上从 IoC 容器获取组件

  • POJO
public class Money {

}

public class People {
    private Money money;

    public void setMoney(Money money) {
        this.money = money;
    }
}
  • 配置类
@SpringBootConfiguration
public class configuration1 {

    @Bean
    public Money money() {
        return new Money();
    }


    @Bean
    public People people() {
        People people = new People();
        //直接调用方法本质上从 ioc 容器获取组件
        people.setMoney(money());
        return people;
    }

}
第二种方式:形参列表自动注入

形参列表声明自动注入

  • 要求必须有对应的类型的组件, 如果没有抛异常
  • 如果有多个同类型的 Bean 。可以使用 形参名称 = 对应的 beanName 的方式
  • POJO
public class Money {

}

public class People {
    private Money money;

    public void setMoney(Money money) {
        this.money = money;
    }
}
  • 配置类
@SpringBootConfiguration
public class configuration1 {

    @Bean //默认方法名就是BeanName
    public Money money() {
        return new Money();
    }


    @Bean
    public People people(Money money) {
        People people = new People();
        people.setMoney(money);
        return people;
    }

}

Bean 依赖注入:基本类型装配(DI)


第一种方式:@Value 直接绑定

  • @Value 是 Spring 框架中的一个注解,其主要作用是将外部配置文件中的具体值注入到由 Spring 管理的组件的字段中。这里所说的 Spring 管理的组件,通常是指带有 @Component 注解的类。
  • 具体使用时,在字段上添加 @Value("${某个属性名}") 注解。当 Spring 应用启动时,它会自动从配置文件里查找与注解中指定属性名相对应的值,并将该值填充到使用 @Value 注解标注的字段中。
    .

使用

  • 情况1:${key} 取外部配置 key 对应的值!
  • 情况2:${key : defaultValue} 没有 key, 可以给与默认值
  • properties 配置文件
username=mangfu
gender=男
age=20
  • 开始注入
@Component
//导入 properties配置文件
@Data
public class MyComponent {
	//注入
    @Value("${username}")
    private String name;

    @Value("${age}")
    private String age;

    @Value("${gender}")
    private String gender;

}

第二种方式:@configurationProperteis 根据前缀绑定

@ConfigurationProperties

前提是要用 @Component 或者 @Bean 把类加入 IoC 容器。并且有 get set 方法

  • application.properties
pig.id=1
pig.name=佩奇
pig.age=5
  • @Component 方式
@Data
//必须加入 IoC 容器 @ConfigurationProperties(prefix = "pig") 才生效
@Component
//根据前缀为 pig 的自动匹配和 properties 一样的后缀然后赋值
@ConfigurationProperties(prefix = "pig")
public class Sheep {

    private Long id;
    private String name;
    private Integer age;

  
}
  • @Bean 方式
@Configuration
public class AppConfig2 {

    @ConfigurationProperties(prefix = "pig")
    @Bean
    public Pig pig() {
        return new Pig();
    }
}
@EnableConfigurationProperties

Spring Boot 默认只扫描主程序所在包,导入第三方包时,即便组件标有 @Component@ConfigurationProperties,也因扫描不到而无法完成属性绑定和注册到容器。
.

使用 @EnableConfigurationProperties(Sheep.class) 可快速对指定类(如 Sheep 类)进行属性绑定并注册到容器。
,
使用该注解需注意:

  • 先使用 @ConfigurationProperties(prefix = " ") 绑定指定类。
  • 在配置类中使用。
  • Application.properties
sheep.id=1
sheep.name=苏西
sheep.age=5
  • POJO
//可以不用 @Component 加入 IoC 容器。等下 @EnableConfigurationProperties 会把它加入 IoC并赋值 
@ConfigurationProperties(prefix = "sheep")
public class Sheep {

    private Long id;
    private String name;
    private Integer age;

 
}
  • 配置类
//这里就把 Sheep 加入 IoC 容器并且对应赋值了
@EnableConfigurationProperties(Sheep.class)
public class AppConfig2 {

}

@ConditionalOnXXX 条件判断注解


如果注解指定的条件成立,则触发指定行为

  • @ConditionalOnClass:如果类路径中存在这个类,则触发指定行为

  • @ConditionalOnMissingClass:如果类路径中不存在这个类,则触发指定行为

  • @ConditionalOnBean:如果容器中存在这个Bean(组件),则触发指定行为

  • @ConditionalOnMissingBean:如果容器中不存在这个Bean(组件),则触发指定行为

  • @ConditionalOnBean(value=组件类型,name=组件名字):判断容器中是否有这个类型的组件,并且名字是指定的值

.
如果是类级别就。类里所有操作都执行或不执行

举例

@SpringBootConfiguration
public class AppConfig {

//类路径中存在这个类就创建这个 Bean 			 
    @ConditionalOnClass(name="com.atguigu.boot.controller.HelloController.class")
    @Bean
    public Money money() {
        return new Money();
    }

//类路径中不存在这个类就创建这个 Bean 	
    @ConditionalOnMissingClass(value ="com.atguigu.boot.controller.HelloController.class")
    @Bean
    public People person() {
        return new People();
    }
}

SpringBoot 获取 Bean


之前我们用的是 AnnotationConfigApplicationContext。现在 主程序SpringApplication.run 返回的是 ConfigurableApplicationContextConfigurableApplicationContext接口类型
.

AnnotationConfigApplicationContextConfigurableApplicationContextConfigurableApplicationContext 的具体实现类。所以相当于直接创建好了 ApplicationContext 了我们直接获取 IoC 中的容器就行

第一种方式:根据 BeanName 获取

直接根据 beanName 获取即可 返回值类型是 Object 需要强转 【不推荐】

Object happyConponent = applicationContext.getBean("happyComponent");

第二种方式:根据 BeanName 同时定制 Class

HappyComponent happyComponent1 = applicationContext.getBean("happyComponent", HappyComponent.class);

第三种方式:直接根据类型获取

直接根据类型获取

  • 条件1:同一个类型, 在 Ioc 容器中只能有一个 Bean,如果 IoC 容器中存在多个同类型的 Bean 会出现: NoUniqueBeanFinitionException
  • 条件2IoC 的配置一定是实现类, 但是可以通过接口类型获取触发多态
    .

原理:根据类型来获取 Bean 时,在满足 Bean 唯一性的前提下,其实只是看:【对象 instanceof 指定的类型】的返回结果,只要返回的是 true 就可以认定为和类型匹配,能够获取到。

//A 是接口 HappyComponent 是实现类
A bean = applicationContext.getBean(A.class);
bean.doWork();

http://www.kler.cn/a/525791.html

相关文章:

  • 17、智能驾驶硬件架构安全设计一般原则
  • 算法每日双题精讲 —— 前缀和(【模板】一维前缀和,【模板】二维前缀和)
  • 動態住宅IP提升網站訪問成功率
  • Nginx前端后端共用一个域名如何配置
  • JAVA实战开源项目:蜗牛兼职平台(Vue+SpringBoot) 附源码
  • 跨域问题及解决方案
  • AI 计算的未来:Deepseek从中心化到去中心化的变革
  • c++:vector
  • 【Linux系统】进程间通信:认识命名管道
  • windows10 配置使用json server作为图片服务器
  • 笔记:使用ST-LINK烧录STM32程序怎么样最方便?
  • 设计模式Python版 适配器模式
  • Vue.js 响应式引用与响应式数据(`ref` 和 `reactive`)
  • 【Python】深入探索Python元类:动态生成类与对象的艺术
  • 深入解析JPA中的多对多关系映射
  • Java---猜数字游戏
  • wordpress每隔24小时 随机推荐一个指定分类下的置顶内容。
  • 【Elasticsearch 】自定义分词器
  • Pyside6(PyQT5)的QSqlQueryModel的常用方法
  • 【C语言】main函数解析
  • 上位机知识篇---GitGitHub
  • 在MIMIC IV数据库的derived中有bg、chemistry和vitalsign,它们都有Glucose指标,如何区分?
  • C++并发编程指南06
  • 基于springboot的校园部门资料管理系统
  • 搜索引擎快速收录:关键词布局的艺术
  • DeepSeek回答人不会干出超出视角之外的事