解决在非spring上下文的环境中无法获取Spring容器的bean【nullpointer:connot invoke because xxx is null问题】

1.背景:

项目在nio监听端口的事件中需要在接收到客户端数据以后把数据封装然后调用service层间接访问数据库插入数据,调试了一天,明明用了autowired但是仍然显示该service对象为空,一下是报错的代码:
在这里插入图片描述

2.原代码:

@Component
public class Myselect implements Callable {
    
    

    @Autowired
    private WashService washService;
    public void getSelector() throws IOException {
    
    
        //创建 Selector
       Selector selector = Selector.open();//用open方法创建
        ServerSocketChannel channel = ServerSocketChannel.open();//获取通道
        channel.configureBlocking(false);//切换为非阻塞模式
        channel.bind(new InetSocketAddress(8004));
        channel.register(selector, SelectionKey.OP_ACCEPT);//注册通道到选择器上,第二个参数为指定的事件为”监听接收事件“
//
//        * 读 : SelectionKey.OP_READ (1)
//* 写 : SelectionKey.OP_WRITE (4)
//* 连接 : SelectionKey.OP_CONNECT (8)
//* 接收 : SelectionKey.OP_ACCEPT (16)
//* 若注册时不止监听一个事件,则可以使用“位或”操作符连接。

        //轮询式的获取选择器上已经“准备就绪”的事件
        while (selector.select() > 0)
        {
    
    

            //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext())
            {
    
    
                //8. 获取准备“就绪”的是事件
                SelectionKey sk = it.next();
                //9. 判断具体是什么事件准备就绪
                if (sk.isAcceptable()) {
    
    
                    //10. 若“接收就绪”,获取客户端连接
                    SocketChannel sChannel = channel.accept();
                    //11. 切换非阻塞模式
                    sChannel.configureBlocking(false);
                    //12. 将该通道注册到选择器上
                    sChannel.register(selector, SelectionKey.OP_READ);
                } else if (sk.isReadable()) {
    
    
                    //13. 获取当前选择器上“读就绪”状态的通道
                    SocketChannel sChannel = (SocketChannel) sk.channel();
                    //14. 读取数据
                    sChannel.socket().getInputStream();
                    ByteBuffer buf = ByteBuffer.allocate(5000);
                    int len = 0;
                    FileOutputStream out = new FileOutputStream("C:\\Users\\14172\\Desktop\\myback\\resources\\static\\0.png");
                    FileOutputStream in = new FileOutputStream("C:\\Users\\14172\\Desktop\\myback\\mydiary.txt");
                    FileChannel fileChannel = out.getChannel();
//                    String hostAddress = sChannel.socket().getInetAddress().getHostAddress();
//                    System.out.println("host:"+hostAddress);
//                    int port = sChannel.socket().getPort();
//                    System.out.println("port:"+port);
                    if(sChannel.socket().getPort() == 8001)
                    {
    
    
                       try{
    
    
                       // 暂时没有成功,无法接受到图片
                           //FileChannel的read方法 ,从通道读取数据并放到缓冲区中
                        while ((len = sChannel.read(buf)) > 0) {
    
    //把channel的东西读到buf
                            buf.flip();
                            //out.write(buf.array(),0,len);
                            int i = fileChannel.write(buf);//buf的数据写到filechannel
                            System.out.println("长度" + i);
                            buf.clear();
                            out.flush();
                        }
                    }finally {
    
    
                         //  fileChannel.close();
                           out.close();
                       }

                        byte[] buffer = new byte[1024];
// 首次从Socket读取数据

                    //    System.out.println("文件读写完毕");
                    }
                 else  if(sChannel.socket().getPort() == 8002)
                    {
    
    
                        try {
    
    
                            while ((len = sChannel.read(buf)) > 0) {
    
    
                                int alltime = 0;

                                buf.flip();
                                //  out.write(buf.array(),0,len);

                               String readfrompython = new String(buf.array(), 0, len);
                              //  fileChannel.write(buf);
                                 String[] arr = readfrompython.split("\n");
                                 //Arrays.stream(arr).forEach(System.out::println);
                                int[] time = new int[arr.length];

//                        for (int i = 0; i < arr.length; i++) {
    
    
//                            time[i] = Integer.parseInt(arr[i]);
//                            alltime+=time[i];
//                        }
                                System.out.println("total:" + alltime);
                                Wash  wash=       new Wash();
                                //wash.setTime(new Date());

                                Wash  wash2 = new Wash();
                                wash2.setLastTime(alltime);
                          //      wash2.setAllTime(service.getWahNums()+1);
                              //  wash2.setWater((int)(service.gettotal()+alltime)/(service.getWahNums()+1));
                                wash2.setWater(1.2);
                       wash2.setTime(new Date());
                                if(washService.save(wash2)) System.out.println("插入数据成功!");
                        System.out.println(new String(buf.array(), 0, len));
                                buf.clear();
                            }
                        } finally {
    
    
                        //    if(sChannel.read(buf)<0)
                            fileChannel.close();
                            out.flush();
                            out.close();
                        }
                    }
                }
                //15. 取消选择键 SelectionKey
                it.remove();
            }
        }
    }

