129.【Spring 注解_IOC】(三)

简介: 129.【Spring 注解_IOC】

7.@Import给容器中快速导入一个组件

这个注解需要放在我们的配置类上,因为配置类项目刚启动的时候就会加载进组件,我们IOC需要识别到这个 @Import 才能继续工作。

/**
     *  给容器中注册组件
     *  1. 包扫描 + 组件标注注解 (repository,service controller component)
     *  2. @Configuration + @Bean
     *  3. @Import[快速给容器导入一个组件]
     *    (1).@Import(要导入的容器),容器中会自动注册这个组件,id默认是全限定名。
     *    (2).@ImportSelector: 返回需要导入的组件的全限定名数组。
     *  4.FactoryBean: 使用Spring提供的FactoryBean (工厂Bean)
     */
(1).@Import

1.要注册的组件

package com.jsxs.bean;
/**
 * @Author Jsxs
 * @Date 2023/8/13 20:54
 * @PackageName:com.jsxs.bean
 * @ClassName: Color
 * @Description: TODO
 * @Version 1.0
 */
public class Color {
}

2.@Import注解放在类上

package com.jsxs.config;
import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
// 快速的导入组件,id默认的是全限定名 ⭐
@Import(Color.class)
public class MyConfig2 {
    /**
     * 1. singleton 但是列的
     * 2.prototype 多实列   (默认值)
     * 3. 同一次请求创建一个实列
     * 4. 同一个session创建一个实列
     */
    @Scope(value = "singleton")
    @Bean("person2")
    @Lazy
    public Person person() {
        return new Person("张三2", 22);
    }
    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})
    @Bean("person01")
    public Person person01() {
        return new Person("张三01", 33);
    }
    @Conditional(LinuxConditional.class)
    @Bean("person02")
    public Person person02() {
        return new Person("张三02", 33);
    }
}

3.测试

package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getSystemEnvironment());
        // 3.获取我们具体的属性名
        System.out.println(environment.getProperty("os.name"));
        // 2.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

(2).ImportSelector ⭐

假如我们的类实现了 ImportSelector 的接口,那么我们这个类的返回值就是我们需要注入IOC容器中组件的全限定名。.

1.MyImportSelector.java

package com.jsxs.conditional;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
 * @Author Jsxs
 * @Date 2023/8/13 21:07
 * @PackageName:com.jsxs.conditional
 * @ClassName: MyImportSelector
 * @Description: TODO   自定义逻辑返回需要导入的组件
 * @Version 1.0
 */
public class MyImportSelector implements ImportSelector {
    /**
     *
     * @param importingClassMetadata :  当前标注@Import注解的类的所有注解信息
     * @return : 返回值就是导入容器中的组件全类名
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.jsxs.bean.Yellow","com.jsxs.bean.Red"};  // ⭐
    }
}
package com.jsxs.config;
import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.MyImportSelector;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
// 快速的导入组件,id默认的是全限定名   ⭐⭐
@Import({Color.class, MyImportSelector.class})
public class MyConfig2 {
    /**
     * 1. singleton 但是列的
     * 2.prototype 多实列   (默认值)
     * 3. 同一次请求创建一个实列
     * 4. 同一个session创建一个实列
     */
    @Scope(value = "singleton")
    @Bean("person2")
    @Lazy
    public Person person() {
        return new Person("张三2", 22);
    }
    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})
    @Bean("person01")
    public Person person01() {
        return new Person("张三01", 33);
    }
    @Conditional(LinuxConditional.class)
    @Bean("person02")
    public Person person02() {
        return new Person("张三02", 33);
    }
    /**
     *  给容器中注册组件
     *  1. 包扫描 + 组件标注注解 (repository,service controller component)
     *  2. @Configuration + @Bean
     *  3. @Import
     */
}

(3). ImportBeanDefinitionRegistrar

1.我们需要实现一个接口 ImportBeanDefinitionRegistrar

package com.jsxs.conditional;
import com.jsxs.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
 * @Author Jsxs
 * @Date 2023/8/14 8:44
 * @PackageName:com.jsxs.conditional
 * @ClassName: MyImportBeanDefinitionRegistrar
 * @Description: TODO
 * @Version 1.0
 */
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata : 当前类的注解信息
     * @param registry : BeanDefinition注册类
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 1.先判断我们的容器中是否有有我们将要注入IOC容器的组件
        if (registry.containsBeanDefinition("com.jsxs.bean.Color")) {
            // 第一个参数是我们注册后的组件名叫什么,第二个参数是我们需要使用类的全限定名 ⭐
            registry.registerBeanDefinition("RainBow",new RootBeanDefinition(RainBow.class));
        }
    }
}

2. 配置类编写

package com.jsxs.config;
import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.MyImportBeanDefinitionRegistrar;
import com.jsxs.conditional.MyImportSelector;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:20
 * @PackageName:com.jsxs.config
 * @ClassName: MyConfig2
 * @Description: TODO
 * @Version 1.0
 */
@Configuration
// 快速的导入组件,id默认的是全限定名  ⭐⭐
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MyConfig2 {
    /**
     * 1. singleton 但是列的
     * 2.prototype 多实列   (默认值)
     * 3. 同一次请求创建一个实列
     * 4. 同一个session创建一个实列
     */
    @Scope(value = "singleton")
    @Bean("person2")
    @Lazy
    public Person person() {
        return new Person("张三2", 22);
    }
    /*
        @ conditional({condition列表}) 按照条件进行注入我们的组件
        提出需求:  假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
     */
    @Conditional({WindowConditional.class})
    @Bean("person01")
    public Person person01() {
        return new Person("张三01", 33);
    }
    @Conditional(LinuxConditional.class)
    @Bean("person02")
    public Person person02() {
        return new Person("张三02", 33);
    }
}

3.进行测试的操作

package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getSystemEnvironment());
        // 3.获取我们具体的属性名
        System.out.println(environment.getProperty("os.name"));
        // 2.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

(4).FactoryBean

第四种在IOC容器中注入我们的组件的方法就是 我们Spring提供的 FactoryBean 工厂。我们只需要实现接口 FactoryBean< T> 这里的 T 就是我们需要的被注入IOC容器的组件类名称。

1. 实际要被注入IOC容器的类

package com.jsxs.bean;
/**
 * @Author Jsxs
 * @Date 2023/8/14 9:53
 * @PackageName:com.jsxs.bean
 * @ClassName: Color_factory
 * @Description: TODO
 * @Version 1.0
 */
public class Color_factory {
}

2.实现我们的接口

package com.jsxs.bean;
import org.springframework.beans.factory.FactoryBean;
/**
 * @Author Jsxs
 * @Date 2023/8/14 9:15
 * @PackageName:com.jsxs.bean
 * @ClassName: ColorFactoryBean
 * @Description: TODO
 * @Version 1.0
 */
// 创建一个Spring定义的FactoryBean  ⭐
public class ColorFactoryBean implements FactoryBean<Color_factory> {  // 这里我们指定我们的类型T为 我们想要注册的组件
    // 1.返回一个 ColorFactoryBean 对象,这个对象会添加到容器中去 ⭐
    @Override
    public Color_factory getObject() throws Exception {
        return new Color_factory();
    }
    // 2.返回类的类型  ⭐
    @Override
    public Class<?> getObjectType() {
        return Color_factory.class;
    }
    // 3. 是否是单列? ⭐
    /**
     *
     * @return : 假如说为true,那么我们就是单实列的,假如说为false,那么我们就不是单实列的。
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}

3.配置类中注册我们的ColorFactoryBean

@Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

4.测试输出

package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
 * @Author Jsxs
 * @Date 2023/8/12 20:22
 * @PackageName:com.jsxs.Test
 * @ClassName: Main_Ann2
 * @Description: TODO
 * @Version 1.0
 */
public class Main_Ann2 {
    public static void main(String[] args) {
        // 1.将这个配置文件中的组件放入我们的IOC容器中
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
        // 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        System.out.println(environment.getSystemEnvironment());
        // 3.获取我们具体的属性名
        System.out.println(environment.getProperty("os.name"));
        // 2.遍历我们所有的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
        System.out.println(applicationContext.getBean("colorFactoryBean")+"-----");
    }
}

遍历所有组件,我们只会得到表象为 colorFactory 这个组件。实际上我们通过组件的名字获取这个colorFactory便会得到我们实际上注入组件的类型和名字。

com.jsxs.bean.Color_factory@276438c9 这个是实际上注入的组件

(二)、组件的生命周期

1.@Bean指定初始化和销毁方法

(1). 使用配置文件进行自定义我们的初始化方法和销毁方法 (第一种)

(2).通过@Bean注解进行初始化和销毁 (第二种)
  1. 当对象创建完成后,并赋值好之后,调用初始化方法。
  2. 容器关闭之后,调用销毁的方法
* Bean的生命周期
 *                      bean 创建 -> 初始化 -> 销毁的过程
 *                      容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 *                      1. init-method="" destroy-method=""
 *                      2. 构造(对象创建)
 *                          单实列: 在容器启动的时候创建对象
 *                          多实列: 在调用到组件的时候创建对象

1.Car.java

package com.jsxs.bean;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:12
 * @PackageName:com.jsxs.bean
 * @ClassName: Car
 * @Description: TODO
 * @Version 1.0
 */
public class Car {
    public Car(){
        System.out.println("Car Constructor ....");
    }
    public void init(){
        System.out.println("Car Init...");
    }
    public void destroy(){
        System.out.println("Car Destroy...");
    }
}

2.配置类

package com.jsxs.config;
import com.jsxs.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 *                      bean 创建 -> 初始化 -> 销毁的过程
 *                      容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 *                      1. init-method="" destroy-method=""
 *                      2. 构造(对象创建)
 *                          单实列: 在容器启动的时候创建对象
 *                          多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */
@Configuration
public class MainConfigOfLifeCycle {
    // 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。 ⭐
    @Bean(value = "car",destroyMethod = "destroy",initMethod = "init")
    public Car car(){
        return new Car();
    }
}

3.测试

package com.jsxs.Test;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:16
 * @PackageName:com.jsxs.Test
 * @ClassName: IOC_LifeStyle
 * @Description: TODO
 * @Version 1.0
 */
public class IOC_LifeStyle {
    public static void main(String[] args) {
        // 1.创建IOC容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        // 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
        applicationContext.close();
        // 1.遍历所有IOC容器中的组件
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }
    }
}

2.InitializingBean与 DisposableBean 进行初始化和销毁 (第三种)

(1).通过实现接口进行初始化和销毁的操作

1.我们需要自定义的bean只需要实现两个接口InitializingBean, DisposableBean即可

package com.jsxs.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
 * @Author Jsxs
 * @Date 2023/8/14 19:57
 * @PackageName:com.jsxs.bean
 * @ClassName: Car01
 * @Description: TODO
 * @Version 1.0
 */
public class Car01 implements InitializingBean, DisposableBean {
    public Car01() {
    }
    // 1.初始化的操作
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Car01进行初始化...");
    }
    // 2.销毁的操作
    @Override
    public void destroy() throws Exception {
        System.out.println("Car01进行销毁...");
    }
}
package com.jsxs.config;
import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @Author Jsxs
 * @Date 2023/8/14 17:04
 * @PackageName:com.jsxs.config
 * @ClassName: MainConfigOfLifeCycle
 * @Description: TODO  Bean的生命周期
 * bean 创建 -> 初始化 -> 销毁的过程
 * 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
 * 1. init-method="" destroy-method=""
 * 2. 构造(对象创建)
 * 单实列: 在容器启动的时候创建对象
 * 多实列: 在调用到组件的时候创建对象
 * @Version 1.0
 */
@Configuration
public class MainConfigOfLifeCycle {
    @Bean
    public Car01 car01() {
        return new Car01();
    }
}

相关文章
|
1月前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
50 0
|
2月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
133 3
|
18天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
38 2
|
23天前
|
前端开发 Java Spring
Spring MVC核心:深入理解@RequestMapping注解
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的核心,它将HTTP请求映射到控制器的处理方法上。本文将深入探讨`@RequestMapping`注解的各个方面,包括其注解的使用方法、如何与Spring MVC的其他组件协同工作,以及在实际开发中的应用案例。
37 4
|
1月前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
62 4
SpringBoot必须掌握的常用注解!
|
23天前
|
前端开发 Java 开发者
Spring MVC中的请求映射:@RequestMapping注解深度解析
在Spring MVC框架中,`@RequestMapping`注解是实现请求映射的关键,它将HTTP请求映射到相应的处理器方法上。本文将深入探讨`@RequestMapping`注解的工作原理、使用方法以及最佳实践,为开发者提供一份详尽的技术干货。
69 2
|
23天前
|
前端开发 Java Spring
探索Spring MVC:@Controller注解的全面解析
在Spring MVC框架中,`@Controller`注解是构建Web应用程序的基石之一。它不仅简化了控制器的定义,还提供了一种优雅的方式来处理HTTP请求。本文将全面解析`@Controller`注解,包括其定义、用法、以及在Spring MVC中的作用。
40 2
|
27天前
|
消息中间件 Java 数据库
解密Spring Boot:深入理解条件装配与条件注解
Spring Boot中的条件装配与条件注解提供了强大的工具,使得应用程序可以根据不同的条件动态装配Bean,从而实现灵活的配置和管理。通过合理使用这些条件注解,开发者可以根据实际需求动态调整应用的行为,提升代码的可维护性和可扩展性。希望本文能够帮助你深入理解Spring Boot中的条件装配与条件注解,在实际开发中更好地应用这些功能。
32 2
|
27天前
|
JSON Java 数据格式
springboot常用注解
@RestController :修饰类,该控制器会返回Json数据 @RequestMapping(“/path”) :修饰类,该控制器的请求路径 @Autowired : 修饰属性,按照类型进行依赖注入 @PathVariable : 修饰参数,将路径值映射到参数上 @ResponseBody :修饰方法,该方法会返回Json数据 @RequestBody(需要使用Post提交方式) :修饰参数,将Json数据封装到对应参数中 @Controller@Service@Compont: 将类注册到ioc容器
|
28天前
|
XML Java 数据格式
SpringBoot入门(8) - 开发中还有哪些常用注解
SpringBoot入门(8) - 开发中还有哪些常用注解
38 2