在没有使用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
最后访问测试: