maven管理多模块, 其中一个模块注入有问题?

项目结构如图:
图片描述

logic模块, 该模块负责具体的业务逻辑(分为service层, dao层)

    beans.xml 定义在这里
    

server模块, 负责具体的客户端的接入(用的netty)

    这里的main方法负责启动spring
    

现在出现一个诡异的地方, server中的一个类ConnectHandler, 该类中的成员对象UserLoginService上@AutoWire, 都没有成功, 也不报错, 只是运行的时候会有空指针异常

其次,我在server模块中的main方法中, 通过spring的getBean方法, 得到 ConnectHandler, 成功, 调用getUserLoginService(), 成功, 为什么这里都不为空,

  1. 综上, 基本可以排除, 什么忘记注解, 没有扫描到server模块啊,之类的错误

以下是beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.2.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
       ">

    <context:component-scan base-package="com.haoyin.*"/>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql:///localtest" />
        <property name="user" value="root" />
        <property name="password" value="" />
        <property name="initialPoolSize" value="3" />
        <property name="minPoolSize" value="3" />
        <property name="maxPoolSize" value="10" />
        <property name="maxIdleTime" value="5" />
    </bean>


    <!-- myBatis 配置    -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations" value="classpath*:com/haoyin/logic/dao/*.xml"/>
    </bean>

    <!-- mybatis自动实现dao-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.haoyin.logic.dao"/>
    </bean>

    <!-- 配置sqlSessionTemplate
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    -->

    <!-- 配置事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven transaction-manager="txManager" />

</beans>

以下是ConnectHandler类:

package com.haoyin.server.handler;


import com.haoyin.logic.service.UserLoginService;
import com.haoyin.server.exception.connect.ConnectMessageException;
import com.haoyin.server.exception.connect.ConnectionAlreadyExistException;
import com.haoyin.server.exception.connect.MessageFormatException;
import com.haoyin.server.exception.connect.UserPermissionException;
import com.haoyin.server.state.Connection;
import com.haoyin.server.state.ConnectionManager;
import com.haoyin.server.state.UserConfig;
import com.haoyin.server.utils.StringUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.mqtt.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.InetSocketAddress;

/**
 * Created by dong on 2016/1/12.
 */

@Service("connectHandler")
public class ConnectHandler extends SimpleChannelInboundHandler<MqttMessage> {

    private Logger logger = LoggerFactory.getLogger(ConnectHandler.class);

    @Autowired
    private TestHandler handler;
    @Autowired
    private UserLoginService userLoginService;
    private ChannelHandlerContext ctx;


    public void setUserLoginService(UserLoginService userLoginService) {
        this.userLoginService = userLoginService;
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        this.ctx = ctx;
        System.out.println("active");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, MqttMessage msg) throws Exception {
        if (msg.fixedHeader().messageType() == MqttMessageType.CONNECT) {
                doConnect(ctx, (MqttConnectMessage) msg);
                sendResponse(buildSuccessAck());
        } else if (msg.fixedHeader().messageType() == MqttMessageType.DISCONNECT) {

        } else {
            //想绕过建立连接
            ctx.fireChannelRead(msg);
        }
    }
    /**
     *
     *
     *  @throws ConnectionAlreadyExistException
     *  @throws UserPermissionException
     *  @throws MessageFormatException
     *
     * */
    private void doConnect(ChannelHandlerContext ctx, MqttConnectMessage connectMessage) {
        checkMessageFormat(connectMessage);

        MqttConnectVariableHeader variableHeader = connectMessage.variableHeader();
        MqttConnectPayload payload = connectMessage.payload();

        //1. 验证用户合法
        String uid = payload.userName();    //约定, username为uid
        String token = payload.password();  //约定, password为token
        checkUserAuth(uid, token);

        String clientId = payload.clientIdentifier();
        checkConnectionExist(clientId);   // 2. 确保用户唯一

        UserConfig userConfig = extractUserConfig(variableHeader, payload);
        buildAndInitConnection(userConfig);
    }


