您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關使用springboot怎么實現自動配置,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
springboot一種全新的編程規范,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程,SpringBoot也是一個服務于框架的框架,服務范圍是簡化配置文件。
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>2.1.7.RELEASE</version> </dependency> </dependencies>
然后,在application.properties中配置redis屬性
spring.redis.port=6379 spring.redis.host=localhost spring.redis.database=0
然后,在啟動類中注入redisTemplate類,redisTemplate為spring官方提供的對redis底層開發包(例如jedis)進行了深度封裝的組件,使用redisTemplate可以優雅的操作redis。我在啟動類中寫了一個測試方法,向redis寫入一條數據
@RequestMapping("/redistest") public String test(){ redisTemplate.opsForSet().add("aaaaa","123456"); return "OK"; }
運行這個方法,打開redis客戶端可以看到值已經寫入了
先拋開這里的鍵和值讓人看不懂的問題,大家是不是覺得springboot整合redis要比普通的springmvc整合redis簡單多了?我只配置了redis的連接地址,端口號,注入了redisTemplate,就能開始操作redis了,那么springboot底層到底做了些什么使得整合變得如此的簡單了呢。
首先我們來看,springboot啟動類上都有一個@SpringbootApplication注解,那么這個注解是起什么作用的呢,讓我們點進去看一下
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication
可以看到SpringbootApplication這個注解是由一系列的注解組合而成,這其中最重要的是@EnableAutoConfiguration和@ComponentScan,@ComponentScan的意思就是組件掃描注解,這個注解會自動注入所有在主程序所在包下的組件。比@ComponentScan注解更重要的就是@EnableAutoConfiguration注解了,這個注解的含義就是開啟自動裝配,直接把bean裝配到ioc容器中,@EnableAutoConfiguration也是一個組合注解,我們點進去看一下
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration
這個地方我們主要看@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)兩個注解,首先來看@AutoConfigurationPackage注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Import(AutoConfigurationPackages.Registrar.class) public @interface AutoConfigurationPackage { }
這個注解主要是獲取我們注解所在包下的組件去進行注冊,大家看到這個@Import注解,那么這個注解是什么含義呢,
@Import注解用來導入@Configuration注解的配置類、聲明@Bean注解的bean方法、導入ImportSelector的實現類或導入ImportBeanDefinitionRegistrar的實現類,這里這個AutoConfigurationPackages.Registrar.class就是ImportBeanDefinitionRegistrar的實現類,來看下源碼
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { //metadata是注解的元信息 registry是bean定義的注冊器 @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //把注解所在的包下所有的組件都進行注冊 register(registry, new PackageImport(metadata).getPackageName()); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImport(metadata)); } } public static void register(BeanDefinitionRegistry registry, String... packageNames) { //首先判斷這個bean有沒有被注冊 if (registry.containsBeanDefinition(BEAN)) { //獲取bean定義 BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN); //通過bean定義獲取構造函數值 ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues(); //給構造函數添加參數值 constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames)); } else { //一個新的bean定義 GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); //設置beanClass為beanPackages類型 beanDefinition.setBeanClass(BasePackages.class); beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); //bean注冊 registry.registerBeanDefinition(BEAN, beanDefinition); } }
接下來就是@Import(AutoConfigurationImportSelector.class)這個注解,我們來看看AutoConfigurationImportSelector這個類,這個類是我們自動裝配的導入選擇器,首先看這個類的第一個方法,其實也就是這個類的核心方法
@Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } //加載元數據 AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); //獲得自動裝配的實體 AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); }
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, 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 = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); }
在這部分中,核心方法是getCandidateConfigurations,我們來看下這個方法
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { //從工廠中獲取自動配置類 List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); //這句斷言很重要,告訴了我們工廠是去哪里找自動配置類的,這里顯然META-INF/spring.factories是一個路徑 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; }
那我們就找一下這個路徑,去哪里找呢,我們看到這個類的包是org.springframework.boot.autoconfigure;那我們就到這個包的位置去找這個spring.factories,果不其然,我們點開這個文件
我們看到文件中有一行注釋這Auto configure,表示這些都是自動配置相關的類,這里我們不得不說spring框架真的是強大,這里面居然有100多個自動配置類,我們找到redis有關的自動配置類
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\
這里我們需要的肯定是第一個自動配置類,我們點進去看看
@Configuration //條件注解,某個class位于類路徑上,才會實例化一個Bean,這個類是redis操作的類 @ConditionalOnClass(RedisOperations.class) //使得@ConfigurationProperties 注解的類生效,這個類是配置redis屬性的類 @EnableConfigurationProperties(RedisProperties.class) //導入一些配置 @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }) public class RedisAutoConfiguration { @Bean //僅僅在當前上下文中不存在某個對象時,才會實例化一個Bean,這個就是spring默認的redisTemplate @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; } }
我們在application.properties中配置的redis屬性,其實就是設置到了這個類中
//前綴spring.redis @ConfigurationProperties(prefix = "spring.redis") public class RedisProperties { /** * Database index used by the connection factory. */ private int database = 0; /** * Connection URL. Overrides host, port, and password. User is ignored. Example: * redis://user:password@example.com:6379 */ private String url; /** * Redis server host. */ private String host = "localhost"; /** * Login password of the redis server. */ private String password; /** * Redis server port. */ private int port = 6379; /** * Whether to enable SSL support. */ private boolean ssl; /** * Connection timeout. */ private Duration timeout; private Sentinel sentinel; private Cluster cluster; private final Jedis jedis = new Jedis(); private final Lettuce lettuce = new Lettuce(); }
我們前面說了,用了spring默認的redisTemplate操作redis的話,存到redis里的數據對我們的閱讀不友好,我們看不懂,那是因為redisTemplate中默認用了jdk自帶的序列化器
要想讓數據變成我們能看得懂的樣子,我們需要替換掉redisTempalte默認的序列化器,現在我就來實操一下,寫一個配置類
@Configuration public class RedisConfig { //這里的上下文已經有了自定義的redisTemplate,所以默認的redisTemplate不會生效 @Bean public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>(); //設置自定義序列化器 redisTemplate.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class)); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } }
然后我改寫一下測試方法,一起來看結果
public String test(){ redisTemplate.opsForSet().add("ffffff","55555555"); return "OK"; }
關于使用springboot怎么實現自動配置就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。