中国建筑业协会官方网站百度新闻
一、概述
Spring IOC容器的扩展点是指在IOC加载的过程中,如何对即将要创建的bean进行扩展。
二、扩展点
2.1、BeanDefinitionRegistryPostProcessor
2.1.1、概述
BeanDefinitionRegistryPostProcessor是bean定义的后置处理器,在BeanDefinition加载后,实例化bean之前,调用 invokeBeanFactoryPostProcessors时进行扩展,通过改变BeanDefinition的定义信息进行扩展,源码如下:
2.1.2、继承结构
2.1.3、案例
2.1.3.1、ATM
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:06* @Description:*/
@Slf4j
@Component(value = "atm")
public class ATM {public int withdrawMoney(int money) {log.info("取钱方法正在执行...");if (money == 100) {throw new RuntimeException("自定义的异常");}return money;}}
2.1.3.2、MySpringConfig
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:29* @Description:*/
@Configuration
@ComponentScan(basePackages = {"org.star"})
public class MySpringConfig {}
2.1.3.3、MyBeanDefinitionRegistryPostProcessor
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/25 17:38* @Description:*/
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {/*** 作用:动态注册BeanDefinition* 调用时机:IOC加载时注册BeanDefinition的时候会调用* @param registry the bean definition registry used by the application context* @throws BeansException*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {RootBeanDefinition definition = new RootBeanDefinition(ATM.class);// 设置ATM bean为多实例definition.setScope("prototype");registry.registerBeanDefinition("atm",definition);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {BeanDefinition beanDefinition = beanFactory.getBeanDefinition("atm");// 将atm设置为懒加载,这样在容器启动时将不会创建bean,只有在getBean时才会创建对象beanDefinition.setLazyInit(true);}
}
2.1.3.4、AopFullAnnotationMainApp
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);ATM atm1 = context.getBean("atm", ATM.class);ATM atm2 = context.getBean("atm", ATM.class);log.info("atm1:{},atm2:{},(atm1 == atm2):{}", atm1,atm2,(atm1 == atm2));}}
2.2、xxxAware接口
2.2.1、概述
Spring中存在着大量的xxxAware接口实现类,用于在bean初始化完成之前做一些前置操作,程序员可以自己实现xxxAware接口,重写里边的方法修改bean的定义信息,进行扩展。
2.2.2、继承结构
2.2.3、案例
2.2.3.1、ATM
同上。
2.2.3.2、MySpringConfig
同上。
2.2.3.3、MyApplicationContextAware
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/25 18:51* @Description:*/
@Component
public class MyApplicationContextAware implements ApplicationContextAware {public ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;AnnotationConfigApplicationContext context = (AnnotationConfigApplicationContext) applicationContext;ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();BeanDefinition beanDefinition = beanFactory.getBeanDefinition("atm");beanDefinition.setScope("prototype");}}
2.2.3.4、AopFullAnnotationMainApp
同上。
2.2.3、调用链路
2.2.4、注意事项
通过观察 2.1.3.4和 2.2.3.4的执行结果,不能发现xxxAware接口中配置的扩展覆盖了BeanDefinitionRegistryPostProcessor中的配置,说明xxxAware的优先级更高,这个也很好理解,对于同样的一个bean,后边的配置肯定会覆盖掉前边的配置。
2.3、生命周期回调时进行扩展
2.3.1、概述
bean的生命周期回调主要分为两种,一种是初始化进行调用,另外一种是销毁时进行调用,但是不管是初始化还是销毁,都对应着三种方式,即:
a、@PostConstruct @PreDestroy
b、实现接口 InitializingBean, DisposableBean的方式
c、@Bean(initMethod = "init",destroyMethod = "destroy")的方式
2.4、初始化后实例化前进行扩展
2.4.1、bean创建完成的标识
当循环完所有的DeanDefinition后,bean就创建完了。
2.4.2、大致流程
启动IOC容器 ===> refresh() ===>finishBeanFactoryInitialization(beanFactory)===>beanFactory.preInstantiateSingletons()
2.4.3、源码解析
#1、启动IOC容器
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);#2、refresh()
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {this();register(componentClasses);refresh();
}# 3、finishBeanFactoryInitialization(beanFactory)
@Override
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}
}# 4、beanFactory.preInstantiateSingletons();
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// Register a default embedded value resolver if no bean post-processor// (such as a PropertyPlaceholderConfigurer bean) registered any before:// at this point, primarily for resolution in annotation attribute values.if (!beanFactory.hasEmbeddedValueResolver()) {beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));}// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);for (String weaverAwareName : weaverAwareNames) {getBean(weaverAwareName);}// Stop using the temporary ClassLoader for type matching.beanFactory.setTempClassLoader(null);// Allow for caching all bean definition metadata, not expecting further changes.beanFactory.freezeConfiguration();// Instantiate all remaining (non-lazy-init) singletons.beanFactory.preInstantiateSingletons();
}# 5、beanFactory.preInstantiateSingletons();
@Override
public void preInstantiateSingletons() throws BeansException {if (logger.isTraceEnabled()) {logger.trace("Pre-instantiating singletons in " + this);}// Iterate over a copy to allow for init methods which in turn register new bean definitions.// While this may not be part of the regular factory bootstrap, it does otherwise work fine.List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {final FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {getBean(beanName);}}}// Trigger post-initialization callback for all applicable beans...for (String beanName : beanNames) {Object singletonInstance = getSingleton(beanName);if (singletonInstance instanceof SmartInitializingSingleton) {final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {smartSingleton.afterSingletonsInstantiated();}}}
}
2.4.4、通过监听器扩展
2.4.4.1、Computer
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 11:52* @Description:*/
@Getter
@Setter
@Accessors(chain = true)
@Component
public class Computer {/*** 电脑名称*/private String name;/*** 品牌*/private String brand;}
2.4.4.2、 MyContextRefreshedEvent
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 11:48* @Description: 监听器*/
@Component
public class MyContextRefreshedEvent {@EventListener(ContextRefreshedEvent.class)public void onContextRefreshedEvent(ContextRefreshedEvent event) {System.out.println(event);// bean初始化完成后做扩展,扩展代码写在这里ConfigurableApplicationContext context = (ConfigurableApplicationContext) event.getApplicationContext();DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();BeanDefinition beanDefinition = factory.getBeanDefinition("computer");beanDefinition.setScope("prototype");factory.registerBeanDefinition("computer",beanDefinition);System.out.println("all singleton beans loaded,onContextRefreshedEvent execute success!");}}
2.4.4.3、MySpringConfig(同上)
2.4.4.4、AopFullAnnotationMainApp
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);Computer computer1 = context.getBean(Computer.class);Computer computer2 = context.getBean(Computer.class);log.info("computer1:{},computer2:{},(computer1 == computer2 ?) : {}",computer1,computer2,(computer1 == computer2));}
}
2.4.5、通过接口扩展
2.4.5.1、Computer
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 11:52* @Description:*/
@Getter
@Setter
@Accessors(chain = true)
@Component
@Slf4j
public class Computer {/*** 电脑名称*/private String name;/*** 品牌*/private String brand;public void init() {Computer computer = new Computer().setName("OptiPlex7010MT Plus13").setBrand("戴尔");log.info("Computer's init was invoked! computer:{}", JSON.toJSONString(computer));}}
2.4.5.2、MySmartInitializingSingleton
/*** @Author : 一叶浮萍归大海* @Date: 2023/11/27 13:04* @Description:*/
@Component
public class MySmartInitializingSingleton implements SmartInitializingSingleton {@Resourceprivate ApplicationContext applicationContext;@Overridepublic void afterSingletonsInstantiated() {ConfigurableApplicationContext context = (ConfigurableApplicationContext) applicationContext;DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();BeanDefinition beanDefinition = factory.getBeanDefinition("computer");beanDefinition.setInitMethodName("init");beanDefinition.setScope("prototype");factory.registerBeanDefinition("computer",beanDefinition);System.out.println("all singleton beans loaded,afterSingletonsInstantiated execute success!");}
}