当前时讯:【Spring源码】- 05 扩展点之BeanPostProcessor
类结构
BeanPostProcessor
和BeanFactoryPostProcessor
是Spring
中两个最重要的扩展的。如果说BeanFactoryPostProcessor
是面向IoC
进行扩展,BeanPostProcessor
就是面向Bean
进行扩展。
(资料图)
从上面类结构图可以看出,BeanPostProcessor
是一个顶层接口,下面有衍生出几个接口,实现对Bean
创建、初始化等各个阶段进行更细化的扩展,所以BeanPostProcessor
要比BeanFactoryPostProcessor
复杂一些,可以实现更多扩展场景。
注册顺序
BeanPostProcessor
被注册到IoC
中才能起作用,在refresh()
方法中registerBeanPostProcessors(beanFactory);
这一语句完成BeanPostProcessor
的注册工作,注册使用:addBeanPostProcessor(BeanPostProcessor beanPostProcessor)
方法完成。
注册BeanPostProcessor
也涉及到先后顺序关系,大致逻辑总结如下:
1、获取实现PriorityOrdered接口的BeanPostProcessor,然后通过getBean()方法实例化,排序后注册到容器中;2、获取实现Ordered接口的BeanPostProcessor,然后通过getBean()方法实例化,排序后注册到容器中;3、获取常规没有实现PriorityOrdered和Ordered接口BeanPostProcessor,然后通过getBean()方法实例化,注册到容器中;4、上述步骤中MergedBeanDefinitionPostProcessor类型会单独存储到internalPostProcessors集合中,排序后保证放到末尾5、最后移除ApplicationListenerDetector重新追加到最末尾
上面只是BeanPostProcessor
注册先后顺序关系,并不会涉及到BeanPostProcessor
的执行,由于BeanPostProcessor
扩展出几个子类,下面我们来分析下每个子类的执行时机。
BeanPostProcessor
执行时机
接口定义见下:
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; }}
之前分析IoC
容器启动流程时,介绍过initializeBean()
方法完成Bean
的init-method
初始化工作,BeanPostProcessor
就是在init-method
执行前后进行扩展。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { //触发BeanPostProcessor#postProcessBeforeInitialization()方法执行 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } //执行init-method方法 invokeInitMethods(beanName, wrappedBean, mbd); if (mbd == null || !mbd.isSynthetic()) { //触发BeanPostProcessor#postProcessAfterInitialization()方法执行 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean;}
再来看下这两个方法的调用逻辑:
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } result = current; } return result;}
如果有postProcessBeforeInitialization()
方法返回null
,则表示该扩展点提前结束,不再需要继续执行后续BeanPostProcessor
的postProcessBeforeInitialization
方法。
再来看下postProcessAfterInitialization()
方法执行逻辑是一样的:
@Override public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor processor : getBeanPostProcessors()) { Object current = processor.postProcessAfterInitialization(result, beanName); if (current == null) { return result; } result = current; } return result; }
使用场景
invokeInitMethods(beanName, wrappedBean, mbd);
方法执行Bean
的init-method
方法进行初始化,进入这个方法可以发现,这里只会执行实现InitializingBean
和@Bean(initMethod="xxx")
这两种方式设置的init-method
方法,我们平时使用很多的@PostConstruct
注解方式,其实是通过InitDestroyAnnotationBeanPostProcessor
这个扩展类实现:
InitDestroyAnnotationBeanPostProcessor
类实现了DestructionAwareBeanPostProcessor
和MergedBeanDefinitionPostProcessor
这两个接口,间接方式继承BeanPostProcessor
。InitDestroyAnnotationBeanPostProcessor
就是在postProcessBeforeInitialization()
方法中完成了对@PostConstruct
注解方法的调用,所以其执行优先级比InitializingBean
和@Bean(initMethod="xxx")
这两种方式更加靠前。
如果你需要在init-method
等Bean
的初始化执行前后进行扩展,可以使用此接口实现。比如:判断Bean
是否是线程池类,如果是则统一设置管理的线程名前缀:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof ThreadPoolTaskExecutor) { ((ThreadPoolTaskExecutor) bean).setThreadNamePrefix("Post-"); } return bean;}
还比如ApplicationListenerDetector
在postProcessAfterInitialization()
方法中实现将ApplicationListener
类型的单例Bean
注册到事件多播器上,实现对事件的监听:
public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof ApplicationListener) { Boolean flag = this.singletonNames.get(beanName); if (Boolean.TRUE.equals(flag)) { // 如果当前 ApplicationListener bean scope 是 singleton 单例模式,则将它注册到应用的事件多播器上 this.applicationContext.addApplicationListener((ApplicationListener>) bean); } else if (Boolean.FALSE.equals(flag)) { // 如果ApplicationListener bean scope 不是 singleton 单例模式,则尝试输出警告日志,说明情况,并移除 //所以ApplicationListener类型的只能是单例模式才会起作用 this.singletonNames.remove(beanName); } } return bean;}
还比如ApplicationContextAwareProcessor
这个就是在postProcessBeforeInitialization()
方法中实现如ApplicationContextAware
、EnvironmentAware
等*Aware
接口注入功能。实现原理非常简单,就是判断Bean
是否实现接口,然后通过setter
方式注入即可:
private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}
InstantiationAwareBeanPostProcessor
前面分析BeanPostProcessor
接口是在Bean的init-method
方法执行前后进行扩展,其子接口InstantiationAwareBeanPostProcessor
则可以在Bean
的创建前后进行扩展,所以此扩展比BeanPostProcessor
扩展更靠前。
接口定义见下:
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { //Bean创建之前回调该方法,beanClass就是将要被创建的Bean对应的Class信息 @Nullable default Object postProcessBeforeInstantiation(Class> beanClass, String beanName) throws BeansException { return null; } //Bean创建之后回调该方法,参数bean就是创建完成的Bean对象 default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { return true; } //postProcessProperties()方法在postProcessAfterInstantiation()方法之后紧挨着执行,其提供PropertyValues类型入参,所以在该方法中可以实现依赖操作 @Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { return null; } //这个方法标注@Deprecated已经被废弃了,被postProcessProperties()方法取代了 @Deprecated @Nullable default PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { return pvs; }}
createBean()
方法中Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
这条语句中会触发对postProcessBeforeInstantiation()
方法的执行。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { Object bean = resolveBeforeInstantiation(beanName, mbdToUse);//触发对postProcessBeforeInstantiation()方法的执行 if (bean != null) { return bean; } ... Object beanInstance = doCreateBean(beanName, mbdToUse, args);//创建Bean实例(一般真正创建Bean的方法) ...}
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()
方法有个重要特性:如果该方法返回非null
结果,则表示Bean
提前创建完成,同时也会忽略掉后续的依赖注入、init-method
初始化等步骤执行,最后只需要执行下BeanPostProcessor#postProcessAfterInitialization
这个方法则整个Bean
的创建流程就全部完成。
总结:在创建对象之前调用了postProcessBeforeInstantiation
方法可以实现给扩展点一次创建代理的机会,如果代理对象返回不为空则不再继续常规方式创建Bean
。
我们再来看下InstantiationAwareBeanPostProcessor
接口中定义的另两个方法执行时机,Bean
创建完成后会执行populateBean()
进行依赖注入,它们就是在这个方法中进行触发回调,pupulateBean()
方法大致见下:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { //执行InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation方法回调 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } } // 注解注入:后置处理器ibp#postProcessProperties,大名鼎鼎的@Autowired就是在这处理的。 PropertyDescriptor[] filteredPds = null; if (hasInstAwareBpps) { //执行InstantiationAwareBeanPostProcessor#postProcessProperties方法回调 for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { //获取出对象的所有set get方法,现在是有一个 getClass()方法,因为继承了Object, 没什么其他卵用 filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } //postProcessPropertyValues方法已废弃,被postProcessProperties替代 pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } } if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); }}
上面代码翻译下大概就是:先执行InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
方法回调,然后再去执行InstantiationAwareBeanPostProcessor#postProcessProperties
,最后再去执行applyPropertyValues()
完成PropertyValue
方式的依赖注入。这里有个大名鼎鼎的@Autowired
、@Value
方式的依赖注入,就是借助于InstantiationAwareBeanPostProcessor#postProcessProperties()
方法实现,这个实现类就是:AutowiredAnnotationBeanPostProcessor
,简单看下依赖注入逻辑:
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { /** * 从缓存中找到此类的@Autowired、@Value注解元数据,尝试注入 * InjectionMetadata,持有待注入的元数据信息,执行inject()方法,开始注入属性或方法参数。 */ InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { //为beanName填充上属性bean metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs;}
这里有意义的代码就两行:
1、InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
获取Bean
中需要依赖注入注入的元素,封装成一个InjectionMetadata
对象,该对象有两个重要属性:
targetClass
指定目标对象的Class
;Collection injectedElements
:目标对象中每个需要依赖注入的元素都会封装成一个InjectedElement
,然后存储到该集合中。根据@Autowired
/@Value
注解到字段上还是方法上,InjectedElement
又可以分为两类:AutowiredFieldElement
和AutowiredMethodElement
。2、metadata.inject(bean, beanName, pvs);
:这个方法内部就是循环,对每个依赖元素InjectedElement
调用inject()方法
if (!elementsToIterate.isEmpty()) { for (InjectedElement element : elementsToIterate) { if (logger.isTraceEnabled()) { logger.trace("Processing injected element of bean "" + beanName + "": " + element); } element.inject(target, beanName, pvs); }}
比如我们一般将@Autowired
标注到字段上,则这里会触发AutowiredFieldElement#inject()
方法执行:
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member;//依赖注入字段 Object value;//存储需要注入的值 if (this.cached) {//如果已被缓存,则直接先从缓存中获取依赖注入值 value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else {//还未被缓存过 //1.DependencyDescriptor:用于对该依赖注入描述信息 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { /* 2.查找依赖注入的值 比如: @Autowired private TestService03 testService03; 这个value就是从IoC容器中查找到的TestService03对象 还比如:@Value("${spring.name}"),这个value就是从Spring上下文环境变量中解析出的spring.name变量值 */ value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } //3.下面synchronized块主要实现缓存功能,已被解析过的包装成ShortcutDependencyDescriptor类型,上面resolvedCachedArgument对这种类型会特殊处理 synchronized (this) { if (!this.cached) { if (value != null || this.required) { this.cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } else { this.cachedFieldValue = null; } this.cached = true; } } } //4.查找到的依赖值不为null,则使用反射方式注入,因为是通过反射方式,所以@Autowired、@Value是不需要setter/getter方法也可以注入 if (value != null) { //通过反射方式将查找到的需要依赖注入的值设置到对象实例中 ReflectionUtils.makeAccessible(field); field.set(bean, value); }}
SmartInstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor
还有个子接口:SmartInstantiationAwareBeanPostProcessor
,其定义如下:
public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor { //推断类型 @Nullable default Class> predictBeanType(Class> beanClass, String beanName) throws BeansException { return null; } //根据一定规则推断出Bean中优选的构造方法 @Nullable default Constructor>[] determineCandidateConstructors(Class> beanClass, String beanName) throws BeansException { return null; } default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException { return bean; }}
SmartInstantiationAwareBeanPostProcessor
接口有三个方法,在实例创建前智能判断实例类型、智能判断构造函数、提起获取暴露Bean
引用,该接口主要是spring
框架内部使用,开发时很少去扩展该接口。
这里主要注意第三个方法:getEarlyBeanReference()
,这个扩展方法主要与Spring
中的循环依赖有关系。前面分析IoC
容器启动时分析过:为了解决Spring
中的循环依赖问题,在doCreateBean()
方法内部,会将刚创建还未来得及进行依赖注入和初始化的半成品Bean
提前暴露出去,addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
,注意这里不是直接将Bean
暴露出去,而是通过() -> getEarlyBeanReference(beanName, mbd, bean)
这句将Bean
包装成ObjectFactory
类型再暴露出去。
这里的一个核心就是:为什么不直接暴露Bean
,而是将Bean
包装成ObjectFactory
再去暴露?将Bean
包装成ObjectFactory
再去暴露,调用getObject()
方法时会触发SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference
方法回调。
分析到这里,还不够完善,因为你可能会问:那这个方法回调又可以给我们解决什么问题呢?
可以利用Spring AOP
原理来回答这个问题,Spring AOP
主要基于AnnotationAwareAspectJAutoProxyCreator
这个类实现,这个类实现了BeanPostProcessor
接口,在postProcessAfterInitialization()
方法中对创建完成的Bean
采用动态代理方式将增强逻辑织入进去。
如果存在这样情况:A
依赖B
,B
同时依赖A
,这就是所说的Spring
循环依赖,但是如果我们对A
采用了AOP
增强,这个过程会是怎样情况呢?
init-method
初始化方法后,postProcessAfterInitialization()
执行时会给A通过动态代理方式织入增强逻辑;这时,步骤3中给B注入的是A的原生对象,但是步骤6会给A创建一个代理对象,但是B中这时还是原生对象没法改变,这就会导致有的依赖注入的是原生对象,有的依赖注入的是代理对象,会出现错乱问题。如何解决呢?这个就是SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference
这个扩展点作用。
A对象提前暴露时,利用ObjectFactory包装了一层,B对象在进行依赖注入时获取到对象A时,不是直接返回A,而是触发getEarlyBeanReference()
方法执行,AnnotationAwareAspectJAutoProxyCreator
类在getEarlyBeanReference()
方法中实现判断A需要做动态代理,则对A进行动态代理后返回,这时B中依赖注入的就不是原生对象。
总结:SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()
方法是在循环依赖场景下,对提前暴露的Bean
可以通过该扩展点进行处理。只有因为存在循环依赖,才会导致需要需要获取那些提前暴露的Bean
时才会触发该扩展点,所以,理解这个扩展点关键在于你对Spring
循环依赖的理解。
DestructionAwareBeanPostProcessor
DestructionAwareBeanPostProcessor
是BeanPostProcessor
子接口,其定义如下:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor { //Bean销毁前回调方法 void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; //可以根据Bean进行过滤,哪些Bean需要用到当前这个回调 default boolean requiresDestruction(Object bean) { return true; }}
从名称就可以看出,该扩展主要用于Bean
销毁之前,回调时机在:DisposableBeanAdapter#destroy()
public void destroy() { //调用DestructionAwareBeanPostProcessor#postProcessBeforeDestruction,Bean销毁之前回调接口 if (!CollectionUtils.isEmpty(this.beanPostProcessors)) { for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) { processor.postProcessBeforeDestruction(this.bean, this.beanName); } } ... ((DisposableBean) this.bean).destroy();//调用DisposableBean.destroy() ... }
DestructionAwareBeanPostProcessor
接口有个实现类InitDestroyAnnotationBeanPostProcessor
,实现对@PreDestroy
注解支持。该扩展接口本身是比较简单的,后续分析Bean
生命周期destroy
流程整体梳理。
MergedBeanDefinitionPostProcessor
MergedBeanDefinitionPostProcessor
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor { void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName); //Spring5.1新增接口,实现BeanDefinition重置通知,一般该方法实现重置前清理metadata等元数据缓存 default void resetBeanDefinition(String beanName) { }}
我们主要看下postProcessMergedBeanDefinition()
方法调用时机:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { //1.创建对象 //2.执行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition回调方法 synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } //3.提前暴露Bean //4.populateBean(beanName, mbd, instanceWrapper); //5.exposedObject = initializeBean(beanName, exposedObject, mbd);}
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
发生在Bean
刚创建完成,Bean
还未提前暴露之前。MergedBeanDefinitionPostProcessor
在Spring
中有很多的应用,比如:AutowiredAnnotationBeanPostProcessor
、CommonAnnotationBeanPostProcessor
、InitDestroyAnnotationBeanPostProcessor
等。这个扩展的一般套路是和其它扩展点一起使用,其起到一个帮手角色,postProcessMergedBeanDefinition
将需要处理的注解信息解析成元数据信息缓存起来,其它扩展点就可以从缓存中获取需要处理的注解信息进行处理。有关这扩展点更多的情况会在后续案例分析中再详细分析。
总结
BeanFactoryPostProcessor
和BeanPostProcessor
是Spring
提供的两个最核心、最基础的扩展方式:一个面向IoC
进行扩展,另一个面向Bean
的创建流程进行各种扩展。BeanPostProcessor
及其子类实现了对Bean
创建过程中的各种扩展:Bean
创建前后、Bean
初始化前后、获取提前暴露对象前等等这些。Spring中大量注解简化了我们使用框架的复杂性,而这些注解很大一部分就是基于这些扩展进行处理,学习这些扩展点可以帮助我们更好的熟悉Spring
的运行机理,同时可以在开发中帮助我们灵活的实现各种功能扩展。
标签:

当前时讯:【Spring源码】- 05 扩展点之BeanPostProcessor
2023-03-29

租客怨,房东愁,自如何以上市?|天天快讯
2023-03-29

天天热门:流感“神药”缺货之谜:集采价买不到,加钱又有了?
2023-03-29

华宝新能(301327):3月28日北向资金增持4.24万股_消息
2023-03-29

火车线路图查询全国(火车线路图) 信息
2023-03-28

日本北海道地区发生6.1级地震 震源深度30千米
2023-03-28

世界快资讯丨都体:尤文将与曼城国米拜仁竞争斯卡尔维尼,斯莫林是低成本备选
2023-03-28

微头条丨本来生活与宁夏西鲜记科技升级合作
2023-03-28

头条焦点:博鳌报告:预计2023年亚洲经济体GDP增速为4.5%
2023-03-28

最新资讯:2023年佛山医保住院报销比例
2023-03-28
租客怨,房东愁,自如何以上市?|天天快讯
天天热门:流感“神药”缺货之谜:集采价买不到,加钱又有了?
华宝新能(301327):3月28日北向资金增持4.24万股_消息
火车线路图查询全国(火车线路图) 信息
日本北海道地区发生6.1级地震 震源深度30千米
世界快资讯丨都体:尤文将与曼城国米拜仁竞争斯卡尔维尼,斯莫林是低成本备选
微头条丨本来生活与宁夏西鲜记科技升级合作
头条焦点:博鳌报告:预计2023年亚洲经济体GDP增速为4.5%
最新资讯:2023年佛山医保住院报销比例
每日速递:中国新能源汽车多项指标性能明显提高 低温续驶里程衰减率逐年降低
探案汽车制造流程的“第二现场”
正确认识政府采购质疑投诉问题
热点聚焦:社保手机上怎么缴费?社保缴费后怎么查询记录?
《人民公安报》报道许昌警方维护创新创业良好治安环境
GL8跌落神坛,别克品牌的最后一块高地正在失守
全球报道:苹果iOS16.4正式版为iPhone新增支持中国广电5G网络
关键指标领先,长沙工业用实力说话_每日简讯
今日快讯:丽翔教育(LXEH.US)3月27日收盘报0.75美元/股,跌10.55%
三峡旅游(002627):第五届第二十九次董事会会议决议,审议《关于召开2023年第一次临时股东大会的议案》 即时焦点
复星医药(02196.HK):曹根兴辞任公司监事-环球微头条
全球资讯:宁夏贺兰:倾心帮带乡土人才 大力发展特色产业
3月27日国产硼酸价格持稳|速递
这个口红最近真火,与兰蔻196难辨真假,难怪迅速蹿红,质感爱了
四川长虹(600839)龙虎榜数据(03-27)
docker 网络知识
环球视点!值得买3月27日快速上涨
全球新消息丨构建中国云生态|华云数据携手才云科技完成产品兼容互认证 推出智能容器云平台联合解决方案
宏观担忧缓解,金价四周来首次下跌0327 环球观点
全球观点:农业银行普惠金融领域贷款余额突破3万亿元


- 360手机抢票神器抢票图文步骤
- 当前报道:暗黑2圣骑士技能加点攻略(暗黑2圣骑士技能加点)
- 云南祥云:集团化办学打造优质均衡共同体-环球动态
- 聚焦:洛阳牡丹节旅游攻略_关于洛阳牡丹节旅游
- 全球速讯:叔圈西服背后藏着哪些秘密?黑化的高启强为啥偏爱戗驳领西服?
- 【天天时快讯】东方碳素北交所IPO过会 拟募资5.05亿元
- 今日看点:金价一度逼近历史最高
- 长期用海藻面膜好吗
- 观天下!A股普涨 300464权重股略弱
- 蜡笔小新动画(蜡笔小新有几部动画片?)|全球热议
- 李若彤多大了真实年龄_李若彤年龄多大了?-播报
- 全球新资讯:聚焦超大城市治理热点难点“2022延吉·新思杯”青年创新创业大赛总决赛圆满落幕
- 世界热头条丨12月5号是什么日子
- 春风吹,纸鸢飞!
- 中国外贸开局平稳(锐财经)
- 嘀米汽车轮胎充气泵BPMI01E上架众筹 超级快充 汽车补气只需60秒 全球即时看
- 近几年药学相关硕士就业前景如何
- 环球播报:我国锂电年总产值首次突破万亿元 应用场景加速融入生产生活
- 今天,请稍“熄”!爱地球不止于一小时
- 环球观天下!人头乳瘤病毒核酸检测是检查什么_人乳头瘤病毒核酸分型检测准确吗
- 睡吧睡吧我亲爱的宝贝是什么歌名|环球时快讯
- 每日动态!四川省级“天府名厨”“天府名店”名单正式发布
- 世界今亮点!股票行情快报:安达维尔(300719)3月24日主力资金净卖出8.71万元
- 貂蝉带什么召唤师技能更合适(貂蝉带什么召唤师技能)_天天热闻
- 世界微动态丨紫金矿业(02899.HK)发布年度业绩,归母净利润200.42亿元 同比增长27.88%
- 光大银行:2022年归母净利润448.07亿元,同比增长3.23% 世界观热点
- 世界快讯:金茂服务2022年实现收入24.36亿元 同比增加60.7%
- 资讯:故障指示器是什么原理
- k歌之王粤语歌词音译_k歌之王粤语歌词谐音?
- 【天天热闻】恭喜!覃海洋50米蛙泳游出超亚洲纪录成绩
- 首架在我国完成总装的空客A321飞机正式交付 每日消息
- 重点聚焦!迈阿密站-蒂姆被横扫一轮游 遭遇巡回赛5连败
- 捷强装备:3月23日获融资买入680.62万元,占当日流入资金比例10.83%
- 牧云笙和穆如寒江结局是悲剧吗 环球播报
- QS世界大学学科排名 台湾地区135项名次下滑
- 伦敦商学院教授复盘瑞信收购案:担心应急可转债市场萎缩,银行股估值恐持续下降 快消息
- 罢工潮席卷欧洲
- 三个火下面一个木子_上面三个火下面一个木 世界快资讯
- 补壹刀:“生死时刻”!这个神秘的新加坡人站到了前台|世界报资讯
- 珠心算的好处
- 天天资讯:单边公积金什么意思_双边公积金什么意思
- 邦达亚洲:美联储加息周期或接近尾声 黄金大幅攀升
- 专利年费查询平台_专利年费查询 天天快看
- 外交部:美国硅谷银行事件已引发全球金融市场动荡 希望美方增强透明度
- 环球速讯:杜锋做出重大决定,季后赛还没到,首先提拔1人
- 好医保少儿长期医疗0免赔版可靠吗?不清楚这2点需迟点入手-每日看点
- 朝组词有哪些 快讯
- 天天精选!23悦达SCP003今日发布发行公告
- 商标在申请中可以办理转让吗?签定商标转让协议的注意事项有哪些?-全球微资讯
- 全球热议:彩铃网盘