spring bean生命周期内拦截点和场景运用

概述

创建 bean 的过程中有多个可以自定义的扩展点,以便在 bean 的生命周期中执行自定义操作,以下是在整个生命周期内,可以自定义的点和场景举例

BeanDefinitionRegistryPostProcessor

bean定义注册后处理器,允许你在 Spring 容器初始化之前修改或注册 bean 定义。你可以实现这个接口来自定义 bean 的注册
注入

  1. 注入
 <bean class="org.example.bean.MyBeanDefinitionRegistryPostProcessor"/>
  1. 自定义
public class MyBeanDefinitionRegistryPostProcessor
    implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
       
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      
    }
}

从哪开始调用的?以上我们定义个实现了BeanDefinitionRegistryPostProcessor的bean后spring在哪调用的?下面是初始化调用的地方

  1. AbstractApplicationContext方法refresh调用 bean工厂后置处理器:invokeBeanFactoryPostProcessors,此时bean工厂ConfigurableListableBeanFactory已经实例化完成
  2. 以上方法调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    是个静态方法,就是在此方法调用的,关键代码如下:
while (reiterate) {
				reiterate = false;
        //根据BeanDefinitionRegistryPostProcessor这个class类型得到postProcessorNames,
        看到没,此时就得到了我们的bean name
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        
        for (String ppName : postProcessorNames) {
           if (!processedBeans.contains(ppName)) {
              currentRegistryProcessors.add(beanFactory.getBean(ppName, 
        BeanDefinitionRegistryPostProcessor.class));
              processedBeans.add(ppName);
              reiterate = true;
           }
        }
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        //这里反射调用的
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();
	}
//这里调用 invokeBeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
}
  1. 方法invokeBeanDefinitionRegistryPostProcessors调用
private static void invokeBeanDefinitionRegistryPostProcessors(
      Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

   for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
      StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
            .tag("postProcessor", postProcessor::toString);
			//这里调用postProcessBeanDefinitionRegistry
      postProcessor.postProcessBeanDefinitionRegistry(registry);
      postProcessBeanDefRegistry.end();
   }
}

至此初始化调用流程分析完毕

方法:postProcessBeanDefinitionRegistry

对BeanDefinitionRegistry的一些操作,可以动态增删bean

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
    genericBeanDefinition.setBeanClass(MyBean1.class);
    //注册bean
    registry.registerBeanDefinition("myBean", genericBeanDefinition);
    //删除bean,前提存在
    if(registry.containsBeanDefinition("beanName")){
        registry.removeBeanDefinition("beanName");
    }
}

场景1:自定义扫描包并注册bean

  1. 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface CustomComponent {
}
  1. 扫描自定义package并注册bean
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
    ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
    TypeFilter filter = new AnnotationTypeFilter(CustomComponent.class);
    scanner.addIncludeFilter(filter);

    // 扫描指定包
    for (BeanDefinition beanDefinition : scanner.findCandidateComponents("org.example.bean")) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
            ClassUtils.resolveClassName(Objects.requireNonNull(beanDefinition.getBeanClassName()), ClassUtils.getDefaultClassLoader()));
        registry.registerBeanDefinition(beanDefinition.getBeanClassName(), builder.getBeanDefinition());
    }
}

自定义包下,注解为CustomComponent的类都会被注册到bean中

方法:postProcessBeanFactory

ConfigurableListableBeanFactory的一些操作,这个就比较丰富
以下是使用场景举例:

场景1:动态注册单例bean

 @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      beanFactory.registerSingleton("myBean1",new MyBean1());
  }

场景2:添加bean的后置处理拦截器BeanPostProcessor

BeanPostProcessor 是bean在初始化前后的拦截器,创建多少bean 拦截多少次,可以通过postProcessBeanFactory,动态把拦截器添加进去

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.registerSingleton("myBean1",new MyBean1());

        beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
    }

MyBeanPostProcessor 定义如下

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("开始注册:" + beanName);
        return bean;
    }

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

场景3:自定义属性配置(挺不错)

什么意思,就是可以给自定义的属性进行转换,将字符串值转换为特定类型的属性值。
看个场景就明白 了
bean为User的对象有个属性是private Address address;
Address 里边也有自己的属性,如下:

private String address1;
private String address2;
private String address3;

我在注入bean的时候,如果传输的是个字符串或者其他乱七八糟的格式,反正不是Address,我该如下转换呢?
如下bean配置,address给的是河南-郑州-高新区这显然不是对象,那我们就可以利用自定义转换器来进行转换

<bean id="user"  class="org.example.bean.User">

    <property name="id" value="1"/>
    <property name="name" value="张三"/>
    <property name="address" value="河南-郑州-高新区"/>