    private void checkMessageFormat(MqttConnectMessage connectMessage)
            throws MessageFormatException {
        MqttConnectPayload payload = connectMessage.payload();

        String clientId = payload.clientIdentifier();
        if (!StringUtils.checkLength(clientId, 1, 23)){
            throw new MessageFormatException(
                    "clientId长度不合法!",
                    MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED);
        }
    }

    private void checkUserAuth(String uid, String token) {
        boolean ok = userLoginService.authenticate(uid, token);
        if (ok) return;
        throw new UserPermissionException("用户验证不通过",
                                        MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD);
}

    private void checkConnectionExist(String clientId) {
        //约定clientId为userId

    }

    /**
     *  保存用户配置, 是否需要遗嘱, clean Session
     *  这些配置在Connect报文的 可选头部和载荷中
     *
     * */
    private UserConfig extractUserConfig(MqttConnectVariableHeader variableHeader,
                                         MqttConnectPayload payload){
        String uid = payload.userName();
        boolean cleanSession = variableHeader.isCleanSession();
        int keepAliveTime = variableHeader.keepAliveTimeSeconds();
        UserConfig profile = new UserConfig(uid, cleanSession, keepAliveTime);
        return profile;
    }

    private void buildAndInitConnection(UserConfig userConfig) {
        Connection connection = ConnectionManager.INSTANCE.create(ctx);
        connection.setUserConfig(userConfig);
    }



    private MqttConnAckMessage buildSuccessAck(){
        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.CONNACK, false,
                MqttQoS.EXACTLY_ONCE, false, 0);
        MqttConnAckVariableHeader variableHeader = new MqttConnAckVariableHeader(
                MqttConnectReturnCode.CONNECTION_ACCEPTED, false);
        MqttConnAckMessage ack = new MqttConnAckMessage(fixedHeader, variableHeader);
        return ack;
    }


    private String getClientIP(){
        InetSocketAddress address = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIP = address.getAddress().getHostAddress();
        return clientIP;
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        if (cause instanceof MessageFormatException) {
            handleProtocolFormatError((MessageFormatException) cause);
        } else if (cause instanceof ConnectionAlreadyExistException) {
            handleConnectionAlreadyExist((ConnectionAlreadyExistException) cause);
        } else if (cause instanceof UserPermissionException) {
            handleUserPermission((UserPermissionException) cause);
        } else {
            ctx.fireExceptionCaught(cause);
        }
    }

    private void handleProtocolFormatError(MessageFormatException e) {
        if (logger.isDebugEnabled()) {
            logger.info("ProtocolFormatError");
        }
        sendResponse(buildErrorAck(e));
    }

    private void handleConnectionAlreadyExist(ConnectionAlreadyExistException e) {
        if (logger.isDebugEnabled()) {
            logger.info("ConnectionAlreadyExist");
        }
        sendResponse(buildErrorAck(e));
    }

    private void handleUserPermission(UserPermissionException e) {
        if (logger.isDebugEnabled()) {
            logger.info("UserPermission");
        }
        sendResponse(buildErrorAck(e));
    }


    private MqttConnAckMessage buildErrorAck(ConnectMessageException e){
        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.CONNACK, false,
                MqttQoS.EXACTLY_ONCE, false, 0);
        MqttConnAckVariableHeader variableHeader = new MqttConnAckVariableHeader(
                e.getMqttConnectReturnCode(), false);
        MqttConnAckMessage ack = new MqttConnAckMessage(fixedHeader, variableHeader);
        return ack;
    }

    private void sendResponse(MqttMessage mqttMessage) {
        ctx.writeAndFlush(mqttMessage);
    }


}

请各位帮忙看看, 困在这里一天了..

阅读 7k
1 个回答

确定空指针是由UserLoginService造成的?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题