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一直为空,可困扰我好久。
特此记录。。。。。。。。。。。。。。。。。

*那些浪费的时间,都是丢在真理路上的金子~~~~!*

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