序
今天Code Review的时候 看到其他项目 static 方法需要使用 bean的实体方法,是从网上copy的 大概是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class SpringUtils implements ApplicationListener { private static ApplicationContext applicationContext; public static ApplicationContext getApplicationContext() { return applicationContext; } public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ContextRefreshedEvent) { ContextRefreshedEvent e = (ContextRefreshedEvent)event; if (e.getApplicationContext().getParent() == null ) { applicationContext = e.getApplicationContext(); } } } public static T getBean(Class clazz){ return getApplicationContext().getBean(clazz); } } |
虽然现在 代码运行没有毛病,但是 我们有公共类SpringUtils 实现了相同功能,其实不应该 重复在业务系统自己写。
但是这个时候 人家可能会问 我这么写和 用公共类 的效果不是一样么? 都一样
区别
- 一方面是 代码规范,公共功能都有现成的,不需要自己开发,节省错误的概率 和 提升效率
开发的时候 有人会说 我哪知道有哪些功能是现在有的,关于这个 我会提供一个搜索的网页,方便进行搜索,如果搜索不到就是没有,你感觉是公共功能,可以提交 让别人使用。
你既然给人家推荐用公共类,那你肯定要说清楚 公共类的好处,才能让人家信服。你不能说效果都一样,就是用我的吧。。。
讲道理
你这种写法是 可能出错的
定义一个 Service
1 2 3 | @Service public class TestService{ } |
定义 一个初始化方法
1 2 3 4 5 6 7 | @Component public class TestInit{ @PostConstruct public void init(){ SpringUtils.getBean(TestService. class ); } } |
报错信息
Caused by: java.lang.NullPointerException: null
at com.example.demo.utils.SpringUtils.getBean(SpringUtils.java:25) ~[classes/:na]
at com.example.demo.service.TestInit.init(TestInit.java:12) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_322]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_322]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_322]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_322]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:363) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:307) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:136) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
18 common frames omitted
原因
在spring服务启动过程中,spring会先去注册所有的bean,在注册过程中,如果发现该bean中包涵了被@PostConstruct注释的函数,那么就会先去执行这个函数,然后再继续注册其他未注册的bean。
但是在springUtils中,无论是继承ApplicationListener,还是继承自ApplicationContextAware,都只有在bean初始化完成后,才会执行注入applicationContext。
解决
可以直接拿着用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | @Component public class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware { private static ConfigurableListableBeanFactory beanFactory; private static ApplicationContext applicationContext; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtils.beanFactory = beanFactory; } @Override public void setApplicationContext(ApplicationContext applicationContext) { SpringUtils.applicationContext = applicationContext; } /** * 获取{@link ApplicationContext} * * @return {@link ApplicationContext} */ public ApplicationContext getApplicationContext() { return applicationContext; } public ListableBeanFactory getBeanFactory() { return null == beanFactory ? applicationContext : beanFactory; } public ConfigurableListableBeanFactory getConfigurableBeanFactory() throws UtilException { final ConfigurableListableBeanFactory factory; if ( null != beanFactory) { factory = beanFactory; } else if (applicationContext instanceof ConfigurableApplicationContext) { factory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); } else { throw new UtilException( "No ConfigurableListableBeanFactory from context!" ); } return factory; } @SuppressWarnings ( "unchecked" ) public T getBean(String name) { return (T) getBeanFactory().getBean(name); } /** * 通过class获取Bean * * @param Bean类型 * @param clazz Bean类 * @return Bean对象 */ public T getBean(Class clazz) { return getBeanFactory().getBean(clazz); } /** * 通过name,以及Clazz返回指定的Bean * * @param bean类型 * @param name Bean名称 * @param clazz bean类型 * @return Bean对象 */ public T getBean(String name, Class clazz) { return getBeanFactory().getBean(name, clazz); } /** * 从spring容器中获取相关降级的bean * * @param fallbackClass 降级的Class类对象 * @param paramValues 参数值 * @return 相关降级的bean */ public Object getBean(Class> fallbackClass, Object[] paramValues) { return getBeanFactory().getBean(fallbackClass, paramValues); } /** * 通过类型参考返回带泛型参数的Bean * * @param reference 类型参考,用于持有转换后的泛型类型 * @param Bean类型 * @return 带泛型参数的Bean * @since 5.4.0 */ @SuppressWarnings ( "unchecked" ) public T getBean(TypeReference reference) { final ParameterizedType parameterizedType = (ParameterizedType) reference.getType(); final Class rawType = (Class) parameterizedType.getRawType(); final Class>[] genericTypes = Arrays.stream(parameterizedType.getActualTypeArguments()).map(type -> (Class>) type).toArray(Class[]:: new ); final String[] beanNames = getBeanFactory().getBeanNamesForType(ResolvableType.forClassWithGenerics(rawType, genericTypes)); return getBean(beanNames[ 0 ], rawType); } /** * 获取指定类型对应的所有Bean,包括子类 * * @param Bean类型 * @param type 类、接口,null表示获取所有bean * @return 类型对应的bean,key是bean注册的name,value是Bean * @since 5.3.3 */ public Map getBeansOfType(Class type) { return getBeanFactory().getBeansOfType(type); } /** * 获取指定类型对应的Bean名称,包括子类 * * @param type 类、接口,null表示获取所有bean名称 * @return bean名称 * @since 5.3.3 */ public String[] getBeanNamesForType(Class> type) { return getBeanFactory().getBeanNamesForType(type); } /** * 获取配置文件配置项的值 * * @param key 配置项key * @return 属性值 * @since 5.3.3 */ public String getProperty(String key) { if ( null == applicationContext) { return null ; } return applicationContext.getEnvironment().getProperty(key); } /** * 获取应用程序名称 * * @return 应用程序名称 * @since 5.7.12 */ public String getApplicationName() { return getProperty( "spring.application.name" ); } /** * 获取当前的环境配置,无配置返回null * * @return 当前的环境配置 * @since 5.3.3 */ public static String[] getActiveProfiles() { if ( null == applicationContext) { return null ; } return applicationContext.getEnvironment().getActiveProfiles(); } /** * 获取当前的环境配置,当有多个环境配置时,只获取第一个 * * @return 当前的环境配置 * @since 5.3.3 */ public String getActiveProfile() { final String[] activeProfiles = getActiveProfiles(); return ArrayUtil.isNotEmpty(activeProfiles) ? activeProfiles[ 0 ] : null ; } /** * 动态向Spring注册Bean * <p> * 由{@link org.springframework.beans.factory.BeanFactory} 实现,通过工具开放API * </p> <p> * 更新: shadow 2021-07-29 17:20:44 增加自动注入,修复注册bean无法反向注入的问题 * * @param Bean类型 * @param beanName 名称 * @param bean bean * @author shadow * @since 5.4.2 */ public void registerBean(String beanName, T bean) { final ConfigurableListableBeanFactory factory = getConfigurableBeanFactory(); factory.autowireBean(bean); factory.registerSingleton(beanName, bean); } /** * 注销bean * </p><p> * 将Spring中的bean注销,请谨慎使用 * * @param beanName bean名称 * @author shadow * @since 5.7.7 */ public void unregisterBean(String beanName) { final ConfigurableListableBeanFactory factory = getConfigurableBeanFactory(); if (factory instanceof DefaultSingletonBeanRegistry) { DefaultSingletonBeanRegistry registry = (DefaultSingletonBeanRegistry) factory; registry.destroySingleton(beanName); } else { throw new UtilException( "Can not unregister bean, the factory is not a DefaultSingletonBeanRegistry!" ); } } /** * 发布事件 * * @param event the event to publish * @since 5.7.12 */ public void publishEvent(ApplicationEvent event) { if ( null != applicationContext) { applicationContext.publishEvent(event); } } } </p><p></p> |
BeanFactoryPostProcessor 为什么能解决这个问题?
1 2 3 4 | @FunctionalInterface public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException; } |
从注释可以看出来:
- BeanFactoryPostProcessor接口允许修改上下文中Bean的定义(definitions),可以调整Bean的属性
- 上下文可以自动检测BeanFactoryPostProcessor,并且在Bean实例化之前调用
源码分析
BeanFactoryPostProcessor是在Bean被实例化之前对Bean的定义信息进行修改,那么Spring是如何实现对自定义BeanFactoryPostProcessor的调用的,下面通过源码来看一下,首先还是从refresh()方法入手,在refresh()方法中会调用invokeBeanFactoryPostProcessors(beanFactory);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { //主要是这一行 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor( new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader( new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } } public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) { /**因代码太长,省略了***/ //这里从beanFacoty中通过BeanFactoryPostProcessor类型来获取Bean名称,就可以拿到我们自定义的BeanFactoryPostProcessor String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor. class , true , false ); List priorityOrderedPostProcessors = new ArrayList(); List orderedPostProcessorNames = new ArrayList(); List nonOrderedPostProcessorNames = new ArrayList(); for (String ppName : postProcessorNames) { if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } //这里是优先级的处理,如果我们有多个自定义的BeanFactoryPostProcessor,可以通过优先级来定义执行顺序 else if (beanFactory.isTypeMatch(ppName, PriorityOrdered. class )) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor. class )); } else if (beanFactory.isTypeMatch(ppName, Ordered. class )) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. //这里先处理实现了PriorityOrdered接口的BeanFactoryPostProcessor,也就是定义了优先级的先处理 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. //再处理实现了Ordered接口的BeanFactoryPostProcessor List orderedPostProcessors = new ArrayList(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor. class )); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. List nonOrderedPostProcessors = new ArrayList(); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor. class )); } //这里才到了处理普通的自定义BeanFactoryPostProcessors invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); // Clear cached merged bean definitions since the post-processors might have // modified the original metadata, e.g. replacing placeholders in values... beanFactory.clearMetadataCache(); } private static void invokeBeanFactoryPostProcessors( Collection extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanFactory(beanFactory); } } |
invokeBeanFactoryPostProcessors()方法的逻辑很简单,就是去遍历容器中的BeanFactoryPostProcessor,然后调用postProcessBeanFactory()方法,这个方法就是我们自定义BeanFactoryPostProcessor时需要去实现的方法,至此整个流程就已经很清晰了
以上就是PostConstruct注解标记类ApplicationContext未加载空指针的详细内容,更多关于PostConstruct ApplicationContext的资料请关注IT俱乐部其它相关文章!