springboot 组件的注册、注入、生命周期

容器篇

配套视频

一.基本概念

组件:具有一定功能的对象

容器:管理组件(创建、获取、保存、销毁)

IOC:Inversion of Control(控制反转)

  • 控制:资源的创建、获取、销毁

  • 反转:和传统方式不同

DI:Dependency Injection(依赖注入)

  • 依赖:组件的依赖关系

  • 注入:通过setter方法、构造器等方式自动注入

二.组件注册

1.主类

运行时返回ioc容器

@SpringBootApplication
public class Demo01Application {
​
    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(Demo01Application.class, args);
    }
​
}

使用以下命令获得所有组件名称

String[] beanNames = ioc.getBeanDefinitionNames();

2.bean组件

a.注册bean组件

首先在bean文件夹中创建类(@Data注解为lombok自动补全)

@Data
public class Person {
    private String name;
    private int age;
    private String gender;
}

然后在主类中创建方法,返回该类

加上@Bean("名字")注解,此时组件就注册好了,组件名默认是方法名

@Bean
public Person zhangsan() {
    Person person = new Person();
    person.setName("zhang");
    person.setAge(18);
    person.setGender("男");
    return person;
}
  • 组件的创建时期:容器的启动过程中就会创建组件对象

  • 组件的默认模式:单例

b.手动获取bean组件

名字获取bean组件,默认为object对象,需要时可以强转为指定类型

Object zhangsan = ioc.getBean("zhangsan");

类型获取单一bean组件,默认为原类型,无须强转

Person bean = ioc.getBean(Person.class);

类型获取所有bean组件,默认为map集合

Map<String, Person> beansOfType = ioc.getBeansOfType(Person.class);

按照类型+名字获取单一bean组件,默认原类型

异常情况:
  • 组件不存在,抛异常

  • 组件不唯一

    • 类型只获取一个组件,抛异常

    • 名字只获取一个组件,不会抛异常,会返回排在最前面的方法

3.Configuration配置类

@Configuration 标注配置类,可用于配置bean组件

@Configuration
public class PersonConfig {
    @Bean
    public Person zhangsan() {
        return new Person("zhangsan", 20, "男");
    }
}

4.SpringMVC分层注解

给人看的,实际都是Component

@Controller控制层
@Service服务层
@Repository持久层
@Component组件

5.ComponentScan组件扫描

@ComponentScan(basePackages = "com.zhang.demo1")

写在配置类上

扫描当前包及其子包,注册了的组件

6.Import导入外部类

外部类无法标注解,只能导入

@Import(xxx.class)

写在配置类上

7.Scope作用域

@Scope("prototype")非单实例
@Scope("singleton")单实例,默认值
@Scope("request")同一请求单实例
@Scope("session")同一会话单实例

8.Lazy懒加载

默认为饿汉式加载,修改为懒汉式加载

@Lazy

标注在@Bean的上方

懒汉加载是指在首次使用时才创建对象实例,而饿汉加载则是在类加载时就创建对象实例。

9.FactoryBean工厂

代替@Bean注解标注组件

适用场景:制造对象复杂的时候

@Component
public class BYD implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        return new Car();
    }

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

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

10.Conditional条件注册

@Contitional(xxx.class)

标注在@bean的上方,需要添加一个条件类

public class windowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return context.getEnvironment().getProperty("os").contains("mac");
    }
}

此外还有多种特殊条件注解

  1. @Conditional:这是最基本的条件注解,它可以接受一个或多个Condition接口的实现类作为参数。只有当所有条件都满足时,才会创建或注册Bean。

  2. @ConditionalOnBean:这个注解用于检查指定的Bean是否存在于Spring容器中。如果存在,则创建或注册当前Bean。

  3. @ConditionalOnMissingBean:与@ConditionalOnBean相反,这个注解用于检查指定的Bean是否不存在于Spring容器中。如果不存在,则创建或注册当前Bean。

  4. @ConditionalOnClass:这个注解用于检查指定的类是否存在于类路径中。如果存在,则创建或注册当前Bean。

  5. @ConditionalOnMissingClass:与@ConditionalOnClass相反,这个注解用于检查指定的类是否不存在于类路径中。如果不存在,则创建或注册当前Bean。

  6. @ConditionalOnProperty:这个注解用于检查指定的属性是否存在于配置文件中,并且其值是否满足指定的条件。如果满足条件,则创建或注册当前Bean。

  7. @ConditionalOnResource:这个注解用于检查指定的资源是否存在于类路径中。如果存在,则创建或注册当前Bean。

  8. @ConditionalOnWebApplication:这个注解用于检查当前应用是否是一个Web应用。如果是,则创建或注册当前Bean。

  9. @ConditionalOnNotWebApplication:与@ConditionalOnWebApplication相反,这个注解用于检查当前应用是否不是一个Web应用。如果不是,则创建或注册当前Bean。

