1. 程式人生 > >springboot基本使用筆記----新增socket服務及獲取spring bean

springboot基本使用筆記----新增socket服務及獲取spring bean

(一)新增socket服務

因為專案基於 springboot 框架,要提供 socket 服務,網上查資料好多說是要新增 websocket 元件,感覺挺麻煩就沒去看,直接使用原始的方式寫個 socket 服務類,然後在 springboot 啟動類的 main 方法中,新增 socket 服務啟動方法。

1.socket服務類程式碼如下(網上有好多例子,隨便拿了個模板略作修改):

import java.io.*;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;

/**
 * nio socket服務端
 */
public class SocketServer {
    //解碼buffer
    private Charset cs = Charset.forName("UTF-8");
    //接受資料緩衝區
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
    //傳送資料緩衝區
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
    //選擇器(叫監聽器更準確些吧應該)
    private static Selector selector;

    /**
     * 啟動socket服務,開啟監聽
     * @param port
     * @throws IOException
     */
    public void startSocketServer(int port){
        try {
            //開啟通訊通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            //設定為非阻塞
            serverSocketChannel.configureBlocking(false);
            //獲取套接字
            ServerSocket serverSocket = serverSocketChannel.socket();
            //繫結埠號
            serverSocket.bind(new InetSocketAddress(port));
            //開啟監聽器
            selector = Selector.open();
            //將通訊通道註冊到監聽器
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            //監聽器會一直監聽,如果客戶端有請求就會進入相應的事件處理
            while (true){
                selector.select();//select方法會一直阻塞直到有相關事件發生或超時
                Set<SelectionKey> selectionKeys = selector.selectedKeys();//監聽到的事件
                for (SelectionKey key : selectionKeys) {
                    handle(key);
                }
                selectionKeys.clear();//清除處理過的事件
            }
        }catch (Exception e){
            e.printStackTrace();
        }



    }

    /**
     * 處理不同的事件
     * @param selectionKey
     * @throws IOException
     */
    private void handle(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel serverSocketChannel = null;
        SocketChannel socketChannel = null;
        String requestMsg = "";
        int count = 0;
        if (selectionKey.isAcceptable()) {
            //每有客戶端連線,即註冊通訊通道為可讀
            serverSocketChannel = (ServerSocketChannel)selectionKey.channel();
            socketChannel = serverSocketChannel.accept();
            socketChannel.configureBlocking(false);
            socketChannel.register(selector, SelectionKey.OP_READ);
        }
        else if (selectionKey.isReadable()) {
            socketChannel = (SocketChannel)selectionKey.channel();
            rBuffer.clear();
            count = socketChannel.read(rBuffer);
            //讀取資料
            if (count > 0) {
                rBuffer.flip();
                requestMsg = String.valueOf(cs.decode(rBuffer).array());
            }
            String responseMsg = "已收到客戶端的訊息:"+requestMsg;
            //返回資料
            sBuffer = ByteBuffer.allocate(responseMsg.getBytes("UTF-8").length);
            sBuffer.put(responseMsg.getBytes("UTF-8"));
            sBuffer.flip();
            socketChannel.write(sBuffer);
            socketChannel.close();
        }
    }

}
2.在 springboot 啟動類 main 方法中新增 socket 服務端啟動程式碼
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
@MapperScan("com.xxx.mapper")
public class PlatformApplication {

	public static void main(String[] args) {
		SpringApplication.run(PlatformApplication.class, args);
		//起socket服務
		SocketServer server = new SocketServer();
		server.startSocketServer(8088);
	}

}
(二 )獲取 spring bean

因為沒使用 websocket 元件,在 SocketServer 類中使用註解方式注入到 spring 容器中的 Service 會存在問題,舉個例子:

資料持久層使用了 mybatis 框架,如果實現資料持久化,需要如下檔案

1.實體類 entity.java 

2.sql 對映檔案 mapper.xml

3.mapper 介面類 mapper.java

4.service 介面類 service.java

5.service 實現類 serviceimpl,java

現在需要做個查詢,通常情況下是呼叫注入的 service 的 find 方法,過程應該是先獲取 注入的 service(即 serviceimpl 的例項),再獲取注入到 service 的  mapper ,

最後通過 mapper.xml 配置檔案獲取相應的 sql 到資料庫查詢。

SocketServer 作為普通類是無法將 servcie 注入進來的,那通過 new 一個例項的方法可以嗎?不可以! new 出來的 serviceimpl 的例項中 mapper 是 null 。所以我們只能從 spring 容器中獲取 serviceimpl bean ,得到的 bean 中 mapper 就不是 null 了。

首先,建立從 spring 容器中獲取 bean 的工具類:

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Created by 
 */
@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    //獲取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通過name獲取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通過class獲取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通過name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }
}
然後在使用的時候呼叫下:

Service service = SpringUtil.getBean(ServiceImpl.class);

這樣,就能在普通類中獲取註解方式注入到 spring 容器中的 bean 了。