为了账号安全,请及时绑定邮箱和手机立即绑定

SpringBoot 中 AutoConfiguration的使用

标签:
Java
在SpringBoot中我们经常可以引入一些starter包来集成一些工具的使用,比如spring-boot-starter-data-redis。
使用起来很方便,那么是如何实现的呢?

代码分析

我们先看注解@SpringBootApplication,它里面包含一个@EnableAutoConfiguration
继续看@EnableAutoConfiguration注解
@Import({AutoConfigurationImportSelector.class})
在这个类(AutoConfigurationImportSelector)里面实现了自动配置的加载

主要代码片段:
String[] selectImports(AnnotationMetadata annotationMetadata)方法中
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
	
getAutoConfigurationEntry方法中:	
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
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
                LinkedMultiValueMap result = new LinkedMultiValueMap();

                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中加入
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.fayayo.fim.zookeeper.ZookeeperAutoConfiguration
接下来我们看看具体的实现:

@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部分实现:
 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呢
	首先要在需要使用的项目中引入依赖
	    <dependency>
            <groupId>com.fayayo</groupId>
            <artifactId>fim-registry-zookeeper</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    然后配置参数
	fim:
      register:
        address: 192.168.88.129:2181
        timeout: 2000
    如果不配置会有默认的参数 

    具体使用的时候只需要在Bean中注入就可以了,比如
	@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
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
6396
获赞与收藏
157

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消