在沒有使用SpringBoot以前,使用ssm時配置redis須要在XML中配置端口號,地址,帳號密碼,鏈接池等等,而使用了SpringBoot後只須要在application.yml或application.properties中配置信息,而後在pom文件添加一個Redis的start就能夠用了java
什麼是自動裝配,也就是說幫你把須要的類自動添加到Spring容器中redis
只要是一個SpringBoot項目確定有這樣一個類spring
@SpringBootApplication public class MyApplication { public static void main(String[] args) { SpringApplication.run(TokenApplication.class, args); } }
而自動裝配是在@SpringBootApplication
這個註解中實現的,點進去首先能看到這個註解上還有三個類緩存
@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication {}
其中SpringBootConfiguration上還有一個註解@Configuration
也就是說明其實SpringBootApplication也是一個配置類springboot
@ComponentScan用於掃描須要被Spring管理的類,這也就是爲何寫的類須要在SpringBoot啓動類同級或在同級下的子包中app
@EnableAutoConfiguration點進去發現它上面有一個特殊的註解@Import(AutoConfigurationImportSelector.class)
maven
@Import註解的做用是將指定類添加到Spring容器中成爲一個Beanide
而在AutoConfigurationSelector類中有自動裝配的實現spring-boot
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } //下面的方法 AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) { //獲取註解的名稱做爲key String name = getAnnotationClass().getName(); AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true)); Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName() + " annotated with " + ClassUtils.getShortName(name) + "?"); return attributes; }
其中咱們關注與返回值相關的代碼,也就是getCandidateConfigurations這個方法測試
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
繼續查看loadFactoryNames方法
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { //從META-INF/spring.factories中獲取配置文件 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
其中須要解釋一下的是:MultiValueMap[接口],它是一個特殊的Map,由SpringBoot本身寫的,查看它的實現類LinkedMultiValueMap
private final Map<K, List<V>> targetMap;
一般咱們使用的Map是一個<K,V>結構的,而它這個Map是一個<K,V V V ...>結構的
首先SpringBoot會從緩存中嘗試獲取(其實也就是個map,不過有點特殊),若是獲取不到,那就一次將所有內容讀取出來,而後以K V V V...的形式存放到類中
那麼META-INF/spring.factories這個文件在哪呢?
它裏面的內容是這樣的
以類的全限定名做爲Key,其餘類的全限定名做爲Value
那到如今仍是一頭霧水,讀到了這個有什麼用呢?咱們拿常見的Redis來看看
點進RedisAutoConfiguration看看
發現裏面全是報錯,由於我尚未導入Redis的start,當我在pom文件中添加redis的依賴後
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>1.4.1.RELEASE</version> </dependency>
發現不報錯了,使用RedisTemplate存取值也能夠了,這裏就再也不演示存取值
上面這個類主要看類上面的註解,主要的兩個爲:ConditionalOnClass
和EnableConfigurationProperties
@ConditionalOnClass
的做用是當前項目的classpath中存在某個類在會實例化這個類爲bean,Spring還提供了其餘相似的註解
那麼毫無疑問pom中導入的那個依賴中確定有一個類或接口叫作RedisOperations
,點進去查看它的包路徑
package org.springframework.data.redis.core;
咱們去導入的包中找一找
@EnableConfigurationProperties
註解是使@ConfigurationProperties
註解的類生效,點進註解上的類
@ConfigurationProperties
註解的做用是能夠將參數的配置設置在application配置文件中,咱們在application配置文件中配置的參數都配置類中的字段,要否則這些參數那來的?
那麼如今SpringBoot自動裝配的大體流程就完成了
@ConditionalOnxxxx
註解就將類添加到Spring容器中如今知道了SpringBoot是如何自動裝配的,掃描MEAT-INF下spring.factories文件,key爲:EnableAutoConfiguration,爲何key爲EnableAutoConfiguration呢?在上面的代碼中,掃描的以@EnableAutoConfiguration註解獲取名稱做爲key
首先建立一個Maven項目,導入依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>2.0.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.0.0.RELEASE</version> <optional>true</optional> </dependency> </dependencies>
以後在resources文件夾下建立META-INF/spring.factories文件
而後建立配置類 當代碼沒有寫完時@ConfigurationProperties會報錯:沒有開啓這個配置類,能夠暫時無論
建立服務類
建立自動注入的配置類
最後在spring.factories中添加自動裝配類
org.springframework.boot.autoconfigure.EnableAutoConfiguration= \com.jame.UserServiceAutoConfiguration //這裏替換成本身的類全路徑
整個項目結構以下
最後將maven項目 clean install 打包到當前maven倉庫中
在target輸出文件夾下打開cmd 直接在路徑框中輸入cmd直接打開當前位置
輸入命令
mvn install:install-file -Dfile=start-user-1.0-SNAPSHOT.jar -DgroupId=com.jame -DartifactId=user-spring-boot-start -Dversion=1.0 -Dpackaging=jar
完成後新建個SpringBoot項目來測試
導入剛纔打包的項目
配置參數
建立一個Controller來測試
這裏使用@Autowired idea可能會提示錯誤,說找不到對應的類型,這個是idea的問題
若是不想看着難受能夠設置:Setting->Editor->inspections->Spring Core->Core->AutoWring for bean class 將Error設置爲Waring
最後訪問測試: