背景
由于最近交付项目,甲方使用了SOFA这套体系,之前虽然有过一些了解,但是真正实战还是没有那么熟悉,因此搭建一个实战的demo,熟悉一下相关内容。
SOFA SIMALE DEMO
项目搭建
项目目录结构
如上图所示,sofa-common可以定义api接口,sofa-provider作为服务提供者,sofa-consumer为服务消费者。
代码传送门:https://gitee.com/kevin1992/sofa-demo.git
公共API
public interface HelloService {
String test(String name);
}
@Path("/rest-api")
public interface HttpService {
@Path("/test")
@GET
String test();
}
需要注意接口定义,如果是bolt,dubbo协议,接口跟普通接口无异,不需要任何处理。
如果是rest协议,就需要结合JAXRS注解定义接口,JAXRS注解需要单独引jar包。
服务提供者
@SofaServiceBean(interfaceType = HelloService.class, bindings = @SofaServiceBinding(bindingType = "bolt"))
public class HelloServiceImpl implements HelloService {
@Override
public String test(String name) {
return "hello, " + name;
}
}
@SofaService(interfaceType = HttpService.class, bindings = {@SofaServiceBinding(bindingType = "rest")})
@Service
public class HttpServiceImpl implements HttpService {
@Override
public String test() {
return "success";
}
}
服务调用者
写一个controller,调用相关服务,使用@SofaReference注解引入即可。
@RequestMapping("/test")
@RestController
public class ConsumerController {
@SofaReference(interfaceType = HelloService.class, binding = @SofaReferenceBinding(bindingType = "bolt"))
private HelloService helloService;
@SofaReference(interfaceType = HttpService.class, binding = @SofaReferenceBinding(bindingType = "rest"))
private HttpService httpService;
@GetMapping("/bolt")
public String test() {
return helloService.test("java");
}
@GetMapping("/rest")
public String testRest() {
return httpService.test();
}
}
注意事项
注册中心
本案例使用的zk,所以服务提供者和消费者application.properties都需要增加注册中心的配置
com.alipay.sofa.rpc.registry.address=zookeeper://127.0.0.1:2181
当然,它还支持其他的几种常见注册中心,这里不一一赘述。可以查看官方文档:https://www.sofastack.tech/projects/sofa-rpc/registry-sofa/
关于注解
第一种方法
服务调用者使用@SofaService和Spring的@Service同时使用,否则不会自动注入Spring Bean。
第二种方法
直接使用Sofa提供的复合注解@SofaServiceBean,因为这个注解源码可以看到使用到了@Component
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@SofaService
@Component
public @interface SofaServiceBean {
@AliasFor(
annotation = Component.class
)
String value() default "";
@AliasFor(
annotation = SofaService.class
)
Class<?> interfaceType() default void.class;
@AliasFor(
annotation = SofaService.class
)
String uniqueId() default "";
@AliasFor(
annotation = SofaService.class
)
SofaServiceBinding[] bindings() default {@SofaServiceBinding};
}
其他xml和api也都是支持的,具体参考官方文档。
rest协议
默认的服务发布端口是8341,服务启动成功就可以浏览器访问
http://localhost:8341/rest-api/test
项目启动问题
由于使用了java17的版本会报错,如下:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @69453e37
原因是高版本jdk对jdk8反射使用的限制导致的,只需要在idea启动服务的时候加入一下jvm参数即可:
--add-opens java.base/java.lang=ALL-UNNAMED
idea如图: