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注解进行初始化和销毁 (第二种)
- 当对象创建完成后,并赋值好之后,调用初始化方法。
- 容器关闭之后,调用销毁的方法
* 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(); } }