(1). 概述
能不能在Liquibase执行完成之后,再让我们的程序向注册中心(Eureka)进行注册呢(即服务正确初始化之后,再提供服务)?
答案是可以的,这里提供大概思路:
- 扩展EurekaAutoServiceRegistration.
- 接受到自定义Event后,才真正的触发向注册中心注册.
(2). 自定义事件(RegisterServiceStartEvent)
public class RegisterServiceStartEvent extends ApplicationEvent {
public RegisterServiceStartEvent(Object source) {
super(source);
}
}
(3). 禁用Spring的EurekaAutoServiceRegistration
package help.lixin.framework.eureka.serviceregistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
/**
* 禁用Spring自带的:EurekaAutoServiceRegistration,添加自定义的.
*/
public class DisableEurekaAutoServiceRegistrationProcessor implements BeanFactoryPostProcessor {
private Logger logger = LoggerFactory.getLogger(DisableEurekaAutoServiceRegistrationProcessor.class);
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof DefaultListableBeanFactory) {
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
String beanName = "eurekaAutoServiceRegistration";
boolean res = beanFactory.containsBeanDefinition(beanName);
if (res) {
defaultListableBeanFactory.removeBeanDefinition(beanName);
BeanDefinition eurekaAutoServiceRegistrationOverrideDefinition = new RootBeanDefinition(
EurekaAutoServiceRegistrationOverride.class);
((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(beanName, eurekaAutoServiceRegistrationOverrideDefinition);
logger.info("Override EurekaAutoServiceRegistration To EurekaAutoServiceRegistrationOverride SUCCESS");
} else {
logger.warn("Override EurekaAutoServiceRegistration To EurekaAutoServiceRegistrationOverride FAIL,description = applicationContext NOT FOUND beanName:[{}]", beanName);
}
res = beanFactory.containsBeanDefinition(beanName);
logger.info("Override EurekaAutoServiceRegistration To EurekaAutoServiceRegistrationOverride SUCCESS");
} else {
logger.warn("Override EurekaAutoServiceRegistration To EurekaAutoServiceRegistrationOverride FAIL,description = (ConfigurableListableBeanFactory !instanceof DefaultListableBeanFactory)");
}
}
}
(4). 扩展EurekaAutoServiceRegistration(EurekaAutoServiceRegistrationOverride)
public class EurekaAutoServiceRegistrationOverride extends EurekaAutoServiceRegistration {
private Logger logger = LoggerFactory.getLogger(EurekaAutoServiceRegistrationOverride.class);
private ApplicationContext context;
private EurekaRegistration registration;
private EurekaServiceRegistry serviceRegistry;
private AtomicInteger port = new AtomicInteger(0);
private AtomicBoolean running = new AtomicBoolean(false);
private AtomicBoolean register = new AtomicBoolean(false);
private Set<String> expectedEventTriggerRegister = new HashSet<>();
public EurekaAutoServiceRegistrationOverride(ApplicationContext context, EurekaServiceRegistry serviceRegistry,
EurekaRegistration registration, EurekaLazyRegisterProperties eurekaLazyRegisterProperties) {
super(context, serviceRegistry, registration);
this.context = context;
this.serviceRegistry = serviceRegistry;
this.registration = registration;
// clone
Set<String> clone = new HashSet<>();
clone.addAll(eurekaLazyRegisterProperties.getExpectedEventTriggerRegister());
expectedEventTriggerRegister = clone;
}
@Override
public void start() {
this.running.set(true);
logger.warn(
"Enable EurekaAutoServiceRegistration Override,Wait RegisterServiceStartEvent , Delay Register Service...");
}
public boolean isRunning() {
return running.get();
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return WebServerInitializedEvent.class.isAssignableFrom(eventType)
|| ContextClosedEvent.class.isAssignableFrom(eventType)
|| RegisterServiceStartEvent.class.isAssignableFrom(eventType);
}
public void onApplicationEvent(RegisterServiceStartEvent event) {
logger.info("revice RegisterServiceStartEvent,ready Register Service.");
// 获得事件源名称.
String eventName = (String) event.getSource();
// 移除事件
expectedEventTriggerRegister.remove(eventName);
// 移除事件之后,发现还存在要期待的事件,则返回,直到:expectedEventTriggerRegister里不存在事件,则进行注册.
if (!expectedEventTriggerRegister.isEmpty()) {
return;
}
if (this.port.get() != 0) {
if (this.registration.getNonSecurePort() == 0) {
this.registration.setNonSecurePort(this.port.get());
}
if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
this.registration.setSecurePort(this.port.get());
}
}
if (this.running.get() && this.registration.getNonSecurePort() > 0) {
this.serviceRegistry.register(this.registration);
this.context.publishEvent(new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
this.running.set(true);
// 标记注册完成
this.register.set(true);
}
}
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof WebServerInitializedEvent) {
onApplicationEvent((WebServerInitializedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onApplicationEvent((ContextClosedEvent) event);
} else if (event instanceof RegisterServiceStartEvent) {
onApplicationEvent((RegisterServiceStartEvent) event);
}
}
public Set<String> getExpectedEventTriggerRegister() {
return expectedEventTriggerRegister;
}
public AtomicBoolean getRegister() {
return register;
}
}
(5). 配置监听
监听的目的,主要是防止一直未向注册中心注册,需要打日志提醒.
public class EurekaAutoServiceRegistrationOverrideListener {
private Logger logger = LoggerFactory.getLogger(EurekaAutoServiceRegistrationOverrideListener.class);
private EurekaAutoServiceRegistration eurekaAutoServiceRegistration;
// 间隔多少秒执行一次.
private final long delay;
private volatile boolean isRunning = false;
public EurekaAutoServiceRegistrationOverrideListener(EurekaAutoServiceRegistration eurekaAutoServiceRegistration, long delay) {
this.delay = delay;
this.eurekaAutoServiceRegistration = eurekaAutoServiceRegistration;
Thread checkThread = new Thread(runnable());
checkThread.setDaemon(true);
checkThread.setName("EurekaAutoServiceRegistrationOverrideListener");
checkThread.start();
}
public Runnable runnable() {
return () -> {
while (!isRunning) {
if (eurekaAutoServiceRegistration instanceof EurekaAutoServiceRegistrationOverride) {
EurekaAutoServiceRegistrationOverride eurekaAutoServiceRegistrationOverride = (EurekaAutoServiceRegistrationOverride) eurekaAutoServiceRegistration;
Set<String> expectedEvents = eurekaAutoServiceRegistrationOverride.getExpectedEventTriggerRegister();
if (!eurekaAutoServiceRegistrationOverride.getRegister().get()) {
logger.warn("EurekaAutoServiceRegistration Register Service FAIL,Wait Events:[{}]", expectedEvents);
} else {
// 注册成功的情况下,当前的线程不要再执行了,不要浪费线程做无意义的事情.
isRunning = true;
}
}
try {
TimeUnit.SECONDS.sleep(delay);
} catch (InterruptedException ignore) {
}
}
};
}
}
(6). 发布事件,触发向注册中心注册
applicationContext.publishEvent(new RegisterServiceStartEvent("TriggerRegister"));
(7). 总结
由于Spring没有提供Hook的方式,对EurekaAutoServiceRegistration进行扩展,所以,只能偷梁换柱的先删除定义信息,再添加自定义的信息.