    public static void main(String[] args) throws IOException {
    
    
        new Myselect().getSelector();
    }


    @Override
    public Object call() {
    
    
        System.out.println(Thread.currentThread().getName());
        try {
    
    
            getSelector();
        }catch (IOException e)
        {
    
    
            e.printStackTrace();
        }
        return 0;
    }
}

用的是mybatis-plus框架
用到业务类插入数据的地方是:washService.save(wash2)
启动类入口:

@MapperScan("com.naughty.userlogin02.dao")
@SpringBootApplication
public class Userlogin02Application  {
    
    
    private final static int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    private final static ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(AVALIABLE_PROCESSORS, AVALIABLE_PROCESSORS * 2,
            1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(5),
            new ThreadPoolExecutor.CallerRunsPolicy());
//extends SpringBootServletInitializer
    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
    
    
     SpringApplication.run(Userlogin02Application.class, args);
    Myselect myselect = new Myselect();
        FutureTask<Integer> future2 = new FutureTask<Integer>(myselect);
        new Thread(future2).start();
        System.out.println(Thread.currentThread().getName());
        }

其中自己的业务层:


public interface WashService extends IService<Wash> {
    
    
    List<Wash> allWash();
    int gettotal();

    double getwotal();
    public BigDecimal getAvgTotal();
int getWahNums();

@Service
public class WashServiceImpl extends ServiceImpl<WashDao,Wash> implements WashService {
    
    
    @Autowired
    WashDao washDao;
    @Override
    public List<Wash> allWash(){
    
    
        return washDao.findAll();
    }
    @Override
    public int gettotal() {
    
    
        return washDao.getTotal();
    }

    @Override
    public double getwotal() {
    
    
        return washDao.getWater();
    }
    @Override
    public BigDecimal getAvgTotal(){
    
    
        return washDao.getAvgTotal();

    }

    @Override
    public int getWahNums() {
    
    
        return washDao.getWahNums();
    }
}

想了很多方法,包括修改注解为configuration,移动到另一个路径,在接口类上面加注解等等均无结果
然后有怀疑是不是这个类不在spring上下文环境里面了然后没有拿到Spring的bean:

非spring环境中获取bean

下面用一个获取非spring环境中获取bean的工具类来测试:

/**
 * spring工具类 方便在非spring管理环境中获取bean
 * 
 * @author ruoyi
 */
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware
{
    
    
    /** Spring应用上下文环境 */
    private static ConfigurableListableBeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
    {
    
    
        SpringUtils.beanFactory = beanFactory;
    }

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

    /**
     * 获取对象
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws org.springframework.beans.BeansException
     *
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException
    {
    
    
        return (T) beanFactory.getBean(name);
        //例如 private static CacheManager cacheManager = SpringUtils.getBean(CacheManager.class);
    }

    /**
     * 获取类型为requiredType的对象
     *
     * @param clz
     * @return
     * @throws org.springframework.beans.BeansException
     *
     */
    public static <T> T getBean(Class<T> clz) throws BeansException
    {
    
    
        T result = (T) beanFactory.getBean(clz);
        return result;
    }

    /**
     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
     *
     * @param name
     * @return boolean
     */
    public static boolean containsBean(String name)
    {
    
    
        return beanFactory.containsBean(name);
    }

    /**
     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
     *
     * @param name
     * @return boolean
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
    {
    
    
        return beanFactory.isSingleton(name);
    }

    /**
     * @param name
     * @return Class 注册对象的类型
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
    {
    
    
        return beanFactory.getType(name);
    }

    /**
     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
     *
     * @param name
     * @return
     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
     *
     */
    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
    {
    
    
        return beanFactory.getAliases(name);
    }

    /**
     * 获取aop代理对象
     * 
     * @param invoker
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getAopProxy(T invoker)
    {
    
    
        return (T) AopContext.currentProxy();
    }

    /**
     * 获取当前的环境配置,无配置返回null
     *
     * @return 当前的环境配置
     */
    public static String[] getActiveProfiles()
    {
    
    
        return applicationContext.getEnvironment().getActiveProfiles();
    }

    /**
     * 获取当前的环境配置,当有多个环境配置时,只获取第一个
     *
     * @return 当前的环境配置
     */
    public static String getActiveProfile()
    {
    
    
        final String[] activeProfiles = getActiveProfiles();
        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
    }
}

然后修改刚刚的nio程序,注释掉autowired
加上:

     WashService washService = SpringUtils.getBean("washservice");
                         washService.allWash().stream().forEach(System.out::println);

再次运行结果:
在这里插入图片描述
可见此时已经在这个nio服务端类中获得了washservice了。

猜你喜欢

转载自blog.csdn.net/qq_41358574/article/details/120591135
今日推荐