</bean>
自定义转换器定义
  1. 新建Address对应的转换器AddressEditor要继承PropertyEditorSupport,重写方法setAsText其实这里得到的就是以上的河南-郑州-高新区字符串,我们手动转换,最后调用setValue封装进去即可
public class AddressEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        String[] arrs = text.split("-");
        Address address = new Address();
        address.setAddress1(arrs[0]);
        address.setAddress2(arrs[1]);
        address.setAddress3(arrs[2]);
        super.setValue(address);
    }
}
  1. AddressEditor肯定需要注册呀,怎么注册?新建个自定义转换注册器呗,实现PropertyEditorRegistrar
public class CustomEditorRegistrar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Address.class, new AddressEditor());
    }
}
  1. 那注册器要交给spring处理,那我们就可以通过postProcessBeanFactory方法的 把注册器加进去
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   beanFactory.addPropertyEditorRegistrar(new CustomEditorRegistrar());
}

执行后,bean的Address就是我们转换后的值

场景4:属性值的动态注入

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 修改属性
        BeanDefinition user = beanFactory.getBeanDefinition("user");
        MutablePropertyValues propertyValues = user.getPropertyValues();
        propertyValues.addPropertyValue("id","123456");
    }
}

场景5:bean定义修改

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 修改属性
    BeanDefinition bd = beanFactory.getBeanDefinition("user");
    //修改初始方法、是否为单例,等其他属性
    bd.setInitMethodName("test2");
}

FactoryBeans

用于创建和配置对象实例。它允许你将对象的创建和配置逻辑封装在一个独立的类中

public class MyBeanFactory implements FactoryBean<User> {

    @Override
    public User getObject() throws Exception {
        // 在这里可以编写创建和配置 MyBean 实例的逻辑
        return new User();
    }

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

    @Override
    public boolean isSingleton() {
        return true; // 这里可以指定对象是否是单例
    }
}

<bean id="myBean" class="org.example.bean.MyBeanFactory"/>
这样也能创建bean

InitializingBean

bean 实现 InitializingBean 重写方法afterPropertiesSet

@Override
public void afterPropertiesSet() throws Exception {
    System.out.println("afterPropertiesSet");
}
  • 调用时机?

bean完成初始化(还未实例化)之后调用,类AbstractApplicationContext refresh 你应该不会陌生,此方法执行到
finishBeanFactoryInitialization(beanFactory);

实例化bean

带着问题来看bean的实例化,并知道在何时执行的以上afterPropertiesSet

  1. 以上方法会执行beanFactory 实现类DefaultListableBeanFactory方法preInstantiateSingletons

简化代码:

public void preInstantiateSingletons() throws BeansException {
  
  //beanDefinitionNames 你应该不陌生,这就是储存所有bean name 的一个list
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   
   for (String beanName : beanNames) {
		//就是根据bean 名称 实例化 bean
       getBean(beanName);
      }
   }

以上代码就是循环bean名称,然后实例化

  1. getBean 会调用doGetBean 此方法就是根据bean name得到成员变量mergedBeanDefinitions 得到bean的元数据信息,也是个map,里边储存的是RootBeanDefinition他里边就储存了你在xml中定义的bean属性信息
  2. 有了name,有了 对应的元数据,可以创建bean了,最终创建代码在类AbstractAutowireCapableBeanFactory
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
   try {
      Object beanInstance;
      beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
      BeanWrapper bw = new BeanWrapperImpl(beanInstance);
      initBeanWrapper(bw);
      return bw;
   }
  1. getInstantiationStrategy 会得到实例化策略类,这里是SimpleInstantiationStrategy,代码就来到了这里,这里没啥好讲的,就是得到反射类Constructor然后根据 .class 创建,具体创建使用的是工具类BeanUtils.instantiateClass(constructorToUse)
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
   if (!bd.hasMethodOverrides()) {
      Constructor<?> constructorToUse;
      synchronized (bd.constructorArgumentLock) {
         constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
         if (constructorToUse == null) {
            final Class<?> clazz = bd.getBeanClass();

            constructorToUse = clazz.getDeclaredConstructor();

            bd.resolvedConstructorOrFactoryMethod = constructorToUse;
            }
            catch (Throwable ex) {
               throw new BeanInstantiationException(clazz, "No default constructor found", ex);
            }
         }
      }
      return BeanUtils.instantiateClass(constructorToUse);
   }

Constructor用法:

 Class<Person> personClass = Person.class;
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);

