本文主要是介绍SpringBoot日常:Spring扩展接口之InitializingBean,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 简介
- 源码分析
- 应用场景
- 代码示例
- 运行示例
简介
这篇文章主要介绍了Spring中InitializingBean的使用详细解析,InitializingBean是Spring提供的拓展性接口,提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法,凡是继承该接口的类,在bean的属性初始化后都会执行该方法。
源码分析
我们大概看一下初始化涉及的源码部分,主要为这两个方法,
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
和#invokeInitMethods
/*** @return the initialized bean instance (potentially wrapped)* @see BeanNameAware* @see BeanClassLoaderAware* @see BeanFactoryAware* @see #applyBeanPostProcessorsBeforeInitialization* @see #invokeInitMethods* @see #applyBeanPostProcessorsAfterInitialization*/protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {//执行BeanPostProcessor接口实现类的postProcessBeforeInitialization方法wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {//如果bean实现了InitializingBean或者自定义了initMethod,//会在这里执行InitializingBean#afterPropertiesSet和initMethod方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {//执行BeanPostProcessor接口实现类的postProcessAfterInitialization方法wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {//判断bean是否实现了InitializingBeanboolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isTraceEnabled()) {logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {//如果实现了InitializingBean,真接调用afterPropertiesSet(),((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {//获取bean自定义的init-method方法String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {//如果自定义了init-method方法,在这里开始执行;invokeCustomInitMethod(beanName, bean, mbd);}}}
看完源码部分,我们可以很清楚地知道InitializingBean#afterPropertiesSet方法和init-method是什么时候用什么方式来调用的( 通过反射调用init-method
),且InitializingBean#afterPropertiesSet方法的执行时机要稍早于init-method。另外,如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法
应用场景
这个扩展点是比较有用的一个扩展点,可以用于
- 修改默认设置的属性
- 添加补充额外的属性值
- 或者针对关键属性做校验
- spring MVC内容有一个经典的实现场景,RequestMappingHandlerMapping完成URL与controller的映射工作
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {@Overridepublic void afterPropertiesSet() {initHandlerMethods();} protected void initHandlerMethods() {//循环所有的beanfor (String beanName : getCandidateBeanNames()) {//如果bean名字不是以scopedTarget.开头if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {processCandidateBean(beanName);}}//日志输出handlerMethodsInitialized(getHandlerMethods());}protected void processCandidateBean(String beanName) {Class<?> beanType = null;try {beanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}//他们是否是Handler(类上标注@Controller注解或者@RequestMapping注解)if (beanType != null && isHandler(beanType)) {//获取这个类上所有标注@RequestMapping的方法信息,以RequestMappingInfo形式把他们储存到MappingRegistry中detectHandlerMethods(beanName);}}
代码示例
完成一个rsa对象的初始化,方便该类方法调用使用
@Slf4j
@Configuration
public class ExtendInitializingBean implements InitializingBean {private RSA rsa;@Overridepublic void afterPropertiesSet() {String priv = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJzDhvCJBIIuZzNu\n" +"+dHWY5inSAN6d/yqWOTl/5rWofT2+m59qjKoFuJ9kkuYUCkIpoEtLhu5PfOAdR9R\n" +"bsVnfXThgwOQFHx1/v4URXwOBrBHRYhPy8fApJSfdBWgKMs9GZ5WbDWVkPm7xhvJ\n" +"t716Wtx/leCjvq87jWVg8oo83uKtAgMBAAECgYAW77bNInG3QxHUy9kf03XpY8Rc\n" +"xJeiBMyShSJjuyFMMFy45jMM9rIOe8qiu+DdTXI14UXnRtsNHHpGgEmBoYrl4IZ9\n" +"Wgbxn0fkrcHaw4F8GoAapyqAgNkyU3kAf8of6G+ZeMulcZtbb7NXVkwTaRHOkzBg\n" +"2a44HCSQ2n/fHPxfwwJBANFhUKWMOV3SqEN7RjsxWNAk8P25xHzIWq6KCyhOx5Vm\n" +"KLIttnYUiA3UA3q5RJK8Hqh0a2JGcg8O9HawOuMWAAsCQQC/qxNG08pX8dm5mh5B\n" +"9d/Wc09U9V7Xni9gqqS5adjxChm97t5h8k3wRxTqDWHCJyZTkezy7pmZvaFWqwLO\n" +"xkMnAkBLEbIBeNIEkoejkiovBNVL40LIJXeOKaNhmrq/W+dw6CzFHWCi21+gXZhV\n" +"wuEUHwB68yqhFJLGVV1OxIaIbpXbAkBBY0WiRiKjuhiDHzbvXchNSu1nmIYQnSCg\n" +"o9aqgpfGM6HwkAtB8v3v2PAjoQkWyXBj1ka14fx43J6sCI9ep3jFAkBDi3wnlIzc\n" +"LpJxumw84P8f3pVJ1xKx9tchAh1W+hhcaq+/S+u3rIJcXfXWLojUp7yMyKjzy2lU\n" +"PNC8Qke0R/qC";String pub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCcw4bwiQSCLmczbvnR1mOYp0gD\n" +"enf8qljk5f+a1qH09vpufaoyqBbifZJLmFApCKaBLS4buT3zgHUfUW7FZ3104YMD\n" +"kBR8df7+FEV8DgawR0WIT8vHwKSUn3QVoCjLPRmeVmw1lZD5u8Ybybe9elrcf5Xg\n" +"o76vO41lYPKKPN7irQIDAQAB";rsa = new RSA(priv, pub);log.info("afterPropertiesSet--Extend--run");}}
运行示例
这篇关于SpringBoot日常:Spring扩展接口之InitializingBean的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!