文章目录
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了。