SpringBoot 中 AutoConfiguration的使用方法

时间:2022-10-12 17:01:27

在springboot中我们经常可以引入一些starter包来集成一些工具的使用,比如spring-boot-starter-data-redis

使用起来很方便,那么是如何实现的呢?

代码分析

我们先看注解@springbootapplication,它里面包含一个@enableautoconfiguration

继续看@enableautoconfiguration注解

@import({autoconfigurationimportselector.class})

在这个类(autoconfigurationimportselector)里面实现了自动配置的加载

主要代码片段:

string[] selectimports(annotationmetadata annotationmetadata)方法中

?
1
autoconfigurationimportselector.autoconfigurationentry autoconfigurationentry = this.getautoconfigurationentry(autoconfigurationmetadata, annotationmetadata);

getautoconfigurationentry方法中: 

?
1
2
3
4
5
6
7
list<string> configurations = this.getcandidateconfigurations(annotationmetadata, attributes);
 
protected list<string> getcandidateconfigurations(annotationmetadata metadata, annotationattributes attributes) {
    list<string> configurations = springfactoriesloader.loadfactorynames(this.getspringfactoriesloaderfactoryclass(), this.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;
}

最后会通过springfactoriesloader.loadspringfactories去加载meta-inf/spring.factories

?
1
2
enumeration<url> urls = classloader != null ? classloader.getresources("meta-inf/spring.factories") : classloader.getsystemresources("meta-inf/spring.factories");
        linkedmultivaluemap result = new linkedmultivaluemap();
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
while(urls.hasmoreelements()) {
      url url = (url)urls.nextelement();
      urlresource resource = new urlresource(url);
      properties properties = propertiesloaderutils.loadproperties(resource);
      iterator var6 = properties.entryset().iterator();
 
      while(var6.hasnext()) {
        entry<?, ?> entry = (entry)var6.next();
        string factoryclassname = ((string)entry.getkey()).trim();
        string[] var9 = stringutils.commadelimitedlisttostringarray((string)entry.getvalue());
        int var10 = var9.length;
 
        for(int var11 = 0; var11 < var10; ++var11) {
          string factoryname = var9[var11];
          result.add(factoryclassname, factoryname.trim());
        }
      }
    }

zookeeperautoconfiguration

我们来实现一个zk的autoconfiguration    

首先定义一个zookeeperautoconfiguration类 

然后在meta-inf/spring.factories中加入

?
1
org.springframework.boot.autoconfigure.enableautoconfiguration=com.fayayo.fim.zookeeper.zookeeperautoconfiguration

接下来我们看看具体的实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@configurationproperties(prefix = "fim.register")
@configuration
public class urlregistry {
  private string address;
  private int timeout;
  private int sessiontimeout;
  public string getaddress() {
    if (address == null) {
      address = urlparam.address;
    }
    return address;
  }
  public void setaddress(string address) {
    this.address = address;
  }
  public int gettimeout() {
    if (timeout == 0) {
      timeout = urlparam.connecttimeout;
    }
    return timeout;
  }
  public void settimeout(int timeout) {
    this.timeout = timeout;
  }
  public int getsessiontimeout() {
    if (sessiontimeout == 0) {
      sessiontimeout = urlparam.registrysessiontimeout;
    }
    return sessiontimeout;
  }
  public void setsessiontimeout(int sessiontimeout) {
    this.sessiontimeout = sessiontimeout;
  }
}
@configuration
@enableconfigurationproperties(urlregistry.class)
@slf4j
public class zookeeperautoconfiguration {
  @autowired
  private urlregistry url;
  @bean(value = "registry")
  public registry createregistry() {
    try {
      string address = url.getaddress();
      int timeout = url.gettimeout();
      int sessiontimeout = url.getsessiontimeout();
      log.info("init zookeeperregistry,address[{}],sessiontimeout[{}],timeout[{}]", address, timeout, sessiontimeout);
      zkclient zkclient = new zkclient(address, sessiontimeout, timeout);
      return new zookeeperregistry(zkclient);
    } catch (zkexception e) {
      log.error("[zookeeperregistry] fail to connect zookeeper, cause: " + e.getmessage());
      throw e;
    }
  }
}

 zookeeperregistry部分实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public zookeeperregistry(zkclient zkclient) {
    this.zkclient = zkclient;
 
    log.info("zk register success!");
 
    string parentpath = urlparam.zookeeper_registry_namespace;
    try {
      if (!zkclient.exists(parentpath)) {
        log.info("init zookeeper registry namespace");
        zkclient.createpersistent(parentpath, true);
      }
      //监听
      zkclient.subscribechildchanges(parentpath, new izkchildlistener() {
        //对父节点添加监听子节点变化。
        @override
        public void handlechildchange(string parentpath, list<string> currentchilds) {
          log.info(string.format("[zookeeperregistry] service list change: path=%s, currentchilds=%s", parentpath, currentchilds.tostring()));
          if(watchnotify!=null){
            watchnotify.notify(nodechildstourls(currentchilds));
          }
        }
      });
 
      shutdownhook.registershutdownhook(this);
 
    } catch (exception e) {
      e.printstacktrace();
      log.error("failed to subscribe zookeeper");
    }
  }

具体使用

那么我们怎么使用自己写的zookeeperautoconfiguration呢

 首先要在需要使用的项目中引入依赖

?
1
2
3
4
5
<dependency>
   <groupid>com.fayayo</groupid>
   <artifactid>fim-registry-zookeeper</artifactid>
   <version>0.0.1-snapshot</version>
 </dependency>

    然后配置参数

?
1
2
3
4
fim:
  register:
   address: 192.168.88.129:2181
   timeout: 2000

   如果不配置会有默认的参数

    具体使用的时候只需要在bean中注入就可以了,比如

?
1
2
3
4
5
6
7
8
9
10
@autowired
  private registry registry;
  public list<url> getall(){
    list<url>list=cache.get(key);
    if(collectionutils.isempty(list)){
      list=registry.discover();
      cache.put(key,list);
    }
    return list;
  }

完整代码

https://github.com/lizu18xz/fim.git

总结

以上所述是小编给大家介绍的springboot 中 autoconfiguration的使用方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!
原文链接:https://www.imooc.com/article/285008