Spring中的Bean可以绕过生命周期管理吗?

结论

答案是可以的。

Talk is cheap. Show me the code

第一步:定义一个类实现任意Spring中Bean生命周期相关方法。

package com.xxx.hyl.ignore.lifecycle;

import org.springframework.beans.factory.InitializingBean;

/***
 * 演示当前类跳过Spring IoC 容器Bean生命周期管理
 * @author 君战
 * */
public class IgnoreLifecycleBean implements InitializingBean {

    private String createdBy;

    // 这里只是为了演示,所以只选择实现InitializingBean接口,只要该接口可以跳过,其它的生命周期方法都是一样的。
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println(this.getClass().getSimpleName() + " -----> afterPropertiesSet 方法执行");
    }

    public String getCreatedBy() {
        return createdBy;
    }

    public void setCreatedBy(String createdBy) {
        this.createdBy = createdBy;
    }
}

第二步:编写一个类实现InstantiationAwareBeanPostProcessor接口,并重写其postProcessBeforeInstantiation方法。

package com.xxx.hyl.ignore.lifecycle;

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

/**
 * 演示通过实现{@linkplain InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(Class,
 * String)} 方法来让Bean跳过IoC容器生命周期管理
 *
 * @author 君战 *
 */
public class CustomizedBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
            throws BeansException {
        if (IgnoreLifecycleBean.class.equals(beanClass)) {
            IgnoreLifecycleBean ignoreLifecycleBean = new IgnoreLifecycleBean();
            ignoreLifecycleBean.setCreatedBy("customize init");
            return ignoreLifecycleBean;
        }
        return null;
    }
}

第三步:编写一个类来测试

package com.xxx.hyl.ignore.lifecycle;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * 演示Bean跳过IoC容器的生命周期管理
 * @author 君战
 * **/
public class IgnoreLifecycleBeanDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(IgnoreLifecycleBean.class,CustomizedBeanPostProcessor.class);
        context.refresh();
        IgnoreLifecycleBean ignoreLifecycleBean = context.getBean(IgnoreLifecycleBean.class);
        System.out.println(ignoreLifecycleBean.getCreatedBy());
    }
}

第四步:查看控制台打印结果。

可以看到,IgnoreLifecycleBean 所实现的InitializingBean的afterPropertiesSet方法并未被调用,并且其getCreatedBy方法所返回的数据和我们在CustomizedBeanPostProcessor的postProcessBeforeInstantiation方法设置的一致。那么接下来就进入底层原理分析。

底层原理分析

在AbstractAutowireCapableBeanFactory的createBean方法中,首先通过resolveBeanClass方法来解析BeanDefinition,获取要实例化的BeanClass。然后调用RootBeanDefinition的prepareMethodOverrides方法,重点是接下来调用的resolveBeforeInstantiation方法,可以看到如果该方法的返回值不为空,则createBean方法结束,而不会再去调用IoC容器中真正实例化Bean的方法-doCreateBean。

// AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {

   if (logger.isTraceEnabled()) {
      logger.trace("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   try {
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
	  // 调用所有实现了InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法
	  // 任何一个InstantiationAwareBeanPostProcessor接口实现类的postProcessBeforeInstantiation方法返回值不为null,那么则结束当前beanName所对应Bean的创建和初始化。
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }

   try {
	  // 这是IoC容器真正实例化Bean的地方
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);
      if (logger.isTraceEnabled()) {
         logger.trace("Finished creating instance of bean '" + beanName + "'");
      }
      return beanInstance;
   }
   catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
   }
}

而讲到这个resolveBeforeInstantiation方法,就不得不提InstantiationAwareBeanPostProcessor接口,该接口继承自Spring IoC容器中大名鼎鼎的BeanPostProcessor接口,并定义了四个接口方法-postProcessBeforeInstantiation方法和postProcessAfterInstantiation方法以及postProcessProperties方法和postProcessPropertyValues方法(该方法已被标记为废弃)。

而前面的resolveBeforeInstantiation方法就是调用IoC容器中所有实现了该接口的实现类的postProce-ssBeforeInstantiation方法,入参为前面解析好的BeanClass和beanName,如果有某一个实现类实现的该方法返回了数据,则直接结束循环,当前Bean的整个实例化过程就结束了。Bean中所有的依赖项、生命周期相关的方法都不会再被处理,因此,很少会有处理器在该方法中返回数据。

// AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
   Object bean = null;
   if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
      // Make sure bean class is actually resolved at this point.
      if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
         Class<?> targetType = determineTargetType(beanName, mbd);
         if (targetType != null) {
            bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
            if (bean != null) {
               bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
            }
         }
      }
      mbd.beforeInstantiationResolved = (bean != null);
   }
   return bean;
}

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
}

总结

Spring中的Bean是可以绕过IoC容器的Bean生命周期管理的,只需要实现InstantiationAwareBeanPostProcessor接口并重写其postProcessBeforeInstantiation方法来对指定beanClass进行创建,从而绕过IoC容器的生命周期管理。

但请慎用该手段,因为通过这种方式返回的Bean不仅其生命周期不受IoC容器管理,并且其依赖也不会被IoC容器所处理。如果其处于切点表达式的指定范围内,那么也不会被进行增强(动态代理/字节码增强),其方法上@Transactional注解将失去作用等等。

慎用!慎用!慎用!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值