背景

惯例要讲一下背景,毕竟问题来源于生活,困难滋生于工作,要是每天吃吃喝喝、无忧无虑,我相信我也没什么问题好写了^_^公司架构组在推新的基础框架,主要是嫌以前的框架用起来太啰嗦了,做了很多感觉多余的工作(思想也是在进步滴)。正好我这边也在做中台服务的下沉和重构,用到了索性就直接接新的框架了,老是用陈年的东西不肯升级,都快觉得自己已经七老八十了,咱要有互联网人的与时俱进的思维,出了问题大不了删库跑路~~~开玩笑哈。

问题

进入正题,问题就来源于这里,引了新的jar包后,大致浏览了一遍对接文档,发现确实要做的工作很少,把核心bean用spring的注入方式引进去就可以拿来用了。类似于下面这样:

@Autowired
private Template template;

然后就可以拿着template做一些不可描述的事情

三下五除二我写完了代码,想着总不能干坐着吧,显得工作不饱满呀,研究一下架构组的框架吧。看着看着还真看出了问题(我以为的问题),我的工程是springboot工程,这个Template为啥可以自动注入进来,所在的包路径明明没有被我配置啊。我们知道,springboot是有自动加载bean到context的配置的,前提是标注@SpringBootApplication的启动类所在的包是bean所在包的父包。有点绕口,总结来说,一般我们把启动类放在根包下,其他的类都在子包下,那其他所有自己写的类就都能自动加载了。但是三方jar的包路径明显跟自己定义的不一样,为啥也能自动加载呢?翻了一遍jar包中的所有类也没找到什么特殊的配置,百思不得其解。说来也巧,问题都是扎推来的,老项目在啥都没改的情况突然不能启动了,报spring的bean命名冲突,也就是容器内存在同名类,一查两个不同三方包内的bean重名了,纳尼?这种问题为啥现在突然爆出来,而且三方包如果所有的bean都自动加载的话,重名根本不是自己能控制的呀。感觉跟前一个是同一问题,就是为啥spring能自动加载三方jar中的bean,各种查资料,终于被我找到了答案,一看也没多高深,就是自己以前没接触过。。。

原因

我们知道,java有一个spi机制,在jar包的META-INF/services/目录里创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader。

这里spring的实现其实与java的spi类似(不知道是不是参考了),在META-INF下创建一个spring.factories文件,像下面这样,然后spring-core包里定义了SpringFactoriesLoader类,这个类实现了检索META-INF/spring.factories文件,并获取指定接口的配置的功能。

// spring实现的检索META-INF/spring.factories文件的方法
public static <T> List<T> loadFactories(Class<T> factoryClass, ClassLoader classLoader) {Assert.notNull(factoryClass, "'factoryClass' must not be null");ClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);if (logger.isTraceEnabled()) {logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);}List<T> result = new ArrayList<T>(factoryNames.size());for (String factoryName : factoryNames) {result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));}AnnotationAwareOrderComparator.sort(result);return result;
}public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {String factoryClassName = factoryClass.getName();try {Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));List<String> result = new ArrayList<String>();while (urls.hasMoreElements()) {URL url = urls.nextElement();Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));String factoryClassNames = properties.getProperty(factoryClassName);result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));}return result;}catch (IOException ex) {throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);}
}

注意,这里是会查找所有的classpath下的jar包中的spring.factories文件的,spring自己本身的starter机制就是以此为基础实现的。至于这个文件内容到底是怎样的,我们需要怎么配置呢?以spring-boot-autoconfigure为例,下面就是其中的spring.factories文件,这个文件还有其他的作用,我们主要关注Auto Configure模块。

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer# 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.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,\
org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,\
org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,\
org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,\
org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,\
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,\
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,\
org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,\
org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,\
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,\
org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,\
org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,\
org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,\
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
org.springframework.boot.autoconfigure.velocity.VelocityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.velocity.VelocityTemplateAvailabilityProvider,\
org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider

如果想要自己实现的jar包被别人依赖的时候能够自动配置,可以仿照该文件写一个,第一行是自动配置的一个注解,然后每一行都是自己定义的一个配置类,比如开头我提到的包自动扫描的功能,只要我在新建一个配置类

@ComponentScan("cn.jjs.demo")
public class DemoAutoConfiguration {
}

然后把这个类加到META/INF下的spring.factories文件中去,像下面这样,这样就可以自动扫描cn.jjs.demo包了,不需要引用方额外配置

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.jjs.demo.DemoAutoConfiguration

结语

不探索还真发现不了编程之美,有时候刨根问题能够带来不一样的收货,说不定爱上了代码,然后就是步步高升,迎娶白富美,走上人生巅峰。

