世界百事通!【Spring源码】- 10 Spring AOP核心API
概述
Spring的两大核心:IoC和AOP,IoC作为Spring的根基,通过大量的扩展点让系统轻而易举的就可以实现良好的扩展性,而AOP和IoC结合在一起,类似于发生强大化学反应一样,将Spring的功能性又提高了一个层次。Spring中也有大量使用AOP场景,比如@Configuration、数据库事务、mybatis mapper接口注入等等。
AOP全称Aspect Oriented Programming,即面向切面编程,其并非Spring独有,作为一种对OOP编程思想的补充,其也有自己的标准规范并有独立的组织进行维护。
根据织入时机的不同,AOP又可以分为三类:
(资料图)
ApectJ主要采用的就是编译时织入方式,这种一般使用特定的编译器方式实现;类加载时织入:这种一般都是依赖JVM Instruments技术实现,Spring中也有对这种技术支持,具体可以了解下LoadTimeWeaver;动态织入:动态代理方式实现AOP就是动态织入场景,Spring中实现AOP最主要方式,根据动态代理方式不同,又可以分为:JDK动态代理或CGLIB动态代理。AOP标准规范是由独立的组织机构进行维护,其涉及到的核心概念主要如下:
JoinPoint):程序运行中的某个阶段点,比如方法的调用、异常的抛出、类初始化和对象实例化等。连接点是AOP的核心概念,并且定义了在应用程序中可以使用AOP插入其它逻辑的点;切点(Pointcut):切点是基于规则定义如何查找连接点,其可以看成包含一系列连接点的组合,Spring中对应的是Pointcut接口,定义了哪些类的哪些方法需要织入增强;通知(Advice):在连接点处需要织入的增强代码逻辑封装;切面(Aspect):切面是Advice和Pointcut组合,对应Spring中Advisor;织入(Weaving):织入是在适当的位置将切面插入到应用程序代码中的过程,就是上面说的编译时织入、类加载时织入和动态织入;目标对象(target):AOP代理增强的原生对象;基础API
Spring AOP很多人不能很好的理解、使用,一方面是因为AOP涉及的概念可能比较抽象,不容易理解;另外一方面你对Spring AOP涉及到的一些基础API不熟悉。下面我们就对Spring AOP中最核心的一些API,由底向上,由基础到高级方式一步步分析。
Enhancer
Spring AOP主要使用的是动态代理方式实现,动态代理实现主要包括两种:jdk动态代理和cglib动态代理。jdk动态代理方式比较熟悉,下面就来看下cglib动态代理如何实现。
Spring中提供了一个工具类:Enhancer,Spring中主要就是利用该工具类创建cglib动态代理。下面我们通过一个案例看下其基本使用:
1、创建Callback回调接口类,该接口中就可以实现增强逻辑:
public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { try { before(method);//前置通知 Object ret = methodProxy.invokeSuper(obj, args);//目标方法执行 after(method, ret);//后置通知 return ret; } catch (Exception e) { exception();//异常通知 } finally { afterReturning();//方法返回通知 } return null; } //前置增强 private void before(Method method) { System.out.printf("before execute:%s\r\n", method.getName()); } //后置增强 private void after(Method method, Object ret) { System.out.printf("after execute:%s, ret:%s\r\n", method.getName(), ret); } //异常增强 private void exception() { System.out.println("execute failure"); } //after返回增强 private void afterReturning() { System.out.println("execute finish"); } }2、编写测试:
//NoOp.INSTANCE:NoOp回调把对方法调用直接委派给这个方法在父类中的实现,即可理解为真实对象直接调用方法,没有任何增强private static final Callback[] CALLBACKS = new Callback[] { new MyMethodInterceptor(), NoOp.INSTANCE};public void test() { //创建Enhancer实例 Enhancer enhancer = new Enhancer(); //cglib是基于继承方式代理,superClass就是基于哪个类型父类进行增强,创建出来的对象就是该类型子类 enhancer.setSuperclass(UserServiceImpl.class); //CallbackFilter主要用于过滤不同Method使用不同的Callback enhancer.setCallbackFilter(new CallbackFilter() { @Override public int accept(Method method) { if (method.getDeclaringClass() == Object.class) { return 1;//使用Callback数组下标是1的 } return 0;//使用Callback数组下标是0的 } }); //设置Callback数组,Callback就是封装的增强逻辑 enhancer.setCallbacks(CALLBACKS); //创建代理对象 UserService proxyObj = (UserService) enhancer.create(); System.out.println(proxyObj.say("zhangsan"));}通过上面enhancer.create()这条语句,就可以为目标类创建一个cglib动态代理,通过Callback回调方式将各种增强逻辑织入到代理实例中。
还可以使用
Enhancer.createClass()方法只创建出代理类型,然后自己通过反射方式创建对象。这时,需要注意:1、这时就不能使用setCallbacks()设置Callback数组,而是使用setCallbackTypes()设置Callback对应的类型;2、Enhancer.createClass()执行完成后,再通过Enhancer.registerStaticCallbacks(clz, CALLBACKS)方式设置Callback数组;
enhancer.setInterfaces()可用于设置生成的代理类必须实现的接口,比如你可以不设置superclass,只设置interfaces,这时也是可以正常创建出基于这个接口的动态代理实例,但是这时就要注意不能触发目标对象方法执行,如methodProxy.invokeSuper执行会报错,如下:
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { try { before(method);//前置通知 //Object ret = methodProxy.invokeSuper(obj, args);//目标方法执行 after(method, ret);//后置通知 return ret; } catch (Exception e) { exception();//异常通知 } finally { afterReturning();//方法返回通知 } return null;}基于接口创建的代理实例还是非常有用的,比如mybatis mapper就是一个没有实现类的接口,但是在spring中却可以依赖注入到service bean中,其中就是利用到上面基于接口创建动态代理的思想,注入进来的其实就是基于接口的动态代理,然后调用接口中方法时就可以进行拦截,获取到具体调用方法签名信息以及参数信息,基于这些数据进行业务逻辑处理。
invoke和invokeSuper方法区别
Callback#intercept()回调方法中执行methodProxy.invokeSuper()和methodProxy.invoke()是有很大区别的,而且看不到执行流程,所以这里涉及的逻辑非常绕。
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object ret = methodProxy.invokeSuper(obj, args); Object ret = methodProxy.invoke(delete, args);}大致区别如下图:
客户端触发代理对象say方法调用,首先进入代理对象中的同名方法,然后进入方法拦截对象MethodInterceptor,这里会出现两种情况:
invokeSuper方法,流程会重新走到代理对象中,代理对象这时会识别出是调用super中同名方法,所以没有继续向下走,而是通过super.say()方式调用目标对象中的方法。如果调用invoke方法,代理对象内部其实包裹一个目标对象target,这时它是直接通过target.say方式调用目标对象。invokeSuper()和invoke()方法都可以调用到目标对象方法,但是它们之间存在的一个本质区别:上下文环境不一样;或者更直接说:目标对象中this指向不一样。通过super.say()方式调用的目标对象,this指向的是代理对象;而通过target.say()方式调用的,目标对象中this指向的就是目标对象本身。这会导致什么差异呢?
假如目标对象类型如下定义,然后使用Enhancer创建一个代理对象:
public class Target { public void a() { System.out.println(" a 方法"); b(); } public void b() { System.out.println(" b 方法"); }}客户端触发代理对象a()方法执行,如果拦截器中使用invoke方式调用目标对象:直接调用目标对象a()方法,这个方法中又会通过this.b()调用方法b,由于是目标对象本身内部调用,所以b()方法不会被拦截的。
客户端触发代理对象a()方法执行,如果拦截器中使用invokeSuper()方式调用目标对象:这里是通过super.a()方式调用目标对象中的a()方法,然后a()方法又会通过this.b()调用方法b,注意这时的this不是目标对象本身,而是代理对象,因为代理对象继承目标对象,代理对象会有重名方法覆写了目标对象方法。所以,this.b()实际上会触发代理对象中方法b的执行,这时是会触发拦截器的。
所以,methodProxy.invokeSuper(obj, args)这个obj是代理对象;而methodProxy.invoke(obj, args)这个入参obj是目标对象。搞清楚这些基本理解清楚应该使用invoke还是invokeSuper。
ProxyFactory
Enhancer只能用于创建cglib动态代理,Spring中还有一个更上层点的类ProxyFactory,可以用于创建JDK动态代理或cglib动态代理。
public void test02() { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new UserServiceImpl()); /* 调用ProxyFactory.addInterface()或setInterfaces()表示对接口进行代理,一般会使用jdk动态代理, 除非setOptimize(true)或setProxyTargetClass(true)表示使用cglib代理 cglib代理类名称格式大致为:ServiceImpl$$EnhancerBySpringCGLIB$$f2952b94 */ //setInterfaces设置这个,会基于接口代理,使用jdk动态代理方式 proxyFactory.setInterfaces(UserService.class); //proxyFactory.setOptimize(true); //proxyTargetClass=true:直接代理目标类,而不是接口,使用cglib proxyFactory.setProxyTargetClass(true); // 添加增强 proxyFactory.addAdvice(new MyBeforeAdvice02()); //内部使用了缓存,target不变时,getProxy()获取到的都是同一个 //只有target变化时,才会重新创建新的代理对象 Object proxy = proxyFactory.getProxy();}ProxyFactory类是AOP底层实现中非常重要的一个类,另外AnnotationAwareAspectJAutoProxyCreator、BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator等一些高级AOP实现工具类都是通过在其父类AbstractAutoProxyCreator中借助ProxyFactory实现AOP逻辑织入的。所以,理解ProxyFactory的使用对理解Spring AOP至关重要。
ProxyFactory类控制代理的创建过程,其内部委托给DefaultAopProxyFactory的一个实例,该实例又转而委托给Cglib2AopProxy或JdkDynamicAopProxy,用于创建基于cglib代理还是jdk代理,想了解这两种动态代理区别可以分析下这个类源码。
ProxyFactory类addAdvice()方法将传入的通知封装到DefaultPointcutAdvisor(DefaultPointcutAdvisor是PointcutAdvisor的标准实现)的一个实例中,并使用默认包含所有方法的切入点对其进行配置。为更加灵活细粒度的控制在哪些连接点上拦截通知,可以使用addAdVisor()方法添加一个带有切入点消息的Advisor。
可以使用相同的ProxyFactory实例来创建多个代理,每个代理都有不同的切面。为了帮助实现该过程,ProxyFactory提供了removeAdvice()和removeAdvisor()方法,这些方法允许从ProxyFactory中删除之前传入的任何通知或切面,同时可以使用boolean adviceIncluded(@Nullable Advice advice)检查ProxyFactory是否附有特定的通知对象。
Advice
ProxyFactory类addAdvice()和addAdvisor()两个方法分别引入了两个重要的类:Advice和Advisor。首先,我们来看下Advice这个接口类,其可以看成需要织入增强的代码逻辑封装。Advice在Spring中API结构如下:
大致描述:
BeforeAdvice:前置通知,该接口没有任何方法,平时主要使用其子类MethodBeforeAdvice,因为Spring中只能在方法前后织入,对应注解@Before;AfterAdvice:后置通知,其存在两个子类AfterReturningAdvice和ThrowsAdvice,分别对应@AfterReturning和@AfterThrowing;MethodInterceptor:可以实现环绕通知,对应注解@Around;Advisor
在AOP规范中有切面概念,在Spring中大概对应就是Advisor。Advisor有两个子接口:PointcutAdvisor和IntroductionAdvisor:
其实真正使用比较多的是它的子类PointcutAdvisor,该接口关键就是如下两个方法:
public interface PointcutAdvisor { Advice getAdvice(); Pointcut getPointcut();}PointcutAdvisor从接口定义大概就可以看出,其就是对Advice和Pointcut的封装,Advice代表的是横切面需要织入的代码,而Pointcut定义了如何去切的问题。从之前分析来看,Advice也可以看出一种非常简单的切面,是对指定的类所有方法都进行切入,横切面太宽泛,灵活性不够,PointAdvisor引入了Pointcut后显然比Advice更加灵活、强大。
PointcutAdvisor主要有6个具体的实现类,分别介绍如下:
DefaultPointcutAdvisor:最常用的切面类型,它可以通过任意Pointcut和Advice定义一个切面,一般可以通过扩展该类实现自定义的切面;NameMatchMethodPointcutAdvisor:通过该类可以定义按方法名定义切点的切面;RegexpMethodPointcutAdvisor:使用正则表达式模式定义切点,其内部通过JdkRegexpMethodPointcut构造出正则表达式方法名切点;StaticMethodMatcherPointcutAdvisor:静态方法匹配器切点定义的切面,默认情况下,匹配所有的目标类;AspecJExpressionPointcutAdvisor:用于Aspecj切点表达式定义切点的切面;AspecJPointcutAdvisor:用于AspecJ语法定义切点的切面;其实,这些Advisor主要区别还是基于其内部封装的Pointcut实现类体现的,在实际工作中这些类使用的可能不多,这里的核心在于Pointcut如何定义切入点,所以实际开发中更多的可能会去定制Pointcut实现类,然后使用DefaultPointcutAdvisor将其包装成Advisor使用。
下面通过RegexpMethodPointcutAdvisor案例简单了解即可:
public void test1(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("aop.demo03"); UserServiceImpl target = new UserServiceImpl(); ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setTarget(target); proxyFactoryBean.setProxyTargetClass(true); RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(); //设置advisor的advice advisor.setAdvice(new MyBeforeAdvice02()); //设置advisor的pointcut,aop.demo03包下所有类中已say开头的方法才会织入 advisor.setPattern("aop.demo03..*.say*"); proxyFactoryBean.addAdvisor(advisor); proxyFactoryBean.setBeanFactory(context); Object obj = proxyFactoryBean.getObject(); System.out.println(obj.getClass().getName()); UserServiceImpl userService = (UserServiceImpl) obj; System.out.println(userService.say("haha"));}RegexpMethodPointcutAdvisor表示通过正则表达式进行切点描述的切面,它有一个pattern属性用来指定增强要应用到哪些类的哪些方法,也可以通过patterns属性指定多个表达式进行匹配。有一个advice属性用来表示要应用的增强,这样就能表示一个完整的切面了。
Pointcut
Advisor引入了一个核心接口Pointcut,其描述了对哪些类的哪些方法进行切入。Pointcut从其定义可以看出其由ClassFilter和MethodMatcher构成。ClassFilter用于定位哪些类可以进行切入,然后再通过MethodMatcher定位类上的哪些方法可以进行切入,这样Pointcut就拥有了识别哪些类的哪些方法能被进行切入的能力。
public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher();}Pointcut接口API结构见下:
其中这里比较常用的AnnotationMatchingPointcut基于注解进行切入,之前分析【Spring源码】- 09 扩展点之@Import注解一节就使用到该实现类,将标记有@MyAsync注解的方法都进行增强就是利用这个实现类:
AnnotationMatchingPointcut pointcut = AnnotationMatchingPointcut.forMethodAnnotation(MyAsync.class);Advice advice = new AsyncAnnotationAdvice(executor);DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();advisor.setPointcut(pointcut);advisor.setAdvice(advice);ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.setTarget(bean);if(!this.isProxyTargetClass()){ proxyFactory.setInterfaces(bean.getClass().getInterfaces());}proxyFactory.addAdvisor(advisor);proxyFactory.copyFrom(this);return proxyFactory.getProxy();ProxyFactoryBean
ProxyFactoryBean和ProxyFactory功能和使用其实差不多,底层逻辑也基本一致,ProxyFactoryBean主要是融合了IOC功能。一方面ProxyFactoryBean类是FactoryBean的一个实现,更加方便注入IoC中,参照mybatis与spring整合一节,其中关键一步就是将扫描的BeanDefinition中beanClass由接口类替换成FactoryBean类型;另一点就是切面可以使用IoC容器bean。
下面通过一个案例简单看下ProxyFactoryBean使用:
package org.simon.ioc.demo1;import org.springframework.aop.MethodBeforeAdvice;import org.springframework.stereotype.Component;import java.lang.reflect.Method;@Componentpublic class MyBeforeAdvice implements MethodBeforeAdvice { public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("-----洗手-----"); }}@Testpublic void test1(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("org.simon.ioc.demo1"); UserService target = new UserServiceImpl(); ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setTarget(target); proxyFactoryBean.setInterceptorNames("myBeforeAdvice", "otherAdvice*"); proxyFactoryBean.setBeanFactory(context); Object obj = proxyFactoryBean.getObject(); System.out.println(obj.getClass().getName()); UserService userService = (UserService) obj; System.out.println(userService.say("haha"));}其中关键一步在:proxyFactoryBean.setInterceptorNames("myBeforeAdvice", "otherAdvice*");,可以使用IoC中的beanName,同时还支持通配符*从IoC中查找对应Bean。
高级API
前面介绍的类、接口等都是Spring AOP中一些底层API,使用起来不太方便,感觉功能不太强大,不论是ProxyFactory还是ProxyFactoryBean创建织入切面的代理,每次只能硬编码一个具体的Bean,假如我想将某个包路径下符合一定规则的类的特定方法都进行织入代理怎么办?
使用前面那些API好像都不能实现这个需求,但是结合之前分析的Spring扩展点,很容易想到可以结合BeanPostProcessor扩展点实现这个需求,postProcessAfterInitialization()这个方法回调时Bean依赖注入、初始化等都已经完成,这时就可以在这个方法中过滤出符合一定条件的Bean进行代理增强处理。
其实,在Spring中基于这种思想,已经为我们提供了三个实现类:
BeanNameAutoProxyCreator:基于beanName进行织入增强,通过setBeanNames(String... beanNames)将需要增强的beanName设置进去;DefaultAdvisorAutoProxyCreator:基于Advisor匹配机制进行织入增强,它会对容器中所有的Advisor进行扫描,自动将这些切面应用到匹配的Bean中;AnnotationAwareAspectjAutoProxyCreator:基于Bean中AspectJ注解方式进行织入增强,就是实现平时使用的@Aspect、@Before、@Around等AspectJ注解功能支持。下面我们就来通过DefaultAdvisorAutoProxyCreator了解下使用场景:
1、定义一个目标类,后续就是基于该类进行增强:
@Componentpublic class UserServiceImpl{ public String say(String name){ System.out.println("执行:==UserService#say==="); return "hello,"+name; }}2、定义一个配置类:
@Configuration@ComponentScan(basePackageClasses = AopConfig.class)public class AopConfig { @Bean public RegexpMethodPointcutAdvisor regexpMethodPointcutAdvisor(){ RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor(); advisor.setAdvice(new MyBeforeAdvice02()); //aop.demo03包下所有类中带有say开头方法进行增强 advisor.setPattern("aop.demo03..*.say*"); return advisor; } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ return new DefaultAdvisorAutoProxyCreator(); }}这个类有两个关键,一个是向IoC中注入Advisor,之前分析过Advisor包含两个功能:
Pointcut定位哪些类的哪些方法需求切入;通过关联的Advice指定切入增强逻辑;另一个关键就是注入DefaultAdvisorAutoProxyCreator,这个就是一个Spring内置的实现BeanPostProcessor扩展类,其在postProcessAfterInitialization()方法中对Bean进行切入增强。
3、测试:
public void test1(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class); System.out.println(context.getBean(UserServiceImpl.class).getClass());}context.getBean(UserServiceImpl.class)从IoC容器中获取的就是使用cglib代理后的实例。
下面我们再来分析下AnnotationAwareAspectjAutoProxyCreator,平时如果项目中需要开启AOP功能,使用@EnableAspectJAutoProxy注解方式开启,我们来看下该注解干了什么?
1、@EnableAspectJAutoProxy注解使用@Import注解将AspectJAutoProxyRegistrar引入:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Import(AspectJAutoProxyRegistrar.class)public @interface EnableAspectJAutoProxy { boolean proxyTargetClass() default false; boolean exposeProxy() default false;}2、AspectJAutoProxyRegistrar是ImportBeanDefinitionRegistrar接口实现类:
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //注册一个SmartInstantiationAwareBeanPostProcessor类型的实现类:AnnotationAwareAspectJAutoProxyCreator AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }}其中最关键一句AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);,就是向IoC容器中注入AnnotationAwareAspectJAutoProxyCreator。
这样我们就明白了@EnableAspectJAutoProxy注解方式开启AOP的本质就像向IoC中注入AnnotationAwareAspectJAutoProxyCreator,它利用BeanPostProcessor扩展点功能实现织入增强逻辑。
总结
首先,对Spring AOP底层一些最基础、最核心的API的分析梳理,相信你会对Spring AOP底层实现逻辑有了一个更加深入的理解。然后通过Spring AOP提供的高级API,理解了如何将IoC和AOP集成到一起实现强大功能,对Spring中AOP的整体实现思路也有了比较清晰的认识。
标签:
推荐文章
- 世界百事通!【Spring源码】- 10 Spring AOP核心API
- 海南支持民营经济发展:全面加强对民营企业和民营企业家的关心服务
- 今亮点!科大讯飞旗下解铃网运营公司注销
- 安东油田服务:2022年净利大幅上升3.1倍至2.94亿元
- 爱上你是一个错 杨培安_爱上一个有妇之夫好累
- *ST易尚(002751)3月28日主力资金净卖出46.99万元
- 小摩:下调绿城服务(02869)目标价至5.8港元 评级仍为“增持”
- 无锡有过购房记录还能申请工程购房补贴吗?|全球新资讯
- “用我一身脏,换来万家净”(把雷锋精神代代传承下去)|每日时讯
- “就业夜市”让毕业生求职“零距离”
- 每日精选:激光祛红血丝对身体有害吗?激光祛红血丝术后注意事项有哪些?
- 天天简讯:方大特钢:3月27日融券净卖出15.86万股,连续3日累计净卖出29.24万股
- 【环球快播报】雨果的名言英文原句_雨果的名言
- 每日速看!孙莉否认多多染金发,回应读错字造黄谣等事,黄磊透露女儿很痛苦
- 即时焦点:2023年03月27日四川自贡疫情最新通报及自贡目前疫情最新通告
- 天秤座上升星座是什么 热闻
- ST星星:公司精密结构件产品有运用在VR、AR领域 但其业务占比较低_当前报道
- 养殖ETF: 国泰基金管理有限公司关于旗下部分交易型开放式基金新增东方财富证券股份有限公司为一级交易商的公告
- 银行基金今天股市新闻琚泽平 全球报资讯
- 【世界聚看点】商务部部长王文涛会见溢达集团董事长杨敏德
- 银行里有定期存款的一定要看,别不当回事,等到吃亏可就晚了_每日消息
- 【全球时快讯】16年潜心研究,改良最难手术技术
- 还有儿皇梦,姆总逼宫巴黎!专访:法国队才有好队友,这里更团结_快看点
- 环洋市场咨询:全球软组织修复产品市场可行性调研报告 全球球精选
- 中石油海南分公司:全力做好天然气保供工作
- 【环球新视野】花旗:持有澳大利亚银行股仍然是明智的
- 小佩顿:对于重新融入勇士感到乐观 与库汤追等人一直相处融洽
- 英汉修辞跨文化研究_关于英汉修辞跨文化研究的简介
- 珠海民警帮助解决犬吠扰民问题获群众感谢信 每日播报
- 鬼吹灯之巫峡棺山 电影_鬼吹灯之巫峡棺山_环球头条
- 中国太保:2022年净利同比降8.3% 拟每股派1.02元
- 羽坛连爆大冷!安赛龙+李梓嘉,男单前二双双出局,国羽2项冲冠-当前要闻
- TT:我一直在推动詹欧重聚 希望看到他们都穿着紫金球衣
- 永久的悔季羡林
- 地产股早盘继续走高,中国武夷 中交地产 深振业A等涨停
- 【全球快播报】为什么说人民群众是历史的创造者和历史发展的决定力量_人民群众为什么是历史的创造者呢
- 工商企业管理专业认知_工商企业管理专业介绍?_世界观速讯
- 每日报道:增广贤文读后感100(增广贤文读后感)
- 重点聚焦!2021愚人节是几月几日 2021愚人节在哪一天
- 世界焦点!徐亮:中国足协不彻底洗牌 中国足球未来别想好
- 小产权房子拆了赔不赔偿_全球微头条
- 跑跑卡丁车羊羊车(《跑跑卡丁车》小绵羊SR王者攻略)|焦点热议
- 优朋普乐a8怎么刷机|天天观焦点
- 销量持续走低,岚图突围谈何易?|当前最新
- 观焦点:汗流浃背的典故出自西汉周勃他汗流浃背的原因是_汗流浃背的典故
- 干桂花怎么吃效果最好_干桂花怎么吃
- 微型电动车销量大跌,“人民的代步车们”为什么卖不动了? 每日热文
- 银行从业证书申请流程-全球热议
- 绿城服务:2022年实现收入148.56亿元-天天速读
- 天天通讯!尿道括约肌发育不好_尿道括约肌什么用
- 总产值首次突破万亿元!我国锂电行业将迎来快速增长期
- 女性吃什么食物避孕更可靠_女性吃什么食物最丰胸
- 愚人节什么时候 愚人节是几月几日的
- 四环医药:2022年公司拥有人应占亏损约19.15亿元 建议派息每股3.2分|全球快播
- 小米2与小米2a的区别(小米2与小米2s) 世界快讯
- 永达汽车(03669.HK)2022年股东应占溢利达14.25亿元 二手车运营能力快速攀升|全球讯息
- 中瑞电子曾因定价未达一致流失大客户 向“老赖”销售超千万元
- 浐灞公安“三下”服务 架起警民“连心桥”
- 武则天为什么要找那么多男宠?其实与国事有关!这位公主说出原因_全球独家
- 重庆轨道交通18号线实现全线“洞通”_当前速递
- 环球新消息丨魔兽世界完整的恶魔之眼有什么用
- 世界百事通!四川消防救援队伍片区比武开赛,全省21支参赛队竞技
- 快讯:第十二章 临时教官(一)
- 猜灯谜游戏答案大全_猜灯谜-当前速讯
- 速递!缅甸,尔康去了都回不来
- 【环球快播报】驾证被扣12分怎么办
- 持之以恒抓分类,长沙县垃圾分类工作稳步推进中
- 张家口桥西区开展“世界水日”环保教育活动
- 环球时讯:杜兆才:把足球工作重心转移到青少年足球
- 腾势N7汽车全球首搭帝瓦雷音响 2023上半年发布
- 广西贵港武警官兵实战化训练 锻造过硬本领
- 民事案例分析报告范文(优选5篇) 世界报资讯
- korea是哪国
- 全球讯息:海南:今年计划筹集保障性租赁住房3455套
- 报道:女排欧联杯斯坎迪奇2-3土航仍晋级决赛 朱婷27分
- 每日速讯:江西鹰潭可提供志高热水器维修服务地址在哪
- 当前热门:枣庄求职网_关于枣庄求职网简述
- 八年级上册英语教科书翻译外研版_八年级上册英语教科书翻译
- 联想手机强行恢复原厂设置_信息
- 环球百事通!上海金山成立沪上首家预制菜产业发展协会
- 胸口哪里是胃吗_胸口是哪里 天天新视野
- 终于轮到便携式投影仪当“风口上的猪”?
- 英雄联盟出装注意什么,英雄联盟出装的顺序谁告诉我
- 【环球速看料】明阳智能:总订单量第一,海上订单量第一!
- 南通崇川“世界水日”“中国水周”系列活动迎春起航_全球快报
- 炼石航空:配套产品研制和需求取得新突破,具体指的是单晶叶片研制和飞机发动机需求的突破
- 丁禹兮彭小冉《春闺梦里人》看两集弃了!剧情无脑,演员用力过猛
- 可立克:3月21日获融资买入734.94万元,占当日流入资金比例7.71%_当前速看
- 《货币战争》编著宋鸿兵:危机三部曲,硅谷银行爆雷只是个开始 当前热点
- 技能培训强本领 促进就业惠民生
- 韩国40岁新娘人数比20岁还多:初婚男女平均年龄创新高
- 资讯:魔兽法师名字大全霸气_魔兽法师名字大全
- 天才建筑师留下的7座世界遗产 “遇见高迪”展览在沪举行
- 武汉一地铁工地用779万元做了这件事!只为让大家睡个好觉
X 关闭
资讯
X 关闭

