全量刷新上下文代码示例:
package com.kfyty.demo;
import com.kfyty.loveqq.framework.boot.K;
import com.kfyty.loveqq.framework.boot.context.ContextRefresher;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnProperty;
import com.kfyty.loveqq.framework.core.autoconfig.env.PropertyContext;
import com.kfyty.loveqq.framework.core.utils.IOC;
import com.kfyty.loveqq.framework.web.core.annotation.GetMapping;
import com.kfyty.loveqq.framework.web.core.annotation.RestController;
import com.kfyty.loveqq.framework.web.core.autoconfig.annotation.EnableWebMvc;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@EnableWebMvc
@RestController
@BootApplication
public class Main {
public static void main(String[] args) throws Exception {
K.run(Main.class, args);
}
@Autowired
private UserService userService;
@Autowired
private PropertyContext propertyContext;
/**
* 调用接口方法
*/
@GetMapping
public String sayHello() {
return userService.hello();
}
/**
* 通过可刷新的配置属性切换 UserService 实现类
*
* @param impl 条件配置属性
*/
@GetMapping
public String switchUserImpl(String impl) {
// 设置可刷新的属性,刷新上下文时不会丢失
propertyContext.setRefreshProperty("user.service.impl", impl);
// 全量刷新上下文,由于类已加载,刷新过程会很快
ContextRefresher.refresh(IOC.getApplicationContext());
// 刷新是异步的,这里返回页面提示
return "ok";
}
/**
* 接口定义
*/
public interface UserService {
String hello();
}
/**
* 扩展实现
*/
@Component
@ConditionalOnProperty(value = "user.service.impl", havingValue = "extension")
public static class ExtensionUserService extends DefaultUserService {
@Override
public String hello() {
return "internal";
}
}
/**
* 默认实现
*/
@Component
@ConditionalOnProperty(value = "user.service.impl", havingValue = "default", matchIfMissing = true)
public static class DefaultUserService implements UserService {
@Override
public String hello() {
return "default";
}
}
}
上述代码启动 main 方法后:
- 先访问:http://localhost:8080/sayHello,将返回 default
- 然后访问:http://localhost:8080/switchUserImpl?impl=internal,此时将进行ioc容器的全量刷新
- 然后再访问:http://localhost:8080/sayHello,将返回 internal,原因是条件注解生效,实现类变化了!
从而实现了热更新类实现,这是 @RefreshScope 注解所无法实现的效果。
并且由于是热更新,所以ioc容器的刷新很快完成(ms 级别),相比重新启动耗时更短。