三.组件注入

1.基本注解

  1. @Autowired: 注入方式:默认按照类型(byType)进行注入。如果有多个相同类型的Bean,Spring会尝试按照名称(byName)进行注入。如果仍然无法确定唯一的Bean,Spring会抛出异常。 使用场景:适用于大多数情况,尤其是当只有一个匹配的Bean时。

  2. @Resource: 注入方式:默认按照名称(byName)进行注入。如果没有找到匹配的名称,则按照类型(byType)进行注入。 使用场景:适用于需要明确指定名称进行注入的情况,或者在Java标准库中使用。

  3. @Qualifier: 注入方式:与@Autowired或@Inject一起使用,用于指定具体要注入的Bean。 使用场景:当有多个相同类型的Bean时,通过指定名称或其他限定符来明确注入的Bean。

  4. @Primary: 注入方式:当有多个相同类型的Bean时,使用@Primary注解来指定首选的Bean。当没有使用@Qualifier注解时,Spring会优先注入使用@Primary注解的Bean。 使用场景:适用于有多个相同类型的Bean,但希望有一个默认的首选Bean的情况。

2.构造器注入:

@Component
public class dog {
    private Person person;
    
    public dog(Person person) {
        this.person = person;
    }
}

组件中可以根据构造方法的参数自动注入

在参数前可以用@Qualifier

3.xxxAware感知接口

@Component
public class dog implements EnvironmentAware {

    @Override
    public void setEnvironment(Environment environment) {
        
    }
}
  1. BeanNameAware:获取Bean的名称。

  2. BeanFactoryAware:获取BeanFactory实例。

  3. ApplicationContextAware:获取ApplicationContext实例。

  4. MessageSourceAware:获取国际化消息源。

  5. ApplicationEventPublisherAware:获取事件发布器。

  6. ResourceLoaderAware:获取资源加载器

4.Value属性赋值

加在组件的属性上方

1.直接赋值

@Value("指定值")

2.从配置文件xxx.properties获取值

@Value("${配置文件key}")

3.进行计算赋值

@Value("#{10*20}")

4.调用方法赋值

@Value("'zhangsan'.toUpperCase()")

5.静态调用类赋值

@Value("T(java.lang.Math).random()")

设置默认值

:分割,当取不到cat.name时,默认为Tom

@Value("${cat.name:Tom}")

5.属性来源

写在类上,注明@Value取值的文件

classpath:从项目路径下找

classpath*:从所有包路径下找

@PropertySource("classpath:application.properties")

6.多环境

在指定环境下加载组件

在类或者方法上标注

@Profile("环境标识,环境标识...")

项目默认为default环境

可以在配置文件中修改

spring.profiles.active=环境

四、组件生命周期

1.

1.@Bean自定义初始化/销毁方法

在类中定义相关方法

public void initUser() {
    System.out.println("初始化---------------");
}

public void destroyUser() {
    System.out.println("销毁----------------");
}

@Bean注册为组件时,指明方法

@Bean(initMethod = "initUser", destroyMethod = "destroyUser", name = "myUser")
public Users user() {
    return new Users();
}

2.intializingBean,disposableBean接口

intializingBean:在init之前执行

disposableBean:在destory之前执行

@Data
public class Users implements InitializingBean, DisposableBean{
    private String name;
    private int age;

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("销毁");
    }
}

3.@PostConstruct,@PreDestory方法

@PostConstruct:在intializingBean之前

@PreDestory:在disposableBean之前

@PostConstruct
public void init(){
    System.out.println("PostConstruct");
}

@PreDestroy
public void destroy(){
    System.out.println("PreDestroy");
}

4.BeanPostProcessor后置处理器

BeanPostProcessor是一个拦截所有Bean的后置处理器

@Component
public class beanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization====="+beanName);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization====="+beanName);
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

将其实现后放到容器中,将拦截所有注册的Bean

5.总结

  1. @Bean创建对象

  2. 调用类构造器

  3. postProcessBeforeInitialization

  4. @Autowired set属性注入

  5. PostConstruct

  6. InitializingBean(afterPropertiesSet属性设置之后)

  7. init

  8. postProcessAfterInitialization

  9. -----------------ioc容器创建完毕-------------------

  10. PreDestroy

  11. DisposableBean

  12. destroy

补充:@Autowired 是如何实现的?

  1. 专门有一个处理@Autowired注解的AutowiredAnnotationBeanPostProcessor

  2. 每个 Bean 创建以后,会调用BeanPostProcessorpostProcessBeforeInitialization方法。

  3. postProcessBeforeInitialization里面就会利用反射,得到当前 Bean 的所有属性,利用反射,得到 Bean 属性上标注的所有注解,看有没有@Autowired注解。

  4. 如果有,去容器中找到这个属性对应的组件(按类型,按名字)找到。

-----------------容器篇结束--------------------

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值