Spring集成smart-socket

现今的企业系统开发通常会使用Spring,smart-socket与Spring的集成就是一个基本的通信服务Bean实例托管的过程。

此处以xml配置和注解两种方式为大家介绍smart-socket于spring的集成方案,前期需要做的准备工作就是先搭建一个spring工程,并引入smart-socket依赖,pom.xml配置如下图。

1.2 Spring集成smart-socket - 图1

1. xml配置化启动服务

​ 通过2.1章节我们了解到smart-socket启用通信服务依赖两个关键的要素:Protocol、MessageProcessor,在spring的集成应用中我们依旧需要定义它们的实现类。接下来我们会以服务端场景为例给大家演示,如果您是要进行客户端通信服务与Spring的集成,请按同样的操作方式替换一下相应的配置即可。

  • 定义协议类
  1. public class StringProtocol implements Protocol<String> {
  2. @Override
  3. public String decode(ByteBuffer readBuffer, AioSession<String> session) {
  4. int remaining = readBuffer.remaining();
  5. if (remaining < Integer.BYTES) {
  6. return null;
  7. }
  8. readBuffer.mark();
  9. int length = readBuffer.getInt();
  10. if (length > readBuffer.remaining()) {
  11. readBuffer.reset();
  12. return null;
  13. }
  14. byte[] b = new byte[length];
  15. readBuffer.get(b);
  16. readBuffer.mark();
  17. return new String(b);
  18. }
  19. }
  • 定义处理器
  1. public class ServerProcessor implements MessageProcessor<String> {
  2. @Override
  3. public void process(AioSession<String> session, String msg) {
  4. WriteBuffer writeBuffer = session.writeBuffer();
  5. byte[] bytes = msg.getBytes();
  6. try {
  7. writeBuffer.writeInt(bytes.length);
  8. writeBuffer.write(bytes);
  9. } catch (IOException e) {
  10. e.printStackTrace();
  11. }
  12. }
  13. @Override
  14. public void stateEvent(AioSession<String> session, StateMachineEnum stateMachineEnum, Throwable throwable) {
  15. }
  16. }

准备工作就绪后,我们需要在application.xml配置它们的实例bean,并将其引用至AioQuickServer的bean配置。因为AioQuickServer的构造方法都是带参数的,所以配置bean的时候需要用到标签constructor-arg

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd">
  6. <bean name="protocol" class="org.smartboot.example.spring.StringProtocol"/>
  7. <bean name="messageProcessor" class="org.smartboot.example.spring.ServerProcessor"/>
  8. <bean name="aioQuickServer" class="org.smartboot.socket.transport.AioQuickServer" init-method="start" destroy-method="shutdown">
  9. <constructor-arg index="0" value="8080"/>
  10. <constructor-arg index="1" ref="protocol"/>
  11. <constructor-arg index="2" ref="messageProcessor"/>
  12. </bean>
  13. </beans>

当启动spring容器时,我们的通信服务便开始运行。接下来我们来验证一下集成后的效果,如果将其配置到真正的web服务中演示过程稍显琐碎,故我们直接通过main函数来调用。

  1. public class SpringDemo {
  2. public static void main(String[] args) {
  3. ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
  4. AioQuickServer aioQuickServer = context.getBean("aioQuickServer", AioQuickServer.class);
  5. System.out.println("服务启动成功:" + aioQuickServer);
  6. ((ClassPathXmlApplicationContext) context).close();
  7. System.out.println("服务关闭");
  8. }
  9. }

执行上述代码后控制台会打印服务的启动与关闭日志,如果出现异常,请检查端口号是否被占用。

2. 注解方式启动服务

如果读者习惯用注解的方式使用Spring,那我们需要对原有的代码稍加改动。Protocol和MessageProcessor实现类需要加上注解@Component

  • 定义协议类
  1. @Component("protocol")
  2. public class StringProtocol implements Protocol<String> {
  3. @Override
  4. public String decode(ByteBuffer readBuffer, AioSession<String> session) {
  5. int remaining = readBuffer.remaining();
  6. if (remaining < Integer.BYTES) {
  7. return null;
  8. }
  9. readBuffer.mark();
  10. int length = readBuffer.getInt();
  11. if (length > readBuffer.remaining()) {
  12. readBuffer.reset();
  13. return null;
  14. }
  15. byte[] b = new byte[length];
  16. readBuffer.get(b);
  17. readBuffer.mark();
  18. return new String(b);
  19. }
  20. }
  • 定义处理器
  1. @Component("messageProcessor")
  2. public class ServerProcessor implements MessageProcessor<String> {
  3. @Override
  4. public void process(AioSession<String> session, String msg) {
  5. WriteBuffer writeBuffer = session.writeBuffer();
  6. byte[] bytes = msg.getBytes();
  7. try {
  8. writeBuffer.writeInt(bytes.length);
  9. writeBuffer.write(bytes);
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. @Override
  15. public void stateEvent(AioSession<String> session, StateMachineEnum stateMachineEnum, Throwable throwable) {
  16. }
  17. }

接下来我们修改application.xml配置,default-autowire="byName"表示优先按bean名称注入,而注解的扫描扫描包路径为org.smartboot.example.spring

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context-4.0.xsd"
  9. default-autowire="byName">
  10. <context:component-scan base-package="org.smartboot.example.spring"/>
  11. </beans>

最后我们还需要以注解的形式构造AioQuickServer对象并启动服务。

  1. @Component
  2. public class SpringDemo {
  3. @Autowired
  4. private MessageProcessor messageProcessor;
  5. @Autowired
  6. private Protocol protocol;
  7. private AioQuickServer aioQuickServer;
  8. public static void main(String[] args) {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
  10. SpringDemo demo = context.getBean("springDemo", SpringDemo.class);
  11. System.out.println("服务启动成功:" + demo.aioQuickServer);
  12. ((ClassPathXmlApplicationContext) context).close();
  13. System.out.println("服务关闭");
  14. }
  15. @PostConstruct
  16. public void init() {
  17. aioQuickServer = new AioQuickServer(8080, protocol, messageProcessor);
  18. try {
  19. aioQuickServer.start();
  20. } catch (IOException e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. @PreDestroy
  25. public void destroy() {
  26. aioQuickServer.shutdown();
  27. }
  28. }