spring_ioc

IOC

准备:

@Test
public void doTest() {
// 传入配置类
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
// 根据name获取bean
Person person = (Person) annotationConfigApplicationContext.getBean("person");
// 根据class获取bean
String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(Person.class);
// 可获得容器中所有组件的名称
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
  1. @Bean

    默认情况下bean的名称和方法名称相同,但也可以使用name属性来指定。

    @Configuration
    @ComponentScan(value = "com.example.springlearn" )
    public class MainConfig {
    @Bean("person1")
    public Person person() {
    return new Person("jony", 19);
    }
    }

    @Test
    public void doTest() {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
    for (String name : beanDefinitionNames) {
    System.out.println(name);
    }
    }

    // 输出:
    // ... person1
  2. @ComponentScan

    value:指定要扫描的包

    excludeFilters = Filter[] 指定扫描的时候按照什么规则排除哪些组件

    includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件

    FilterType.ANNOTATION 按照注解

    FilterType.ASSIGNABLE_TYPE 按照给定的类型

    FilterType.ASPECTJ 使用ASPECTJ表达式

    FilterType.REGEX 使用正则指定

    FilterType.CUSTOM 使用自定义规则

    useDefaultFilters 默认为true,加载所有组件,即使用默认的 Filter 进行包扫描,默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描

    示例:自定义过滤规则需要实现TypeFilter接口

    @Configuration
    @ComponentScans(value = {@ComponentScan(value = "com.example.springlearn",
    includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,
    classes = {MyTypeFilter.class})}, useDefaultFilters = false)})
    public class MainConfig {
    @Bean("person1")
    public Person person() {
    return new Person("jony", 19);
    }
    }

    public class MyTypeFilter implements TypeFilter {
    /**
    * @param metadataReader 读取到当前正在扫描的类信息
    * @param metadataReaderFactory 读取到其他的类信息
    * @return boolean
    */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    // 获取当前类注解信息
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    // 获取当前正在扫描到类的类信息
    ClassMetadata classMetadata = metadataReader.getClassMetadata();
    // 获取当前类资源信息 (类的路径)
    Resource resource = metadataReader.getResource();
    String className = classMetadata.getClassName();
    System.out.println("===> " + className);
    if (className.contains("service")) {
    return true;
    }
    return false;
    }
    }

    // 输出:
    // ... personService
    // person1
  3. @Scope

    singleton:默认,容器启动时就会创建对象,放到IoC容器中;

    prototype:容器启动并不会去调用方法创建对象,而是在每次获取时 才会创建对象。

    @Scope("prototype")
    @Bean
    public Person person() {
    System.out.println("向容器中添加person...");
    return new Person("Tom", 19);
    }
  4. @Lazy

    针对单实例Bean,容器启动时不创建对象,第一次使用(获取)Bean创建对象,并初始化。

  5. @Conditional

    按照一定的条件进行判断,满足条件给容器中注册Bean,可用在方法或类上

    示例:

    @Conditional({WindowsCon.class})
    @Bean("Windows")
    public Person personCon() {
    return new Person("windows", 30);
    }

    @Conditional({LinuxCon.class})
    @Bean("Linux")
    public Person personCon2() {
    return new Person("linux", 35);
    }
    public class LinuxCon implements Condition {
    /**
    * @param conditionContext 判断条件能使用的上下文(环境)
    * @param annotatedTypeMetadata 注释信息
    * @return boolean
    */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    // 获取IOC使用的BeanFactory
    ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
    // 获取类加载器
    ClassLoader classLoader = conditionContext.getClassLoader();
    // 获取当前环境信息
    Environment environment = conditionContext.getEnvironment();
    // 获取bean定义的注册类
    BeanDefinitionRegistry registry = conditionContext.getRegistry();

    // 可以判断容器中bean注册情况, 也可以给容器中注册bean
    boolean definitionRes = registry.containsBeanDefinition("person");

    String property = environment.getProperty("os.name");
    if (property.contains("Windows")) {
    return false;
    }
    return true;
    }
    }
    public class WindowsCon implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    // 获取当前环境信息
    Environment environment = conditionContext.getEnvironment();
    String property = environment.getProperty("os.name");
    return property.contains("Windows");
    }
    }
  6. @Import

    @Import(要导入到容器中到组件),容器中就会自动注册这个组件,id默认是全类名

    示例:新建一个Cat类

    @Configuration
    @Import(Cat.class)
    public class MainConfig2 {
    ...
    }

    public class MainApplication2 {
    public static void main(String[] args) {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
    for (String name : beanDefinitionNames) {
    System.out.println(name);
    }
    }
    }

    // 输出:
    // ... com.example.springlearn.bean.Cat

    ImportSelector:返回需要导入的组件的全数组

    示例:创建一个Dog类

    public class MyImportSelector implements ImportSelector {
    /**
    * @param annotationMetadata 当前标注@Import注解的类的所有注解信息
    * @return java.lang.String[]
    */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
    return new String[]{"com.example.springlearn.bean.Dog"};
    }
    }

    ImportBeanDefinitionRegistrar:手动注册Bean

    示例:创建一个Rabbit类

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
    * @param importingClassMetadata
    * @param registry BeanDefinition注册类, 把所有需要添加到容器中的bean 调用 registry.registerBeanDefinition 手动注册进来
    * @param importBeanNameGenerator
    * @Description // 当前类的注解信息
    */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
    boolean rabbit = registry.containsBeanDefinition("rabbit");
    if (!rabbit) {
    // 指定bean定义信息 (bean的类型 作用域等...)
    RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Rabbit.class);
    // 注册一个bean 指定bean名
    registry.registerBeanDefinition("rrrabbit", rootBeanDefinition);
    }
    }
    }
    @Configuration
    @Import({Cat.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class MainConfig2 {
    ...
    }
    // 输出:
    // ... com.example.springlearn.bean.Cat
    // com.example.springlearn.bean.Dog
    // rrrabbit
  7. FactoryBean

    示例:

    public class CatFactoryBean implements FactoryBean<Cat> {
    /**
    * @Description // 返回一个Cat对象, 这个对象会添加到容器中
    * @return com.example.springlearn.bean.Cat
    */
    @Override
    public Cat getObject() throws Exception {
    System.out.println("Cat getObject()");
    return new Cat();
    }

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

    @Override
    public boolean isSingleton() {
    // true 单例, false 多实例
    return true;
    }
    }
    @Configuration
    @Import({Cat.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class MainConfig2 {
    @Bean
    public CatFactoryBean catFactoryBean() {
    return new CatFactoryBean();
    }
    ...
    }
    @Test
    public void doTest() {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

    // 工厂bean获取的是调用getObject()创建的对象
    Object catFactoryBean = annotationConfigApplicationContext.getBean("catFactoryBean");
    System.out.println("bean的类型: " + catFactoryBean.getClass());

    Object factoryBean = annotationConfigApplicationContext.getBean("&catFactoryBean");
    System.out.println("bean的类型: " + factoryBean.getClass());
    }
    // 输出:
    // ... Cat getObject()
    // bean的类型: class com.example.springlearn.bean.Cat
    // bean的类型: class com.example.springlearn.bean.CatFactoryBean

    默认获取到的是工厂bean调用getObject()创建的对象;

    要获取工厂Bean本身,需要在id前加&;

/**
* 容器中注册组件的方式:
* 1) 包扫描+注解(@Controller, @Service, @Component, @Repository)
* 2) @Bean(导入的第三方包)
* 3) @Import(快速给容器中导入组件)
* @Import id默认是全类名
* ImportSelector 返回需要导入的组件的全类名数组
* ImportBeanDefinitionRegistrar 手动注册bean到容器中
* 4) 使用Spring提供的FactoryBean
* 默认获取到的是工厂bean调用getObject创建的对象
* 要获取工厂bean本身 需要在id前加&
*/

生命周期

/**
* @ClassName MainConfigOfLifeCycle
* @Description
* bean的生命周期: bean创建 -> 初始化 -> 销毁的过程
* 容器管理bean的生命周期:
* 可以自定义初始化和销毁方法: 容器在bean进行到当前生命周期的时候 来调用自定义的初始化和销毁方法
* 构造 (对象创建)
* 单实例: 在容器启动的时候创建对象
* 多实例: 在每次获取的时候创建对象
*
* BeanPostProcessor.postProcessBeforeInitialization
* 初始化:
* 对象创建完成, 并赋值好, 调用初始化方法...
* BeanPostProcessor.postProcessAfterInitialization
* 销毁:
* 单实例: 容器关闭的时候
* 多实例: 容器不会管理这个bean,容器不会调用销毁方法; 需要手动调用
*
* 源码debug:
* 遍历得到容器中所有的BeanPostProcessor: 逐个执行 beforeInitialization
* 一旦返回null, 跳出for循环, 不会执行后面的 BeanPostProcessor.PostProcessorsBeforeInitialization
*
* BeanPostProcessor原理:
* populateBean(beanName, mbd, instanceWrapper); 给bean进行属性赋值
* initializeBean(beanName, exposedObject, mbd) {
* applyBeanPostProcessorsBeforeInitialization(bean, beanName);
* invokeInitMethods(beanName, wrappedBean, mbd); 执行自定义初始化
* applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
* }
*
* 自定义的方法:
* 1) 指定初始化和销毁方法: 指定init-method 和 destroy-method
* 2) 通过让bean实现 InitializingBean, DisposableBean
* 3) 可以使用JSR250:
* @PostConstruct 在bean创建完成并且属性赋值完成: 来执行初始化方法
* @PreDestroy 在容器销毁bean之前通知我们进行清理工作
* 4) BeanPostProcessor【interface】, bean的后置处理器:
* 在bean初始化前后进行一些处理工作:
* postProcessBeforeInitialization: 在初始化之前工作
* postProcessAfterInitialization: 在初始化之后工作
* @Author yjy
* @Date 2020/10/1 16:35
* @Vertion 1.0
**/
  1. 指定初始化和销毁方法

    public class Car {
    public Car() {
    System.out.println("car constructor...");
    }

    public void initCar() {
    System.out.println("car init...");
    }

    public void destroyCar() {
    System.out.println("car destroy...");
    }
    }
    @Configuration
    @ComponentScan("com.example.springlearn.bean")
    public class MainConfigOfLifeCycle {

    @Bean(initMethod = "initCar", destroyMethod = "destroyCar")
    public Car car() {
    return new Car();
    }
    }
    @SpringBootTest
    public class TestLifeCycle {

    @Test
    public void doTest() {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("ioc container finished");
    // 关闭容器
    annotationConfigApplicationContext.close();
    }
    }

    singleton: 容器关闭后执行destroyMethod方法;

    prototype: 获取的时候才会初始化,容器关闭后不会执行destroyMethod方法,需手动调用;

  2. 实现接口 InitializingBean和DisposableBean

    @Component
    public class Bus implements InitializingBean, DisposableBean {
    @Override
    public void destroy() throws Exception {
    System.out.println("Bus destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    System.out.println("Bus afterPropertiesSet...");
    }
    }
  3. @PostConstruct和@PreDestroy

    @Component
    public class Bicycle {
    public Bicycle() {
    System.out.println("Bicycle constructor...");
    }

    // 对象创建并赋值后调用
    @PostConstruct
    public void init() {
    System.out.println("Bicycle PostConstruct...");
    }

    // 容器移除对象前调用
    @PreDestroy
    public void destroy() {
    System.out.println("Bicycle PreDestroy...");
    }
    }
  4. 自定义BeanPostProcessor

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

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

    BeanPostProcessor【interface】, bean的后置处理器, 在bean初始化前后进行一些处理工作:

    • postProcessBeforeInitialization: 在初始化之前工作
    • postProcessAfterInitialization: 在初始化之后工作
  5. BeanPostProcessor原理

    遍历得到容器中所有的BeanPostProcessor: 逐个执行 beforeInitialization,一旦返回null,跳出for循环,不会执行后面的 BeanPostProcessor.PostProcessorsBeforeInitialization;

    BeanPostProcessor原理:

    populateBean(beanName, mbd, instanceWrapper); 给bean进行属性赋值

    initializeBean(beanName, exposedObject, mbd) {

    ​ applyBeanPostProcessorsBeforeInitialization(bean, beanName);

    ​ invokeInitMethods(beanName, wrappedBean, mbd); 执行自定义初始化

    ​ applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

    }

属性赋值

  1. @Value

  2. @PropertySource

    // 使用@PropertySource读取外部配置文件中的 k/v 保存到运行的环境变量中; 加载完外部的配置文件以后使用${}取出配置文件中的值
    @Configuration
    @PropertySource("classpath:/person.properties")
    public class MainConfigOfPropertyValues {
    @Bean
    public Person person() {
    return new Person();
    }
    }
    public class Person {
    private String name;
    /**
    * 使用@Value赋值:
    * 1) 基本数值
    * 2) 可以写SpEL, #{}
    * 3) 可以写${} 取出配置文件【properties】中的值 (在运行环境变量里的值)
    */
    @Value("${p.age}")
    private Integer age;
    ...
    }

    因为是运行时变量,所以可以用applicationContext.getEnvironment

    @SpringBootTest
    public class TestPropertyValues {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);

    @Test
    public void doTest() {
    ConfigurableEnvironment environment = annotationConfigApplicationContext.getEnvironment();
    String property = environment.getProperty("p.age");
    System.out.println(property);
    }
    }

自动装配

Author: Jiayi Yang
Link: https://jiayiy.github.io/2020/09/01/spring-ioc/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.