首页 > 其他分享 >spring-1-IOC、创建bean的方式、创建bean的过程

spring-1-IOC、创建bean的方式、创建bean的过程

时间:2024-06-11 20:55:23浏览次数:11  
标签:spring Spring Bean class bean yang37 User 创建 public

1.背景

IOC(Inversion of Control,控制反转)

控制反转是一种设计原则,它将对象的创建和管理责任从应用代码中移交给容器。

在Spring中,IOC容器负责管理应用中的所有对象,包括它们的生命周期和相互之间的依赖关系。

IOC的主要目的是为了减少代码之间的耦合,使代码更加模块化和可测试。

这里的控制反转,控制的是谁,反转又是反转到哪里了?

  • 控制:对各种对象的控制
  • 反转:将控制权反转给Spring容器

嗯,就是将对象的管理交给Spring容器,不用你自己来 new Xx();

好,我们也先别管它是怎么创建对象的了,我们思考一个问题。

我们类中,是不是经常会存在。

public class Xx{
    private MyClass myclass;
}

现在问题就来了,既然Spring容器要帮我们创建这个Xx对象,那么其中依赖的其他对象,例如此处的MyClass怎么办?

这就又谈到了我们的依赖注入(Dependency Injection, DI)

依赖注入是指将对象的依赖(即它所需要的对象)在外部注入,而不是由对象自己创建或查找这些依赖。

你看,依赖注入只是帮助我们构建这个类,其根本目的还是为了实现咱们的控制反转。

好,在开始之前,我们先来大致了解几个点,留个印象。

  • IOC创建对象:通过反射完成
  • 依赖注入的几种方式
    • 构造器注入:通过构造函数来注入依赖对象。
    • Setter方法注入:通过Setter方法来注入依赖对象。
    • 接口注入:通过接口来注入依赖对象(在Spring中不常用)。

后续的内容,基于SpringBoot程序演示。

2.@SpringBootApplication注解

上面已经提到了,IOC容器是用来管理咱们的对象的,Bean就是Spring IoC容器管理的一个对象,称呼而已。

好,在此之前,我们先来了解下,SpringBoot默认加载哪些bean。

回到梦开始的地方。

image-20240610120615736

一切来自于咱们的这个@SpringBootApplication注解。

image-20240610115354154

前面4个,是咱们java自带的元注解。

image-20240610120049470

注解 作用
@Target({ElementType.TYPE}) 表明可以应用于类、接口或枚举类型
@Retention(RetentionPolicy.RUNTIME) 表明在运行时可用
@Documented 表明使用的元素应被 javadoc 或类似工具记录
@Inherited 表明可以被子类继承

后面3个,是咱们Spring的。

