// 注意事项
// 1. 在需要使用SPI接口层,声明SPI注解
// 2. 依赖与上篇文章的Provider创建META-INF/dubbo目录
// 3. 配置文件名:com.ly.service.HelloService内容:hello=com.ly.service.impl.HelloServiceImpl
// 实现
public class SpiDubboMain {
public static void main(String[] args) {
// 获取扩展加载器
ExtensionLoader loader =
ExtensionLoader.getExtensionLoader(HelloService.class);
// 获取支持的拓展点\META-INF\dubbo
Set extensions = loader.getSupportedExtensions();
for(String ex:extensions) {
String spi = loader.getExtension(ex).sayHellow("spi");
System.out.println(spi);
}
}
}
// 注意事项
// 1. 可以自己指定在Consumer 还是 Provider
// 2. 新建工程 spi-filter
// 3. Filter接口全限定名: org.apache.dubbo.rpc.Filter
// 4. 创建META-INF/dubbo目录
// 5. 文件名:org.apache.dubbo.rpc.Filter
// 6. 内容: timefilter=com.leiyu.filter.DubboInvokeFilter
// 7. 指定了Consumer 即在Consumer工程加入spi-filter依赖
@Activate(group = {CommonConstants.CONSUMER})
public class DubboInvokeFilter implements Filter{
@Override
public Result invoke(Invoker> invoker, Invocation invocation) throws RpcException {
long startTime = 0 ;
try {
startTime = System.currentTimeMillis();
return invoker.invoke(invocation) ;
} finally {
System.out.println("invoke time : " +( System.currentTimeMillis() - startTime) + " 毫秒");
}
}
}
// 注意事项
// 1. 可以配置在Consumer 也可以配置在Provider, 采用dubbo自带的【看官网文档】
//在服务消费者一方配置负载均衡策略
@Reference(check = false,loadbalance = "random")
//在服务提供者一方配置负载均衡
@Service(loadbalance = "random")
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return "hello " + name;
}
}
// 2. 可以自定义负载均衡, 需要实现LoadBalance接口
// 配置负载均衡器 利用SPI机制, 创建META-INF/dubbo目录
// 文件名:org.apache.dubbo.rpc.cluster.LoadBalance
// 内容: onlyFirst=包名.负载均衡器
获取结果:RpcContext.getContext().getFuture() 来进行获取Future对象来进行后续的结果等待操作
dubbo中与java对应的线程池:
public class WachingThreadPool extends FixedThreadPool implements Runnable {
private final static Logger LOGGER = LoggerFactory.getLogger(WachingThreadPool.class) ;
// 定义线程池使用的阈值
private final static double ALANG_PERCENT = 0.90 ;
// 存储真正做线程池的对象
private final Map THREAD_POOLS = new ConcurrentHashMap<>() ;
// 每隔三秒报告线程池使用情况
public WachingThreadPool() {
Executors.newSingleThreadScheduledExecutor()
.scheduleWithFixedDelay(this,1, 3, TimeUnit.SECONDS) ;
}
// 通过父类方式创建线程池
@Override
public Executor getExecutor(URL url) {
final Executor executor = super.getExecutor(url);
if(executor instanceof ThreadPoolExecutor) {
THREAD_POOLS.put(url, (ThreadPoolExecutor) executor) ;
}
return executor ;
}
@Override
public void run() {
// 遍历线程池
for(Map.Entry entry:THREAD_POOLS.entrySet()) {
final URL url = entry.getKey();
final ThreadPoolExecutor executor = entry.getValue();
// 计算相关指标
// 拿到活动线程数
final int activeCount = executor.getActiveCount() ;
// 拿到总共线程数
final int size = executor.getCorePoolSize();
double useredPrecent = activeCount / (size * 1.0) ;
LOGGER.info("线程池执行状态: [{}/{}: {}%]", activeCount, size, useredPrecent*100);
if(useredPrecent > ALANG_PERCENT) {
LOGGER.error("超出警戒线! host: {} 当前使用率是: {}, URL: {}",
url.getIp(), useredPrecent, url);
}
}
}
}
2. 创建META-INF/dubbo目录
3. 创建文件: org.apache.dubbo.common.threadpool.ThreadPool 内容:
watching=com.ly.threadpool.WatchingThreadPool
4. 在Provider的xml配置文件中添加:
5. 在提供方加入dubbo-spi-threadpool工程依赖
6. 修改consumer施压:
public static void main(String[] args) throws IOException, InterruptedException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
context.start();
// 获取消费者组件
ConsumerComponent service = context.getBean(ConsumerComponent.class);
while(true) {
for (int i = 0; i < 1000; i++) {
Thread.sleep(6);
new Thread(new Runnable() {
@Override
public void run() {
String msg = service.say("watching", 0) ;
System.out.println(msg);
}
}).start();
}
}
}
1. 根据zookeeper获取注册中心配置
2. 可以实现动态配置
public class DubboRouterMain {
public static void main(String[] args) {
RegistryFactory
registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://127.0.0.1:2181"));
registry.register(URL.valueOf("condition://0.0.0.0/com.ly.service.HelloService?category=routers&force=true&dynamic=true&rule="
+ URL.encode("=> host != 192.168.23.1")));
}
}
route:// 表示示路由规则的类型,支持条件路由规则和脚本路由规则,可拓展
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?
category=configurators&dynamic=false
&application=foo&mock=force:return+null"));