自定义Spring-Boot @Enable注解
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; } }