企业门户网站的建设费用,如何将wordpress上传,品牌建设 厚植,wordpress发文章文章目录如果没时间看的话#xff0c;在这里直接看总结一、Java SPI的概念和术语二、看看Java SPI是如何诞生的三、Java SPI应该如何应用四、从0开始#xff0c;手撸一个SPI的应用实例五、SpringBoot自动装配六、Spring SPI机制与Spring Factories机制做对比七、这里是给我自…
文章目录如果没时间看的话在这里直接看总结一、Java SPI的概念和术语二、看看Java SPI是如何诞生的三、Java SPI应该如何应用四、从0开始手撸一个SPI的应用实例五、SpringBoot自动装配六、Spring SPI机制与Spring Factories机制做对比七、这里是给我自己提个醒如果没时间看的话在这里直接看总结 1. SPI是一个机制流程由三个组件构成 ServiceLoader就是ClassLoaderService是接口作为文件在META-INF/services目录下的名称ServiceProvider是接口的实现类作为文件在META-INF/services目录下的内容 2. SPI执行流程 ServiceLoader通过classpath路径加载指定的Service文件然后使用里面合适的内容ServiceProvider 一、Java SPI的概念和术语
SPIService Provider Interface基于ClassLoader发现并加载服务机制 SPI由三个组件构成Service、Service Provider、ServiceLoader Service是一个公开的接口或抽象类定义了一个抽象的功能模块文件名称Service Provider是Service的实现类文件内容ServiceLoader是SPI机制中的核心组件负责在运行时发现并加载Service Provider 二、看看Java SPI是如何诞生的 在Java SPI出现之前Class.forName要自己根据需求写驱动类 JDBC要求Driver实现类在类加载的时候能将自身的实例对象自动注册到DriverManager中从而加载数据库驱动。 Java SPI逐渐融入JDBC 三、Java SPI应该如何应用
规范的配置文件 Service Provider类必须具备无参的默认构造方法 在JDBC中的对应实现 保证能加载到配置文件和Service Provider类 在JDBC中的对应实现 总结上述除了导包需要自己动手以外其他的手续都是导包之后Java SPI自动完成的
四、从0开始手撸一个SPI的应用实例 总体流程
五、SpringBoot自动装配
参考视频每一帧都是干货15分钟的视频花2小时看 参考文章springboot自动装配到底是什么意思 参考文章建立META-INF/spring.factories文件的意义何在 参考文章springboot自动装配原理-以redis为例 参考文章聊聊 SpringBoot 自动装配原理 参考文章spring.factories 文件的位置
1. 手动装配Redis实例
加入pom依赖
dependencygroupIdorg.springframework.data/groupIdartifactIdspring-data-redis/artifactIdversion2.0.9.RELEASE/version
/dependencydependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion2.9.0/version
/dependency配置xml的bean的配置 //配置连接池bean idpoolConfig classredis.clients.jedis.JedisPoolConfigproperty nameminIdle value10/propertyproperty namemaxTotal value20/property/bean//配置连接工厂bean idjedisConnectionFactory classorg.springframework.data.redis.connection.jedis.JedisConnectionFactoryproperty namehostName value47.104.128.12/propertyproperty namepassword value123456/propertyproperty namedatabase value0/propertyproperty namepoolConfig refpoolConfig/property/bean//配置 redisTemplate 模版类bean idredisTemplate classorg.springframework.data.redis.core.RedisTemplateproperty nameconnectionFactory refjedisConnectionFactory/!--如果不配置Serializer那么存储的时候缺省使用String如果用User类型存储那么会提示错误User cant cast to String --property namekeySerializerbean classorg.springframework.data.redis.serializer.StringRedisSerializer//propertyproperty namevalueSerializerbean classorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer//propertyproperty namehashKeySerializerbean classorg.springframework.data.redis.serializer.StringRedisSerializer//propertyproperty namehashValueSerializerbean classorg.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer//property/bean导入配置 ImportResource(locations “classpath:beans.xml”) 可以导入xml的配置文件
2. SpringBoot自动配置Redis实例
引入依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency配置Redis服务器
spring:redis:database:0host:127.0.0.1port:6379password:123456直接使用RedisTemplate或StringRedisTemplate
Autowired
private RedisTemplateObject, Object redisTemplate;
Autowired
private StringRedisTemplate stringRedisTemplate;提出问题自动配置 我们除了通过maven引入一个starter外其他什么也没有做但是呢SpringBoot就自动完成了Redis的配置将相关的Bean对象注册到IOC容器中了。那么SpringBoot是如何做到这一点的呢这就是这篇博客所要说明的问题了。 2. 自动配置一切从注解SpringBootApplicaiton说起
SpringBootApplication注解 下面我们逐步分析EnableAutoConfiguration的自动配置
Target({ElementType.TYPE})
Retention(RetentionPolicy.RUNTIME)
Documented
Inherited
AutoConfigurationPackage
Import({AutoConfigurationImportSelector.class})
public interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY spring.boot.enableautoconfiguration;Class?[] exclude() default {};String[] excludeName() default {};
}AutoConfigurationImportSelector.class的selectImports方法
Override
public String[] selectImports(AnnotationMetadata annotationMetadata){if(!isEnabled(annotationMetadata))return NO_IMPORTS;AutoConfigurationMetadata autoConfigurationMetadata AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);//SpringBoot自动配置的入口方法AutoConfigurationEntry autoConfigurationEntry getAutoConfigurationEntry(autoConfigurationMetadata, annotationErtadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());selectImports方法中引用的getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata){//1. 获取annotationMetadata的注解EnableAutoConfiguration的属性AnnotationAttributes attributes getAttributes(annotationMetadata);//2. 从资源文件Spring.factories中获取EnableAutoConfiguration对应的所有的类ListString configurations getCandidateConfigurations(annotationMetadata, attributes);//3. 通过在注解EnableAutoConfiguration设置exclude的相关属性可以排除指定的自动配置类SetString exclusions getExclusions(anntationMetadata, attributes);checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);//4. 根据注解Conditional来判断是否需要排除某些自动配置类configurations filter filter(configurations, autoConfigurationMetadata);//5. 触发AutoConfiguration导入的相关事件fireAutoCOnfigurationImportEvents(configurations, exclusions);return new AutofigurationEntry(configurations, exclusions);
}getAutoConfigurationEntry引用的getCandidateConfigurations
protected ListString getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes){//通过SpringFactories机制从配置文件Spring.factories中找出所有的自动配置类ListString configurations SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, getBeanClassLoader());Assert.notEmpty(configurations,No auto configuration classes found);return configurations;
}SpringFactoriesLoader.loadFactoryNames方法调用loadSpringFactories方法从所有的jar包中读取META-INF/spring.factories文件信息。 // 参数// Class? factoryType需要被加载的工厂类的class// ClassLoader classLoader类加载器public static ListString loadFactoryNames(Class? factoryType, Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse classLoader;if (classLoaderToUse null) {// 若没传入类加载器使用该本类的类加载器classLoaderToUse SpringFactoriesLoader.class.getClassLoader();}// class.getName():获取该类的全类限定名字String factoryTypeName factoryType.getName();// loadSpringFactories(classLoaderToUse) 返回是Map// Map.getOrDefault(A,B): A为Key从Map中获取Value若Value为Null则返回B 当作返回值return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());}loadSpringFactories方法调用ClassLoader.getSystemResources获取META-INF/spring.factories文件
private static MapString, ListString loadSpringFactories(Nullable ClassLoader classLoader) {MultiValueMap result (MultiValueMap)cache.get(classLoader);if(result ! null) {return result;} else {try {Enumeration ex classLoader ! null?classLoader.getResources(META-INF/spring.factories):ClassLoader.getSystemResources(META-INF/spring.factories);LinkedMultiValueMap result1 new LinkedMultiValueMap();while(ex.hasMoreElements()) {URL url (URL)ex.nextElement();UrlResource resource new UrlResource(url);Properties properties PropertiesLoaderUtils.loadProperties(resource);Iterator var6 properties.entrySet().iterator();while(var6.hasNext()) {Entry entry (Entry)var6.next();List factoryClassNames Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));result1.addAll((String)entry.getKey(), factoryClassNames);}}cache.put(classLoader, result1);return result1;} catch (IOException var9) {throw new IllegalArgumentException(Unable to load factories from location [META-INF/spring.factories], var9);}}}下面是spring-boot-autoconfigure这个jar中spring.factories文件部分内容选择带有EnableAutoConfiguration自动配置类。
org.springframework.boot.autoconfigure.AutoConfigurationImportListener\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter\
org.springframework.boot.autoconfigure.condition.OnClassCondition# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\六、Spring SPI机制与Spring Factories机制做对比
联系Spring Factories自动装配借用了SPI机制SPI机制本身就是一种思想不是特定的技术。区别如下
七、这里是给我自己提个醒
META-IF/spring.factories是在Maven引入的Jar包中每一个Jar都有自己META-IF/spring.factories所以SpringBoot是去每一个Jar包里面寻找META-IF/spring.factories而不是我的项目中存在META-IF/spring.factories当然也可以存在但是我项目的META-IF/spring.factories肯定没有类似以下这些东西