当前位置: 首页 > news >正文

店铺引流的30种方法橘子seo

店铺引流的30种方法,橘子seo,手机制作动画的app,外贸网站建设seo清明前夕#xff0c;我发表了一篇与Spring Cloud有关的文章#xff0c;原计划在这篇文章之后#xff0c;就梳理Eureka注册中心的相关知识。然而在跟踪之后#xff0c;我才发现上来就谈Eureka组件的实现原理是不现实的#xff0c;因为我根本不清楚SpringBoot是如何集成Eure…清明前夕我发表了一篇与Spring Cloud有关的文章原计划在这篇文章之后就梳理Eureka注册中心的相关知识。然而在跟踪之后我才发现上来就谈Eureka组件的实现原理是不现实的因为我根本不清楚SpringBoot是如何集成Eureka组件的。虽然周围人一再强调集成与要梳理的组件没有任何关系但是我总觉得不解决这个问题的梳理就像是在半空中建房一样无处落脚。因此在这篇文章中我想梳理一下SpringBoot自动装配的过程。 1 SpringBoot中的Import注解 记得在梳理《Spring AOP》及《Spring事务》的时候同事有跟我提过这个注解。当时他明确指出Import注解的解析起点位于ConfigurationClassPostProcessor类的processConfigBeanDefinitions(BeanDefinitionRegistry)方法中具体如下图所示 顺着图中红色方框标识的方法继续向下会进入到ConfigurationClassParser类中该类中的parser()方法的源码如下所示 这个方法中我们主要关注红色方框标出的地方。然后继续顺着这个方法向下看最后会来到ConfigurationClassParser类的doProcessConfigurationClass(ConfigurationClass, SourceClass)方法中在这个方法中我们可以看到如下信息具体如下图所示 从红色方框可以看出这个方法是真正调用各注解解析逻辑的地方这个方法可以处理的注解有PropertySource、ComponentScan、Import、ImportResource、Bean。注意这里我们主要关注Import注解的解析过程。 梳理到这里先停一下。因为在梳理过程中我发现如果不明白这个注解的作用就算弄清楚了它的解析流程也就是蜻蜓点水毫无意义。那Spring框架的设计者为什么要提供这样一个注解呢 在Spring中Import注解的作用是用来导入额外的配置类或者组件类以扩展当前上下文中的Bean定义集合。这意味着当我们在一个配置类上使用Import注解时Spring容器会在初始化过程中处理被导入的类并依据类的不同特性执行不同的操作 导入配置类如果Import的参数是一个带有Configuration注解的类则Spring容器会像处理其他配置类一样处理这个类包括扫描并实例化其中通过Bean注解的方法所定义的Bean导入普通类从Spring 4.2开始Import不仅可以导入配置类还可以导入普通的类。这意味着即使不是配置类只要通过Import引入Spring也会尝试将该类作为Bean进行实例化和管理实现ImportSelector接口当Import的参数是一个实现了ImportSelector接口的类时Spring容器会实例化该类并调用selectImports()方法。此方法返回一个包含类全路径名的字符串数组Spring容器会按照返回的列表加载并实例化那些类实现DeferredImportSelector接口类似于ImportSelector但DeferredImportSelector的selectImports()方法调用时机更晚确保在所有常规的Configuration类处理完毕后才进行。这对于那些依赖于其他Bean配置完成后才能确定导入哪些类的情况非常有用实现ImportBeanDefinitionRegistrar接口当Import注解导入一个实现了ImportBeanDefinitionRegistrar接口的类时Spring容器允许软件开发者直接通过编程方式向BeanDefinitionRegistry注册自定义的Bean定义这提供了更底层的控制机制可以在注册Bean时设置更多的属性或执行复杂的逻辑。 总之Import注解提供了一种灵活的方式来聚合和整合各个模块或组件的配置使得Spring容器能够统一管理和初始化应用程序所需的所有Bean。个人理解Import注解的主要作用就是向Spring容器中注入Bean不知这个说法是否准确若不对欢迎大家在评论区留言。了解了Import注解的作用下面就来看看其使用案例吧 1.1 导入普通类 在本小节中我们将使用Import注解向Spring容器中导入一个普通java类下面就一起看看这种用法的实现过程。首先定义一个普通java类源码如下 public class A { }接着再定义一个配置类ConfigA然后在该类中定义一个方法a()该方法上有一个Bean注解源码如下所示 import org.springframework.context.annotation.Bean;public class ConfigA {Beanpublic A a() {return new A();} }最后再定义一个配置类ConfigB该类上有两个注解Configuration和Import其中Import注解中指定ConfigA.class为属性具体源码如下所示 Configuration Import(ConfigA.class) public class ConfigB { }最后编写一个测试类用于验证这种写法能否正常向Spring容器中注入相关对象ConfigA对象及A对象。该测试类的源码如下所示 SpringBootApplication public class EurekaServiceApplication {public static void main(String[] args) {ApplicationContext ctx SpringApplication.run(EurekaServiceApplication.class, args);ConfigA ca ctx.getBean(ConfigA.class);A a ctx.getBean(A.class);System.out.println(ca.getClass().getSimpleName());System.out.println(a.getClass().getSimpleName());}}通过观察控制台输出我们可以发现ConfigA及A可以正常注入到Spring容器中。 1.2 导入ImportSelector实现类 在本小节中我们将通过在Import注解中指定ImportSelector接口的实现类的方式向Spring容器中注入一个Bean对象下面就一起看看这种用法的实现过程。首先定义一个普通java类源码如下 public class Tiger { }然后再定义一个配置类ZooConfig然后在该类中定义一个方法tiger ()该方法上有一个Bean注解源码如下所示 import org.springframework.context.annotation.Bean;public class ZooConfig {Beanpublic Tiger tiger() {return new Tiger();}}接着再定义一个ZooImportSelector类该类实现了ImportSelector接口并实现了该接口中的selectImports()方法该类的源码如下所示 public class ZooImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{org.com.chinasoft.s.ZooConfig};}}最后再定义一个配置类ZooConfigB该类上有两个注解Configuration和Import其中Import注解中指定ZooImportSelector.class为属性具体源码如下所示 Configuration Import(ZooImportSelector.class) public class ZooConfigB { }最后编写一个测试类用于验证这种写法能否正常向Spring容器中注入相关对象ZooConfig对象及Tiger对象。该测试类的源码如下所示 SpringBootApplication public class EurekaServiceApplication {public static void main(String[] args) {ApplicationContext ctx SpringApplication.run(EurekaServiceApplication.class, args);ZooConfig zooConfig ctx.getBean(ZooConfig.class);Tiger tiger ctx.getBean(Tiger.class);System.out.println(zooConfig.getClass().getSimpleName());System.out.println(tiger.getClass().getSimpleName());}}通过观察控制台输出我们可以发现ZooConfig及Tiger可以正常注入到Spring容器中。 1.3 导入ImportBeanDefinitionRegistrar实现类 在本小节中我们将通过在Import注解中指定ImportBeanDefinitionRegistrar接口的实现类的方式向Spring容器中注入一个Bean对象下面就一起看看这种用法的实现过程。首先定义一个普通java类源码如下 public class Dog { }然后再定义一个ZooRegistrar类该类实现了ImportBeanDefinitionRegistrar接口并实现了该接口中的registerBeanDefinitions ()方法该类的源码如下所示 import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata;public class ZooRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {GenericBeanDefinition gbd new GenericBeanDefinition();gbd.setBeanClass(Dog.class);registry.registerBeanDefinition(dog, gbd);}}接着再定义一个配置类ZooConfigBC该类上有两个注解Configuration和Import其中Import注解中指定ZooRegistrar.class为属性具体源码如下所示 Configuration Import(ZooRegistrar.class) public class ZooConfigBC { }最后编写一个测试类用于验证这种写法能否正常向Spring容器中注入相关对象Dog对象。该测试类的源码如下所示 SpringBootApplication public class EurekaServiceApplication {public static void main(String[] args) {ApplicationContext ctx SpringApplication.run(EurekaServiceApplication.class, args);Dog dog ctx.getBean(Dog.class);System.out.println(dog.getClass().getSimpleName());}}通过观察控制台输出我们可以发现Dog可以正常注入到Spring容器中。 通过前面的梳理我们知道Import注解的作用就是向Spring容器中注入Bean也了解了通过Import注解向Spring容器中注入Bean的方法。下面我们将继续梳理Spring解析Import注解的步骤。 前面梳理到ConfigurationClassParser类doProcessConfigurationClass(ConfigurationClass, SourceClass)方法。在该方法中我们可以看到有这样一段代码如下所示 processImports(configClass, sourceClass, getImports(sourceClass), true); 这段代码中的getImports(sourceClass)方法的主要作用就是搜集源类上的Import注解这里的源类是我们项目的启动类即EurekaServiceApplication这个类上有两个注解一个是SpringBootApplication一个是EnableDiscoveryClient具体情况如下所示 图中的情况与上面的说法一致下面先看一下getImports(sourceClass)方法该方法及其相关方法的源码如下所示 private SetSourceClass getImports(SourceClass sourceClass) throws IOException {SetSourceClass imports new LinkedHashSetSourceClass();SetSourceClass visited new LinkedHashSetSourceClass();collectImports(sourceClass, imports, visited);return imports; } private void collectImports(SourceClass sourceClass, SetSourceClass imports, SetSourceClass visited)throws IOException {if (visited.add(sourceClass)) {for (SourceClass annotation : sourceClass.getAnnotations()) {String annName annotation.getMetadata().getClassName();if (!annName.startsWith(java) !annName.equals(Import.class.getName())) {collectImports(annotation, imports, visited);}}imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), value));} }从CollectImports()方法的源码不难看出这个方法采用递归调用的方式逐步找出源类及该类上的注解通过Import注解导入的类。具体过程如下图所示 从图中可以看出第一轮循环先处理启动类上的SpringBootApplication注解此时annName的值为org.springframework.boot.autoconfigure.SpringBootApplication接下来用if分支中的判断条件处理后发现if分支中的逻辑可以执行所以下面会递归调用collectImports()方法其中sourceClass参数的值为SpringBootApplication注解imports参数的值为importsvisited的值为visited集合。此时可以看到下面这样一幅图片 图中的Evaluate对话框展示的是sourceClass.getAnnotations()操作从SpringBootApplication注解类中拿到的注解信息其中前四个是java提供的元注解后三个则是Spring框架提供的注解。因此这轮解析中只有后三个会被处理其中SpringBootConfiguration注解处理后imports集合无变更默认大小为零处理后依旧为零、EnableAutoConfiguration注解处理后imports集合有变化默认大小为零处理后变为二、ComponentScan注解处理后imports集合无变化默认大小为二处理后依旧为二。这里一起看一下EnableAutoConfiguration注解的详细源码如下所示 Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited AutoConfigurationPackage /** 注意下面这个注解 */ Import(EnableAutoConfigurationImportSelector.class) public interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration;/*** Exclude specific auto-configuration classes such that they will never be applied.* return the classes to exclude*/Class?[] exclude() default {};/*** Exclude specific auto-configuration class names such that they will never be* applied.* return the class names to exclude* since 1.3.0*/String[] excludeName() default {};} Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited /** 注意下面这个注解 */ Import(AutoConfigurationPackages.Registrar.class) public interface AutoConfigurationPackage {} 从代码可以看出这里有两个Import注解所以前面递归解析后imports集合大小会变成二。由于启动类上还有一个EnableDiscoveryClient注解该注解的源码如下所示 Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented Inherited Import(EnableDiscoveryClientImportSelector.class) public interface EnableDiscoveryClient {/*** If true, the ServiceRegistry will automatically register the local server.*/boolean autoRegister() default true; }从源码可以看出这个注解上有个Import注解所以最终imports集合的大小为三最终效果如下图所示 imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), value))这一句代码位于collectImports()方法中。其主要作用就是将定义在sourceClass比如EurekaServiceApplication启动类上的Import注解中的值解析出来并添加到imports集合中。 接下来就可以回到processImports()方法中了这段方法的主要作用是对import候选类进行处理。在开始梳理前先来看一下它的源码如下所示 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,CollectionSourceClass importCandidates, boolean checkForCircularImports) throws IOException {if (importCandidates.isEmpty()) {return;}if (checkForCircularImports isChainedImportOnStack(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));}else {this.importStack.push(configClass);try {for (SourceClass candidate : importCandidates) {if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector - delegate to it to determine importsClass? candidateClass candidate.loadClass();ImportSelector selector BeanUtils.instantiateClass(candidateClass, ImportSelector.class);ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);if (this.deferredImportSelectors ! null selector instanceof DeferredImportSelector) {this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));}else {String[] importClassNames selector.selectImports(currentSourceClass.getMetadata());CollectionSourceClass importSourceClasses asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar -// delegate to it to register additional bean definitionsClass? candidateClass candidate.loadClass();ImportBeanDefinitionRegistrar registrar BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}else {// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -// process it as an Configuration classthis.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass));}}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException(Failed to process import candidates for configuration class [ configClass.getMetadata().getClassName() ], ex);}finally {this.importStack.pop();}} }为了更清楚的捋顺这个方法的处理逻辑我们先来看一下这个方法在运行过程中的情况具体如下图所示 注意configClass、currentSourceClass均为启动类而importCandidates则是前面getImports()执行的结果集。因此图中蓝色条纹标注出来的importCandidates集合有三个值。蓝色条纹所处的代码块的处理逻辑也相对简单 判断import候选类是否是ImportSelector类型如果是则加载这个类然后通过反射的方式创建对象最后反射调用这个对象上的Aware方法。接着判断这个对象是否是DeferredImportSelector如果是则将其添加到deferedImportSelectors集合中如果不是则直接执行这个类上的selectImports()方法接着将返回结果转化为Collection集合最后再次调用processImports()方法处理selectImports()方法返回的数据这正呼应了前面说的实现ImportSelect接口的类其selectImports()方法返回的数据会被加载到Spring容器中 未完请见谅
http://www.zqtcl.cn/news/837230/

