在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