【Spring】Spring中bean生命周期重要的四个扩展点

514 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

一.BeanDefinitionRegistryPostProcessor扩展点

1. 重写 postProcessBeanDefinitionRegistry

BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor 需要重写 postProcessBeanDefinitionRegistry 方法

image-20220405185222965

2.获取BeanDefinitionRegistry,增删改BeanDefinition

能过实现 BeanDefinitionRegistryPostProcessor 接口,重写 postProcessBeanDefinitionRegistry 方法 可以拿到 BeanDefinitionRegistry 自己注册bean的定义信息 或者拿到任何一个bean的定义信息进行修改

/**
     * 在完成注册bean定义信息后执行
     * @param registry
     * @throws BeansException
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        //拿到bean的定义信息
        BeanDefinition beanDefinition = registry.getBeanDefinition("a");
        System.out.println("beanDefinition = " + beanDefinition);

        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(C.class);
        HashMap<Object, Object> properMap = new HashMap<>();
        properMap.put("name","我是C");
        genericBeanDefinition.setPropertyValues(new MutablePropertyValues(properMap));
        //注册新的bean定义信息
        registry.registerBeanDefinition("c",genericBeanDefinition);

        System.out.println("BeanDefinitionRegistryPostProcessor 扩展点 执行 postProcessBeanDefinitionRegistry");
    }
      ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:application.xml");

        C bean = applicationContext.getBean(C.class);
        System.out.println("bean = " + bean.getName());

3.执行时机

BeanDefinitionRegistryPostProcessor 执行时间在 创建bean工厂并解析生成bd(BeanDefinition) 之后,执行 BeanFactoryPostProcessor 扩展点之前

二.BeanFactoryPostProcessor 扩展点

1. 重写 postProcessBeanFactory

实现 BeanFactoryPostProcessor 需要重写 postProcessBeanFactory 方法

image-20220405190622211

有非常多的子类 包括我们刚刚看到的 BeanDefinitionRegistryPostProcessor

2. 获取 beanFactory 在bean实例化前对Bean的属性修改

实现BeanFactoryPostProcessor 重写 postProcessBeanFactory 方法

 @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("c");
        beanDefinition.getPropertyValues().addPropertyValue("name","增强c");
        System.out.println("BeanFactoryPostProcessor 的  postProcessBeanFactory 方法执行了 拿到bean工厂");
    }

对bean的属性name进行修改

image-20220405191757958

可以看到结果是重写postProcessBeanFactory 后设置的值

3.执行时机

BeanFactoryPostProcessor 扩展点 在 解析生成bd,并执行BeanDefinitionRegistryPostProcessor扩展点后,实例化bean之前

三. InstantiationAwareBeanPostProcessor 扩展点

1.重写postProcessBeforeInstantiation和postProcessAfterInstantiation

InstantiationAwareBeanPostProcessor 继承自 BeanPostProcessor 接口 有四个默认方法

@Nullable
	default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		return null;
	}


default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		return true;
	}
	
	
	@Nullable
	default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
			throws BeansException {

		return null;
	}
	
	
		@Deprecated
	@Nullable
	default PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {

		return pvs;
	}

2.抑制特定目标bean的默认实例化或者属性注入

  1. postProcessBeforeInstantiation 方法将在 bean实例化前执行,如果返回不为null,将结束当前bean的实例化
  2. postProcessAfterInstantiation 方法将在bean实例化后属性填充前执行,如果返回为false,将不会进行属性注入

首先我们看一个bean C的正常生命周期

image-20220405194608792

而此时 postProcessBeforeInstantiation 返回值为null

image-20220405193911077

如果我不返回null,创建一个新的C对象返回

 @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("InstantiationAwareBeanPostProcessor 的 postProcessBeforeInstantiation 方法执行了 在"+beanName+"实例化之前");

        if (beanClass.isAssignableFrom(C.class)){
            return new C("我是代理C");
        }
        return null;
    }

image-20220405194649930

可以看到此时 执行完 postProcessBeforeInstantiation 返回后 bean的生命周期就结束了,并且容器中的 C 变成了我们返回的对象

再来看 postProcessAfterInstantiation 方法 默认返回true 进行属性注入 如果我们返回false

image-20220405194822095

如果返回false是不是进行属性填充的 因为bean的生命周期中缺少了属性填充 所以bean的name属性没有值

3.执行时机

postProcessBeforeInstantiation 方法将在BeanFactoryPostProcessor 扩展点执行后 bean实例化前执行

postProcessAfterInstantiation 方法将在 bean实例化后,属性填充前执行

四.BeanPostProcessor

1.重写 postProcessBeforeInitialization 和 postProcessAfterInitialization

public interface BeanPostProcessor {


	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}


	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

2.生成新的bean实例以及代理类

1.重写 postProcessBeforeInitialization 方法,生成新的bean实例

重写 postProcessBeforeInitialization 方法,返回一个新的c,没有设置属性值

 @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {


        if (beanName.equals("c")){
            C c = (C) bean;
            System.out.println("当前正在初始化的bean的name值为"+c.getName());
            C c1 = new C();
            return c1;
        }

        return bean;
    }

image-20220405202451660

可以看到此时的bean变成了一个新的bean 注意这个行的bean是不会走Spring中Bean生命周期的其他步骤的,直接就是

new Bean() -> 执行BeanPostProcessor.postProcessAfterInitialization 方法 然后就放到容器中 不会走执行BeanPostProcessor这个扩展点执行时前任何的Spring中bean生命周期过程,包括属性填充

如果 c 依赖 d 且两者都有spring容器管理,则在属性填充时,d会有值 如果没有值,说明没有属性填充

idea64_ZzMhvlfONF

2.重写 postProcessAfterInitialization方法,生成代理类

可以通过重写postProcessAfterInitialization 方法,往容器中添加一个代理类,Spring的AOP就是基于此处实现的

可以看如下的案例演示,此处使用的是JDK动态代理

往容器中添加一个D bean,改bean实现了 Myint 接口 有一个抽象方法 say();

image-20220405204632748

image-20220405204638794

image-20220405204651432

通过实现 BeanPostProcessor 重写 postProcessAfterInitialization 方法,往容器中添加一个代理对象

image-20220405204749732

代理类MyProxy

public class MyProxy {


    public Myint proxy(Object target)
    {

        Myint o = (Myint) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("方法执行前增强");
                        Object invoke = method.invoke(target);
                        System.out.println("方法执行后增强");

                        return invoke;
                    }
                }
        );

        return o;

    }

}

我们从容器中取出这个对象,并执行say方法

image-20220405204837006

image-20220405204851485

可以看到执行的是代理类的方法,也就是说往容器中添加的是代理类对象

五.总结图