相关文章:

  • 如何查看域名以前是做什么网站的网站索引下降如何解决
  • 潜江 网站建设扬中话
  • 网站建设项目方案ppt广州建站模板平台
  • 房产部门成立网站免费seo推广软件
  • python做网站好处百度指数分析报告
  • 网站建设挣钱班级介绍网页制作模板
  • 工作室 网站建设app公司
  • 自己做的网站怎么在百度搜索到网页制作论文3000字
  • 如何网站托管中国跨境电商平台有多少
  • 手机p2p网站做平面设计兼职的网站有哪些
  • 贵金属网站建设唐山网站制作工具
  • 网站入门成都网站制作沈阳
  • 接做网站单子的网站做网站要会那些ps
  • 做盗市相关网站wordpress速度优化简书
  • 贵阳手机网站建设公司国内永久免费云服务器
  • 温州做网站定制哪家网络推广公司好
  • 招聘网站怎么做线下活动网站后台管理系统怎么开发
  • 西湖区外贸网站建设商梦建站
  • 网站首页设计注意斗蟋蟀网站建设
  • 石家庄网站建设远策科技网站建设公司人员配备
  • 手机怎么建网站链接专门做鞋子的网站吗
  • 网站建设设计作品怎么写网站建设 网站内容 采集
  • 自己做网站nas如何做网站大图片
  • 网站优化定做嘉兴模板建站代理
  • 南宁做网站比较好的公司有哪些花乡科技园区网站建设
  • 网站注册平台怎么注册申请空间 建立网站吗
  • 汕头住房与城乡建设网站做网站视频 上传到哪儿
  • 东莞网站关键词优化福建个人网站备案
  • 国外获奖flash网站泉州网站制作专业
  • 万网域名注册后如何做网站教学上海app开发和制作公司