SpringBoot在自定義實現類中調用service層等Spring其他層報錯爲null的解決辦法

背景:

使用Springboot整合Netty寫了一個TCP實現客戶端服務端通信接收主板信息,然後需要將設備實時發送的檢測數據等關鍵信息存儲到數據庫,也是爲了能最快利用mybatis框架實現數據訪問,然後在TCP服務器消息處理時,需要寫數據庫,直接調用DAO層,編譯報錯。改爲調用Service層,編譯正常,運行到調用的地方,報空指針異常,跟蹤到異常位置,發現service爲空,也就是按照之前controller層通過
@Autowired注入service層失效。
解決方案:

1.不要用mybatis,使用原生的jdbc連接數據庫進行存儲

代碼如下:

blic class MessageHandler extends ChannelInboundHandlerAdapter {
	private static Logger logger = LoggerFactory.getLogger(MessageHandler.class);
	/**
	 * 本方法用於讀取客戶端發送的信息
	 * @param ctx
	 * @param msg
	 * @throws Exception
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    System.out.println("輸出接收過來的信息: "+msg);
        //將msg進行入庫操作
        //基礎的jdbc連接操作,這裏省去基礎的連接方法
        String str;
        // 傳遞sql語句
        Statement stt;
        Connection conn = null;
        String sql = "insert into test_db(datas) values ('"+msg+"')";  //寫SQL
        try {
            conn = mysqlimages.getConn();  //一個連接數據庫的方法,這就不貼了,很簡單的
            //獲取Statement對象
            stt = conn.createStatement();
            //執行sql語句
            stt.executeUpdate(sql);
            logger.info(">>>插入數據庫成功");
            str = Const.SECCESS;
        }catch (Exception e) {
            logger.error("<<<插入數據錯誤--"+e.getMessage());
            str = Const.ERROR;
        }

這種方法可以實現,但是不推薦,本來這裏數據量就大,再用jdbc沒有連接池將會造成業務阻塞netty本身的worker工作線程。
所以推薦使用下一種方法:

2.使用@PostConstruct靜態初始化spring的成員變量

代碼如下:
channelRead方法:

	//調用線程池處理大數據量問題
	ExecutorService executor = Executors.newFixedThreadPool(5);
    int num=0;
    
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println();
        log.info("加載客戶端報文......");
        log.info("【" + ctx.channel().id() + "】" + " :" + msg);
        /**
         *  下面可以解析數據,保存數據,生成返回報文,將需要返回報文寫入write函數
         */
        num++;
        System.out.println(num);//輸出當前已經接收過來的條數
        //引入異步業務線程池的方式,避免長時間業務耗時業務阻塞netty本身的worker工作線程
        executor.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                log.info("收到服務端發來的方法請求了--------------------------------------------");
                ServerHandler handler = new ServerHandler();//這個類在下面
                handler.test(msg.toString());
                return null;
            }
        });
        //響應客戶端
        this.channelWrite(ctx.channel().id(), msg);
    }


@Component 
public class ServerHandler extends IoHandlerAdapter {

    @Autowired
    private ITest2StaticService test2StaticService;// 注入service方法

    private static ServerHandler serverHandler;

    @PostConstruct //通過@PostConstruct實現初始化bean之前進行的操作
    //在初始化的時候初始化靜態對象和它的靜態成員變量healthDataService,原理是拿到service層bean對象,靜態存儲下來,防止被釋放。
    public void init() {
        serverHandler = this;
        serverHandler.test2StaticService = this.test2StaticService;
        // 初使化時將已靜態化的testService實例化
    }

    //測試調用
    public void test(String msg) {
        Test2Static test2Static = new Test2Static();
        test2Static.setBb(Double.valueOf(msg));
        test2Static.setCreateTime(LocalDateTime.now());
        System.out.println("1111111111111111");
        boolean b = serverHandler.test2StaticService.save(test2Static);
        System.out.println("---! "+b);
    }

}

IoHandlerAdapter類 所用到的maven座標:
  <!-- https://mvnrepository.com/artifact/org.apache.mina/mina-core -->
        <dependency>
            <groupId>org.apache.mina</groupId>
            <artifactId>mina-core</artifactId>
            <version>2.1.3</version>
        </dependency>


2.說明:

將需要調用Spring的Service層的類通過@Component註解爲組件加載;
同樣通過@Autowired獲取Service層的Bean對象;
爲類聲明一個靜態變量,方便下一步存儲bean對象;
劃重點:通過註解@PostConstruct ,在初始化的時候初始化靜態對象和它的靜態成員變量healthDataService,原理是拿到service層bean對象,靜態存儲下來,防止被釋放。

找了好久,終於找到這個方法,本來以爲很簡單,卻總是怎麼也寫不進去數據庫。調用service一直爲空,可困擾我好久。
特此記錄。。。。。。。。。。。。。。。。。

*那些浪費的時間,都是丟在真理路上的金子~~~~!*

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章