注解 作用
@SpringBootConfiguration 这是一个特殊的 @Configuration 注解,用于标记一个类作为 Spring 配置类。
它继承自 @Configuration,表明该类可以作为 Spring IoC 容器的配置类。
@EnableAutoConfiguration 这个注解启用 Spring Boot 的自动配置机制。
Spring Boot 会根据类路径中的依赖、定义的 Bean 和各种属性设置自动配置 Spring 应用程序的上下文。
它通过读取类路径中的 META-INF/spring.factories 文件,查找可以自动配置的类。
@ComponentScan 这个注解启用组件扫描,默认扫描 @SpringBootApplication 所在包及其子包中的所有组件(如带有 @Component、@Service、@Repository 和 @Controller`的类)。
excludeFilters属性用于排除特定类型的组件。例如:
- TypeExcludeFilter.class:一个自定义过滤器类型,用于排除特定类型的组件。
- AutoConfigurationExcludeFilter.class:用于排除自动配置类。

综上,使用了 @SpringBootApplication 注解:

  • ZaApplication类被标记为一个配置类,可用于定义 Bean。

  • Spring Boot 的自动配置机制被启用:Spring Boot 会根据类路径中的依赖自动配置应用程序上下文。

  • Spring Boot 会自动扫描cn.yang37.za包及其子包中的组件,并将它们注册为 Spring Bean。

3.查看SpringBoot中的Bean

3.1 Actuator

注意啊,这个东西权限很大,不懂的话,你别在生产环境乱用。

这玩意就是个Spring自带的监控工具,用起来很简单。

3.1.1 导入pom

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

3.1.2 声明配置

这里就是声明暴露的端点,包含一个beans。

server:
  port: 9595
# actuator相关
management:
  endpoints:
    web:
      exposure:
        include: beans

3.1.3 启动后访问

启动后访问web,可以看到相关信息。

http://localhost:9595/actuator/beans

image-20240610125156296

3.2 ApplicationContext

这个就比较简单了,直接注入了使用就行。

例如我注册一个bean,类型是MyConfig,名字是“6666”。

package cn.yang37.za.config;

import org.springframework.stereotype.Component;

@Component("6666")
public class MyConfig {

}

然后,在测试类中获取它。

package cn.yang37.za.controller;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;

@Slf4j
@SpringBootTest
class BeanControllerTest {

    @Resource
    private ApplicationContext applicationContext;

    @Test
    void name() {
        Object myConfig = applicationContext.getBean("6666");
        log.info("info : {}", myConfig);
    }
}

可以看到相关信息。

image-20240610125652769

image-20240610125942078

4.SpringBoot中创建bean的方式

4.1 @Componet + @ComponentScan

4.1.1 @Componet

Bean命名规则

  • 类名的首字母小写:Spring会将类名的首字母小写,其他部分保持不变,作为默认的Bean名称。比如此处的beanName是myConfig。

  • 保留原有大小写:如果类名的首字母和第二个字母都是大写(例如URLConverter),Spring会直接使用类名URLConverter作为Bean名称,而不会改变首字母的大小写。

最简单的方式,就是直接用上咱们的@Componet注解,标记这个类要放到容器中去。

@Component
// 也可以声明一个Bean名字@Component("MyConfig666")
public class MyConfig {

}

使用的时候,直接使用@Autowired或者@Resource获取即可。

@RestController
@RequestMapping("/bean")
public class BeanController {

    @Resource
    private MyConfig myConfig;


    @GetMapping("/info")
    public String info() {
        return myConfig.toString();
    }
}

image-20240610114020906

我们平时用到的@Controller等注解,都是它的子注解。

那我到底写@Component还是@Controller?要反过来说,@Controller这些注解都不合适的时候,再用@Component。

注解 作用 适用层次
@Component 标记为Spring管理的通用bean 通用组件
@Controller 标记为Spring MVC控制器,处理HTTP请求并返回视图 表现层(MVC控制器)
@Service 标记为服务层组件,表示业务逻辑 服务层
@Repository 标记为数据访问层组件,提供数据访问功能并处理数据库异常转换 数据访问层
@RestController 标记为RESTful Web服务控制器,默认返回JSON或XML格式的数据 表现层(REST控制器)
image-20240610114532047

4.1.2 @ComponentScan

该注解呢,用于扫描某个包,将所有声明了@Component注解的类,注入到Spring容器中。

哎,你肯定问,我都@Componet了?还scan个毛?@Componet不是已经可以加载进来了吗?

你忘啦,最开始说的,启动类上的@SpringBootApplication注解包含了@ComponentScan注解,但是它的默认扫描位置是:

  • 启动类(即@SpringBootApplication的类)所在的包
  • 子包

回到项目里,就是默认只扫描cn.yang37.za文件夹和其中的文件夹。

image-20240610120937492

我们在别的位置新建一个类,即便用上注解,它也是扫描不到的。

image-20240610121437434

image-20240610121425863

这个时候,咱们的@ComponentScan注解不就有用了吗?咱们直接在类中补上这个扫描的位置,它不就启动起来啦。

image-20240610121633954

啊,你别懵,十分正常,你只是平时写习惯了,不妨看下咱们类加载器的知识:Java-JVM-类加载器

idea启动的时候,自动把classpath路径给我们传了,这下面所有的类都能在JVM里面找到。

所以咱们JVM中是有这个Demo类的,在配置了@ComponentScan到这个cn.yang的包下后,就一切正常了。

image-20240610122038897

好,实际上不会这样搞对吧?咱们Java程序员向来喜欢搞各种xx包、xx类的概念,咱们根本就做不出来旁边新建个文件夹cn.yang的鬼操作对吧?

是滴,这里是在给你演示。

常见的方式是,某个组件没在你当前项目(比如此处的ZaApplication)代码里,比如某某jar包、比如跨模块,此时没加载到Spring容器中,不妨试试这个注解。

当然,正常情况下,这个jar包应该使用咱们2.5节spring.factories的方式。

反正,你发现没自动加载上,你就试试手动声明下扫描位置,不用这么纠结到底要在何时使用。

注意,@ComponentScan不要乱写在启动类上,用在启动类上会覆盖默认的扫描范围。

4.2 @Bean

Bean命名规则:默认情况下,其名字是方法名,也可以在注解中指明名字(注解的name属性)。

当然可以我们自己创建一个对象,把它放到我们的Spring容器中去。

哎,前面不是说,咱们把对象管理交给Spring去处理吗?什么玩意这么大的面子,还得我亲自创建?

先来段专业的话术。

@Bean 注解用于告诉 Spring 容器这个方法将返回一个需要注册为 Spring Bean 的对象,这样,我们可以自定义对象的创建逻辑,尤其是在对象创建需要复杂配置或依赖于其他组件时。

上例子,假设我们有个User对象,朴实无华。

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {

    private String name;

    private int age;
}

假设我创建它的时候,我要先到excel中读取下年龄数据,再调用xx接口获取下名字。

哈哈,你也知道我在乱扯。肯本原因就是,Spring哪能啥都知道啊,它也只是个框架,像上面的例子中,你还能指望Spring知道你要读取excel来加载年龄?

正如咱们自己写代码的时候,场景就是千变万化的,@Bean的用处,是告诉你,当某些复杂场景搞不定的时候,你可以自己定义bean的注册逻辑。

所以,复杂点的场景,我要yang某活到1666岁,咱们可以自己放一个想要的Bean进去。

image-20240610131455815

image-20240610131618672

又比如你在用Redis时,经常看到的StringRedisTemplate,这不就是你不满意默认的StringRedisTemplate嘛,你要搞一个给它覆盖了。

    @Bean
    public StringRedisTemplate stringRedisTemplate(@Qualifier("redissonConnectionFactory") RedisConnectionFactory connectionFactory) {
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        stringRedisTemplate.setConnectionFactory(connectionFactory);
        stringRedisTemplate.setKeySerializer(stringRedisSerializer);
        stringRedisTemplate.setValueSerializer(stringRedisSerializer);

        stringRedisTemplate.afterPropertiesSet();
        return stringRedisTemplate;
    }

4.3 @Configuration

Bean命名规则:跟@Componen一样的。

这个玩意呢,打开里面还是@Component,适用于配置类的场景。

image-20240610132927692

所以我们可以知道,它也能注册bean,那既然有自己的名字,肯定做了些定制化的操作。

Configuration这个单词你总该认识吧?什么,这你都不认识?

image-20240610133141821

那看名字我们也能猜到了,它就是专门针对配置类的场景

配置类的话,它的关键点在哪里,在于单例,即咱们的配置项key=123,它不会成key=456,所以@Configuration针对这点做了优化。

不过呢,这个优化点咱们一般感受不到。

Spring 会对 @Configuration 类进行 CGLIB 动态代理增强,确保@Bean对应的方法只被调用一次,直接返回相同的实例(单例)。

有点抽象对不对,我们来看个例子。

@Component
public class MyConfig {

    @Bean
    public User user1() {
        return new User();
    }

    @Bean
    public User user2() {
        // 调用user1方法
        return user1();
    }
    
}

这里我们用的@Component注解,关键点在于下方的user2,它是在调用user1()方法。

此时,@Component注解返回了两个不同的对象。

image-20240610140720240

那我们改成@Configuration

@Configuration
public class MyConfig {

    @Bean
    public User user1() {
        return new User();
    }

    @Bean
    public User user2() {
        return user1();
    }

}

此时,@Component返回的对象是同一个。

image-20240610140822053

哎,有点奇怪了对吧。

注意啊,注意,这不是@Component多例@Configuration单例,是强调这两个类中的@Bean对应的方法执行时会不会被代理掉。

Bean的单例还是多例,取决于Bean它自己本身声明的是单例bean还是原型bean。

你别晕,我给你改造下,是@Component对吧,注册了一个user1的bean(默认为单例bean)。

@Component
public class MyConfig {

    @Bean
    public User user1() {
        return new User();
    }

}

因为它是默认的单例Bean,不管你怎么调用它都还是同一个。

image-20240611165300981

你改成原型Bean。

@Component
public class MyConfig {

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public User user1() {
        return new User();
    }
}

image-20240611165408107

你看,生成出来的Bean是单例还是多例,取决于它自身是单例Bean还是原型Bean。

回顾一下之前的User2这个Bean。

    @Bean
    public User user2() {
        return user1();
    }

    @Bean
    public User user2() {
        return new User();
    }

上方的根本逻辑是什么,是我们主动去触发user1()这个方法了,user1方法干嘛的,给你new个User出来。

@Configuration 中所有带@Bean注解的方法都会被动态代理,调用该方法首次执行后,总该有返回值了吧?后续呢,它不会再执行,直接返回这个实例(除非你又自己主动去强调Bean的类型是原型Bean)。

@Component,注意啊,这里的user2是个原型Bean,意味着每次都会返回新的对象,触发咱们的user1()方法。

image-20240611170336291

image-20240611170410978

改成@Configuration呢,会发现,user1()方法不会多次触发。

image-20240611170429777

image-20240611170452176

哎,你肯定奇怪,那我平时也没有跑去调那个@Bean下面的方法呀。

声明就声明,我没事我乱主动调用干嘛,我自己注册两个User对象,我闲的没事我跑去用user1()方法创建啊?

这应该就是针对这个场景的防范式编码了。

  • 首先呢,咱们不乱调用,Spring源码里面可能涉及到多次调用,是为了确保@Configuration它符合自己的特性。
  • 其次呢,也是为了避免你乱来,在咱们@Configuration类中写的玩意,哪怕你自己乱用,咱们的配置对象也不会混乱。

4.4 @Import

Bean命名规则:跟@Componen一样的。

@Configuration可以将某个类标记为配置类,当配置类比较多的时候呢,我们可以不用再在每个类上写@Configuration,而是统一在一个类中借用@Import引入。

比如这样:

MyConfig2、MyConfig3都上没有注解

public class MyConfig2 {
    @Bean
    User user3(){
        return new User();
    }
}
public class MyConfig3 {
    @Bean
    User user4() {
        return new User();
    }
}

咱们在AppConfig类中引入它们两个配置类。

@Configuration
@Import({MyConfig2.class, MyConfig3.class})
public class AppConfig {

}

验证一下,两个类都能被成功导入。

image-20240611171828484

嗯,这是@Import的一个简单用法,这样我们只用在一个类中(例如AppConfig)去找都导入了哪些玩意,方便管理。

然后呢,还有个常用的用法就是动态导入配置,编写一个类来实现ImportSelector接口即可。

配置选择类

public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        LinkedList<String> configList = new LinkedList<>();
        // 根据条件导入配置类
        if (true) {
            configList.add(MyConfig2.class.getName());
            configList.add(MyConfig3.class.getName());
        }

        return configList.toArray(new String[0]);
    }

}

这里我list.toArray(new String[0])是个正确的写法,返回的就是对应的那个2个长度的数组。并且是建议这样写的,你可以去自己搜索下。

在@Import中使用配置选择类

@Configuration
@Import(MyImportSelector.class)
public class AppConfig {

}

验证结果

image-20240611173026448

4.5 FactoryBean接口

FactoryBean是一个工厂Bean,可以生成指定类型的Bean实例。

实现FactoryBean接口,可以对Bean创建提供更高的灵活性和扩展性,例如动态创建不同类型的 Bean、复杂初始化逻辑、延迟初始化等场景。

好,简单来说,就是我们想要创建某个类型的Bean的时候,可以找这个FactoryBean要。

public interface FactoryBean<T> {
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
        return true;
    }
}

比如上方的User,我们想要创建该类型的bean。

重写的getObject方法中,我们描述详细的创建逻辑。

  • sex为1时,age是18。
  • sex为2时,age是20。
@NoArgsConstructor
@AllArgsConstructor
public class UserFactoryBean implements FactoryBean<User> {

    private int sex;

    @Override
    public User getObject() {
        User user = User.builder()
                .name("yang")
                .age(0)
                .build();

        if (1 == sex) {
            user.setAge(18);
        }
        if (2 == sex) {
            user.setAge(20);
        }

        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

}

注册这个UserFactoryBean。

  • userFactoryBean1:sex为1,其中创建的user的age是18。
  • userFactoryBean2:sex为2,其中创建的user的age是20。
@Slf4j
@Configuration
public class MyConfig {

    @Bean
    public UserFactoryBean userFactoryBean1() {
        return new UserFactoryBean(1);
    }

    @Bean
    public UserFactoryBean userFactoryBean2() {
        return new UserFactoryBean(2);
    }

}

此时,咱们利用UserFactoryBean来获取User对象,并没有说去@Bean来一个user。

image-20240611190430845

哈,这里我拿的Bean名字不是userFactoryBean1吗,咱直接返回里面的User对象了?往后看。

简单来说,就是为了方便,我都开始写FactoryBean了,当然是关注于拿到实际的Bean,咱默认设计成给你直接返回对应Bean实例。

然后呢,你还可以这样用。image-20240611191112047

额,这里你可能看到我用了个&userFactoryBean1,这个&是何用意?

& 前缀在 Spring 中是专门用来获取FactoryBean实例本身的。

即通过 getBean方法获取 Bean 时,FactoryBean这个玩意,默认情况下返回的是它创建的对象。

  • 违背预期:大多数情况下,开发者希望获取的是由 FactoryBean 创建的对象,而不是 FactoryBean 本身。

    例如,当你配置了一个 UserFactoryBean,你希望得到的是 User 对象,而不是 UserFactoryBean的 实例。

  • 简化使用:通过 getBean 方法直接获取目标对象,简化了代码的使用,不需要开发者额外处理 FactoryBean 实例。

  • 避免混淆:明确区分 FactoryBean 和它创建的对象,有助于代码的可读性和可维护性。

那么在例子中,UserFactoryBean本身是不会直接注入的,默认注册的是 UserFactoryBean创建的User,为了注入 UserFactoryBean实例,得像我下面这样:

    @Autowired
    @Qualifier("&userFactoryBean1")
    private UserFactoryBean userFactoryBean1;

不用太纠结,有个印象即可,毕竟,报错了你会搜索,而且,也不是不给你拿,你加&指明下就好了。

有点懵是吧,上图。

image-20240611193658510

4.6 BeanDefinitionRegistryPostProcessor接口

BeanDefinitionRegistryPostProcessor与上面FactoryBean接口类似,实现这个接口,也能创建出Bean。

@Slf4j
@Configuration
public class UserBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        log.info("=====> UserBeanDefinitionRegistryPostProcessor");
        // 创建User类的Bean定义
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.addPropertyValue("name", "yang");
        beanDefinitionBuilder.addPropertyValue("age", 166);

        // 注册User类的Bean定义
        beanDefinitionRegistry.registerBeanDefinition("user", beanDefinitionBuilder.getBeanDefinition());
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        // 这里可以留空,或者用于进一步定制 BeanFactory
    }
}

image-20240611194935762

4.7 spring.factories

这个呢,主要用于三方包的场景。

前面提到了,咱们默认扫描的是启动类和其子包,那我写给别人的stater,我还发个聊天消息给别人说,你来配置下扫描我的xx包?

spring.factories呢无非就是一个固定的文件,咱们写在里面的类,会被自动注册到容器中。

原理呢是基于Java的SPI机制的。

它的位置固定为:

META-INF/spring.factories

好,不妨演示一下。

  • 旧项目cn.yang37
  • 新项目com.yang37

4.7.1 旧项目

我们直接把当前项目清空,你看,啥都没有,只有个简单的Controller和启动类。

image-20240611201444843

记录下当前项目的坐标。

    <groupId>cn.yang37</groupId>
    <artifactId>yang-spring-za</artifactId>
    <version>0.0.1-SNAPSHOT</version>

image-20240611201547931

4.7.2 新项目

然后呢,直接新开一个项目,用不同的包名总可以了吧,新项目用com.yang37-2,这差别够大了吧。

    <groupId>com.yang37-2</groupId>
    <artifactId>yang-spring-za2</artifactId>
    <version>0.0.1-SNAPSHOT</version>

它里面啥也没有,只是导入了spring-boot-starter,代码呢写了两个实体类和配置类,启动类都没有。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

image-20240611201812661

两个实体类,朴实无华,也没用spring的注解。

package com.yang37.za.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User2 {

    private String name;

    private int age;
}
package com.yang37.za.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User3 {
    private String name;

    private int age;

}

然后呢,配置类中,我们把它俩注册为Bean。

package com.yang37.za.config;

import com.yang37.za.entity.User2;
import com.yang37.za.entity.User3;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {

    @Bean
    public User2 user2() {
        return User2.builder()
                .name("user2")
                .age(30)
                .build();
    }

    @Bean
    public User3 user3() {
        return User3.builder()
                .name("user3")
                .age(30)
                .build();
    }

}

接着我们在META-INF\spring.factories声明需要加载UserConfig。

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.yang37.za.config.UserConfig

image-20240611202510674

最后我们将这个项目install。

image-20240611202551996

4.7.3 验证

现在,我们在旧工程中导入打包好的新项目。

        <dependency>
            <groupId>com.yang37-2</groupId>
            <artifactId>yang-spring-za2</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

image-20240611202718928

你看,已经加载进来了。

image-20240611202818037

停,先回顾下。

  • 旧项目cn.yang37:啥也没有
  • 新项目com.yang37:啊,是个外部的玩意,里面记录了要加载哪些bean。

你看,我们在当前项目中,引入了这个带有spring.factories的三方包,我们旧项目自身啥也没有对吧?

验证下,你看,一切都是如期而至。

image-20240611203131426


哎,前面不是讲了,咱们用scan是不是也可以,我们把com.yang37里面的spring.factories删除了重新打包。

没了之后,我们不@ComponentScan直接报错。

image-20240611203448302

加下@ComponentScan,是不是正常啦。

image-20240611203606098

好咯,回顾下,条条大路通罗马,无非就是适用的场景不一样而已。

4.7.4 总结

上面的例子只是演示了一个类似于加载自定义配置类的玩意,实际上咱们有很多场景可以用到。

spring.factories 文件中常见配置项的总结。

配置项类型 说明
org.springframework.boot.autoconfigure.EnableAutoConfiguration 用于指定自动配置类。
org.springframework.context.ApplicationContextInitializer 用于指定初始化 Spring 上下文的类。
org.springframework.context.ApplicationListener 用于指定应用程序事件监听器。
org.springframework.boot.env.EnvironmentPostProcessor 用于在 Spring Boot 应用程序环境准备好后进行处理的类。
org.springframework.boot.SpringApplicationRunListener 用于在 SpringApplication 运行时的监听器。

demo:

# META-INF/spring.factories

# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.yang37.za.config.UserConfig,\
  com.yang37.za.config.OtherConfig

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
  com.yang37.za.config.SomeInitializer,\
  com.yang37.za.config.AnotherInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
  com.yang37.za.config.SomeListener,\
  com.yang37.za.config.AnotherListener

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
  com.yang37.za.config.SomeEnvironmentPostProcessor,\
  com.yang37.za.config.AnotherEnvironmentPostProcessor

# Spring Application Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
  com.yang37.za.config.SomeRunListener,\
  com.yang37.za.config.AnotherRunListener

5.SpringBoot如何创建Bean

5.1 过程

5.2 问题

5.2.1 三级缓存

标签:spring,Spring,Bean,class,bean,yang37,User,创建,public
From: https://www.cnblogs.com/yang37/p/18242704

相关文章

  • SpringBoot内置数据源
    回顾:在我们之前学习在配置文件当中配置对应的数据源的时候,我们设置的数据源其实都是Druid的数据源,并且其配置有两种方式,当然这两种方式都需要我们导入对应的有关德鲁伊的依赖才行一种是直接在开始设置为druid数据源类型的一种是在对应的正常的数据库配置下,设置......
  • 【Azure Spring Apps】Spring App部署上云遇见 502 Bad Gateway nginx
    问题描述在部署AzureSpringApp应用后,访问应用,遇见了502BadGatewayNginx。问题解答502BadGateway, 并且由Nginx返回。而自己的应用中,并没有定义Nginx相关内容,所以需要查看问题是否出现在AzureSpringApp服务的设置上。根据SpringApp的通信模型图判断,502的请求是由N......
  • wimlib API 提供了一系列用于处理 Windows 映像文件(.wim 文件)的函数和数据结构,使开发
    wimlibAPI提供了一系列用于处理Windows映像文件(.wim文件)的函数和数据结构,使开发人员能够在其应用程序中集成对WIM文件的创建、修改和提取功能。以下是一些常见的wimlibAPI:WIM文件的创建和初始化:wimlib_create_new_wim():创建一个新的WIM文件。wimlib_open_wim():......
  • 基于SpringBoot的刷题小程序的设计与实现+附源码+数据库
    摘要:随着互联网技术的快速发展,在线教育平台逐渐成为学生学习和复习的重要工具。为了提高用户在学习过程中的效率和体验,本文提出并实现了一个基于SpringBoot的刷题小程序。该小程序旨在通过高效的题库管理、智能化的刷题功能以及友好的用户界面,帮助用户更好地进行知识点的巩......
  • Java项目:208Springboot + vue实现的校园服务平台(含论文+开题报告)
    作者主页:夜未央5788 简介:Java领域优质创作者、Java项目、学习资料、技术互助文末获取源码项目介绍基于Springboot+vue实现的汽车服务管理系统本系统包含管理员、接单员、普通用户三个角色。管理员角色:管理员管理、基础数据管理、接单详情管理、接单员管理、公告信......
  • Spring学习笔记--1.IoC入门
    Spring学习笔记一、IoC入门1.什么是IoCIoC即控制反转,一个类不再主动控制创建自己所依赖的类,而是交给外部容器去控制创建自己所依赖的类。例如,有一个汽车厂,原本想要制作一辆汽车,需要自己制作发动机、轮胎、方向盘等零部件,汽车就是这个类,发动机和轮胎就是它的依赖项,这些依......
  • 基于springboot+vue.js+uniapp小程序的社区团购系统附带文章源码部署视频讲解等
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaits系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • SpringBoot3.0.x适配mybatis版本
    SpringBoot适配mybatis版本最低为3.0.3<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version><......
  • springboot junit测试
    这边记录的不是怎么在springboot下作测试,而是最近在学习测试时遇到的一个有趣的问题。啰嗦两句,一直觉得单元测试很重要,但我在以前的工作中发现很少有人重视,或者很少有人去写这个单元测试,其实单元测试也不难,关键得上手,慢慢就会有感觉,但说实话一开始不会写的话,需要有个样例,这样你去......
  • 85道Spring高频题整理(附答案背诵版)
    请阐述Spring框架的基本概念。?Spring框架是一个开源的企业级应用开发框架,由RodJohnson创建,并于2003年首次发布。Spring是在全方位提供企业级服务的基础上,用Java实现的。Spring的核心思想是使现代Java开发更加简单。Spring框架以其灵活性和透明性闻名,几乎可以用在任何Ja......