// 使用构造函数创建对象
Person person = constructor.newInstance("Alice", 25);
  1. 那以上创建好后返回的最终是个BeanWrapper对象,他是spring提供的一个bean工具类,用于方便地访问和操作 bean 对象的属性

具体用法如下:

public static void main(String[] args) {
        // 创建一个简单的对象
        Person person = new Person();
        
        // 使用 BeanWrapper 包装这个对象
        BeanWrapper wrapper = new BeanWrapperImpl(person);
        
        // 设置属性值
        wrapper.setPropertyValue("name", "Alice");
        wrapper.setPropertyValue("age", 25);
        // 获取属性值
        String name = (String) wrapper.getPropertyValue("name");
        int age = (int) wrapper.getPropertyValue("age");
        
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    	  //获取对象
			Object bean = wrapper.getWrappedInstance();
    }

到此,bean实例化完成,最终返回一个bean包装类BeanWrapper

调用afterPropertiesSet 以及定义的初始化方法

回到最初,刚刚只有bean name和RootBeanDefinition 如何关联上BeanWrapper 的?

  1. 方法doCreateBean 关联代码,mbd 就是RootBeanDefinition对象,getWrappedClass就是获取 bean的class
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
  mbd.resolvedTargetType = beanType;
}
  1. 初始化bean 方法doCreateBean 调用initializeBean调用invokeInitMethods,简化代码如
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {

   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      
      ((InitializingBean) bean).afterPropertiesSet();
   }

   if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}
  1. 以上第一个if 就是进入afterPropertiesSet关键代码,啥意思,bean满足继承了InitializingBean,就调用
  2. 看第二个if是啥mbd.getInitMethodName()mbd 就是RootBeanDefinitiongetInitMethodName就是你在xml中定义的初始化方法,xml配置如下:

<bean id="user" class="org.example.bean.User" init-method="test"/>

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

init-method 定义的方法,如果他有长度,而且方法名不是afterPropertiesSet而且不是mbd.isExternallyManagedInitMethod(initMethodName)这个是什么意思?这个引申出另一个概念了:待续
然后利用反射执行我们定义的初始化方法

总结

afterPropertiesSet是在初始化bean和实例化之后,调用的,在他执行之后才会调用其他xml定义的init-method

  • 注意init-method 只接受一个无参的初始化方法
Spring bean的生命周期可以分为以下阶段: 1. 实例化:通过反射或工厂方法创建对象实例。 2. 属性注入:将对象的属性设置bean实例中。 3. Aware回调:调用实现了Aware接口的回调方法,例如BeanNameAware、BeanFactoryAware等。 4. 初始化前回调:调用实现了InitializingBean接口或使用@Bean(initMethod="methodName")指定的初始化方法。 5. 初始化后回调:调用实现了BeanPostProcessor接口的postProcessBeforeInitialization和postProcessAfterInitialization方法。 6. 销毁前回调:调用实现了DisposableBean接口或使用@Bean(destroyMethod="methodName")指定的销毁方法。 7. 销毁后回调:调用实现了BeanPostProcessor接口的postProcessBeforeDestruction方法。 下面我们来分析一下Spring源码中bean的生命周期实现过程。 首先,Spring使用BeanFactory在需要时创建bean实例。BeanFactory是一个接口,它定义了获取和管理bean的方法。在使用Spring时,通常使用其子接口ApplicationContext。 BeanFactory的实现类DefaultListableBeanFactory中,当调用getBean方法时,会根据传入的bean名称从缓存中获取bean实例,如果缓存中没有,则会调用createBean方法创建一个新的实例。 createBean方法中,首先会进行实例化,即通过反射或工厂方法创建对象实例。然后,会进行属性注入,将对象的属性设置bean实例中。 接下来,会调用实现了Aware接口的回调方法,例如BeanNameAware、BeanFactoryAware等。然后,会调用实现了InitializingBean接口或使用@Bean(initMethod="methodName")指定的初始化方法。 在调用初始化方法之前,会先调用实现了BeanPostProcessor接口的postProcessBeforeInitialization方法。在调用初始化方法之后,会调用实现了BeanPostProcessor接口的postProcessAfterInitialization方法。 在bean被销毁之前,会调用实现了DisposableBean接口或使用@Bean(destroyMethod="methodName")指定的销毁方法。在销毁方法之前,会先调用实现了BeanPostProcessor接口的postProcessBeforeDestruction方法。最后,销毁bean实例。 总结一下,Spring bean的生命周期主要是通过BeanFactory中的createBean方法实现的,包括实例化、属性注入、Aware回调、初始化前后回调、销毁前后回调等过程。其中,BeanPostProcessor接口的实现类可以在bean的初始化前后进行拦截和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值