Spring-Boot中有很多Enable開頭的注解,通過添加注解來開啟一項功能,如
其原理是什么?如何開發自己的Enable注解?
1.原理
以@EnableScheduling為例,查看其源碼,發現添加了一個@Import注解
繼續查看@Import注解源碼,發現其是由Spring提供的,用來導入配置類的,在配置類中定義的Bean(@Bean),可通過@Autowired注入到容器中,也就是可以被掃描到
2.自定義
了解了Enable注解的原理,我們就可以開發自己的Enable注解了,下面的例子實現了通過@Enable注解方式開啟服務器負載監控的功能
2.1 定義定時任務類
package com.yc.dudu.common.monitor; import com.alibaba.fastjson.JSONObject; import com.sun.management.OperatingSystemMXBean; import com.yc.dudu.common.constant.CommonConstants; import com.yc.dudu.common.util.DateTimeUtil; import com.yc.dudu.common.vo.ServerMonitorInfo; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import java.io.File; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.UnknownHostException; /** * 收集服務器負載信息 * * @author zhya * @date 2018/9/20 **/ @Slf4j @EnableScheduling public class ServerLoadMonitorRunner implements CommandLineRunner { /** * 自定義log,輸出服務器負載信息到日志文件 */ private static final Logger monitorLog = LoggerFactory.getLogger("serverMonitorLog"); /** * 系統信息 */ private static final OperatingSystemMXBean mem = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); /** * 收集服務器負載信息並輸出到日志文件 */ @Scheduled(cron = "*/5 * * * * ?") public void collectServerSystemLoad() { try { // 輸出json格式的信息到文件 monitorLog.info(JSONObject.toJSONString(new ServerMonitorInfo(InetAddress.getLocalHost().getHostName(), String.valueOf(mem.getFreePhysicalMemorySize() / CommonConstants.BYTES_TO_MB), String.valueOf(mem.getSystemCpuLoad()), String.valueOf(File.listRoots()[0].getFreeSpace() / CommonConstants.BYTES_TO_MB), DateTimeUtil.getNowDateTimeStr()))); } catch (UnknownHostException e) { log.error(e.getMessage()); } } /** * Callback used to run the bean. * * @param args incoming main method arguments * @throws Exception on error */ @Override public void run(String... args) throws Exception { try { collectServerSystemLoad(); } catch (Exception e) { log.error(e.getMessage()); // 不做處理,繼續運行 } } }
2.2 定義配置類,其中聲明定時任務Bean
package com.yc.dudu.common.monitor; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.annotation.PostConstruct; /** * 服務器負載監控自動配置類 * * @author zhya * @date 2018/09/20 **/ @Configuration public class ServerLoadMonitorAutoConfig { /** * 是否開啟監控配置參數 */ @Value("${monitor.server.enabled:}") private String enabledConfig; /** * 錯誤提醒 */ @PostConstruct protected void init() { if (StringUtils.isBlank(enabledConfig)) { System.err.println("~~~Please config the monitor.server.enabled property in application.yml file to enable server monitor function~~~"); } } /** * 根據運行環境決定是否開啟服務器負載信息監控 * * @return */ @Bean @ConditionalOnProperty(prefix = "monitor.server", name = "enabled", havingValue = "true") protected ServerLoadMonitorRunner startServerMonitor() { return new ServerLoadMonitorRunner(); } }
2.3 定義自己的Enable注解,Import 配置類
package com.yc.dudu.common.monitor; import org.springframework.context.annotation.Import; import java.lang.annotation.*; /** * 服務器負載監控開啟注解 * * @author zhya * @date 2018/09/20 **/ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(ServerLoadMonitorAutoConfig.class) @Documented @Inherited public @interface EnableServerLoadMonitor { }
2.4 使用自定義的EnableServerLoadMonitor注解,配合着配置參數,就可以開啟服務器負載監控功能了
package com.yc.dudu.gate.admin; import com.yc.dudu.auth.client.EnableDuduAuthClient; import com.yc.dudu.common.monitor.EnableServerLoadMonitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import zipkin2.Span; import zipkin2.reporter.Reporter; /** * admin網關啟動類 * * @author zhya * @date 2018/9/20 **/ @EnableHystrix @EnableServerLoadMonitor @SpringBootApplication @EnableDiscoveryClient @EnableDuduAuthClient @EnableFeignClients({"com.yc.dudu.auth.client.feign", "com.yc.dudu.gate.admin.feign"}) public class AdminGatewayApplication { public static void main(String[] args) { SpringApplication.run(AdminGatewayApplication.class, args); System.out.println("AdminGatewayApplication is started!~~~~~~~~"); } /** * 鏈路跟蹤信息輸出log */ private static Logger sleuthLog = LoggerFactory.getLogger("sleuthLog"); /** * 將鏈路跟蹤信息輸出到日志文件 * * @return */ @Bean public Reporter<Span> spanReporter() { Reporter<Span> reporter = span -> sleuthLog.info(span.toString()); return reporter; } }