针对这种三方jar能够自动配置bean的情况,如果重名了咋办呢?因为这也不是自己能控制的,所以需要我们手动排除,如果确实两个bean都需要用到,那就另外取一个名字,类似下面这样:

@SpringBootApplication
// 这里通过类型在扫描中排除了A这个类
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = A.class)})
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
// 这里通过配置A的别名解决重名冲突,spring默认会拿方法名作为beanName
@Configuration
public class AutoConfig {@Beanpublic A anotherA() {return new A();}
}

本文由博客一文多发平台 OpenWrite 发布!

关于spring自动加载的那点事儿相关推荐

  1. spring的applicationContext.xml如何自动加载

    一个web工程自动加载的配置文件只有web.xml,想要加载其他.xml必须在web.xml里面进行配置. 用spring的时候需要一个bean容器来管理所有的bean,所有bean默认是写在appl ...

  2. Spring Boot 自动加载指定包下的拦截器

    Spring Boot 在我们需要对程序添加拦截器需要使用 WebMvcConfigurerAdapter 中的 addInterceptors方法去注册拦截器,这样我们如果在程序里面有多个拦截或者我 ...

  3. Spring Boot加载配置文件

    问题1:Spring如何加载配置,配置文件位置? 1.默认位置: Spring Boot默认的配置文件名称为application.properties,SpringApplication将从以下位置 ...

  4. spring security加载原理(基于springboot)

    一.基本架构 二.自动配置原理 依据 Spring Boot 自动配置原理,其会自动加载spring-boot-autoconfigure.jar中/META-INF/spring.factories ...

  5. spring 启动加载数据_12个很棒的Spring数据教程来启动您的数据项目

    spring 启动加载数据 Spring Data的任务是为数据访问提供一个熟悉且一致的,基于Spring的编程模型,同时仍保留基础数据存储的特​​殊特征. 它使使用数据访问技术,关系和非关系数据库, ...

  6. org.xml.sax.SAXParseException: Failed to read schema document错误的完美解决方法 以及 Spring如何加载XSD文件

    有时候你会发现过去一直启动正常的系统,某天启动时会报出形如下面的错误: org.xml.sax.SAXParseException: schema_reference.4: Failed to rea ...

  7. web.xml的contextConfigLocation作用及自动加载applicationContext.xml

    web.xml的contextConfigLocation作用及自动加载applicationContext.xml 转自:http://blog.csdn.net/sapphire_aling/ar ...

  8. springboot是如何实现配置文件自动加载的呢

    springboot提倡: 约定大于配置 springboot最常见的面试题: 1.springboot是如何实现自动加载配置呢? 2.如何写一个starter呢? 带着问题,我们以mybatis-s ...

  9. ajax自动加载blogjava和博客园的rss

    自动加载blogjava和博客园的rss <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"   "h ...

最新文章

  1. 机甲才是男人的浪漫 这款Python版免费战争机甲类游戏,“白拿党”还在等什么?(超帅气)
  2. vue图片懒加载插件vue-lazyload
  3. python项目代码量_python统计项目代码行数
  4. mysql数据库从删库到跑路之mysq索引
  5. 传统 Ajax 已死,Fetch 永生
  6. ASP.NET--窗体实现淡入淡出效果
  7. 解析json结构绘制canvas
  8. Nginx 服务器安装及配置文件详解
  9. 普通美国人英语词汇量多少?
  10. python经纬度转换xy坐标公式_python 经纬度和平面坐标相互转换利用米勒坐标系
  11. 【String类】StringBuffer类 StringBuilder类
  12. ‘VBE6EXT.OLB’ 不能被加载
  13. 股票中什么是总负债同比增长率,有什么作用
  14. vue 引入萤石视频
  15. 【Photoshop实用教程】如何用魔术棒工具替换背景?
  16. https安全证书提示证书风险怎么办
  17. 机器学习实战——人脸表情识别
  18. 如何设计一个积分领取系统
  19. 使用ArcGIS为tif影像生成tfw文件
  20. 我的计算机专业作文,我的专业作文 我是计算机专业

热门文章

  1. 深度学习原理-----逻辑回归算法
  2. Docker之镜像操作
  3. RSA双向加解密(公钥加密-私钥解密;私钥加密-公钥解密)
  4. “恋爱”,一路走来,
  5. 动态时间规整matlab和python代码
  6. 开始使用spring
  7. 压电加速度传感器的结构原理详解
  8. Mathtype 自动转 latex bug 修复(更改编译文件)
  9. php苹果内购验证,苹果内购凭据验证工具(苹果支付,苹果内购,凭据解析)
  10. 小白进阶之文档快速比较功能 --- 比较两个文档并标记