spring.xml文件中
<!-- MINA -->
<!-- =============================================================== -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.net.SocketAddress">
<bean class="org.apache.mina.integration.beans.InetSocketAddressEditor" />
</entry>
</map>
</property>
</bean>
<bean id="xmppHandler" class="org.androidpn.server.xmpp.net.XmppIoHandler" />
<bean id="filterChainBuilder"
class="org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder">
<property name="filters">
<map>
<entry key="executor">
<bean class="org.apache.mina.filter.executor.ExecutorFilter" />
</entry>
<entry key="codec">
<bean class="org.apache.mina.filter.codec.ProtocolCodecFilter">
<constructor-arg>
<bean class="org.androidpn.server.xmpp.codec.XmppCodecFactory" />
</constructor-arg>
</bean>
</entry>
<!--
<entry key="logging">
<bean class="org.apache.mina.filter.logging.LoggingFilter" />
</entry>
-->
</map>
</property>
</bean>
<bean id="ioAcceptor" class="org.apache.mina.transport.socket.nio.NioSocketAcceptor"
init-method="bind" destroy-method="unbind">
<property name="defaultLocalAddress" value=":5222" />
<property name="handler" ref="xmppHandler" />
<property name="filterChainBuilder" ref="filterChainBuilder" />
<property name="reuseAddress" value="true" />
</bean>
spring中会在加载 <bean id="ioAcceptor" init-method="bind">启动org.apache.mina.transport.socket.nio.NioSocketAcceptor 的bind方法启动监听的程序,同时设置了属性,其作用如同
以下是最简单的MINA例子程序,
public class MinaTimeServer {
private static final int PORT = 9123;// 定义监听端口
public static void main(String[] args) throws IOException {
IoAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast(
"codec",
new ProtocolCodecFilter(new TextLineCodecFactory(Charset
.forName("UTF-8"))));// 指定编码过滤器
acceptor.setHandler(new TimeServerHandler());// 指定业务逻辑处理器
acceptor.setDefaultLocalAddress(new InetSocketAddress(PORT));// 设置端口号
acceptor.bind();// 启动监听
System.out.println("Begin************");
}
}
//业务逻辑处理,当监听到有数据传送过来的时候会调用
public class TimeServerHandler extends IoHandlerAdapter {
@Override
public void sessionCreated(IoSession session) {
// 显示客户端的ip和端口
System.out.println("sessionCreated"+session.getRemoteAddress().toString());
}
@Override
public void messageReceived(IoSession session, Object message)
throws Exception {
String str = message.toString();
System.out.println("Message written..."+str);
if (str.trim().equalsIgnoreCase("quit")) {
session.close();// 结束会话
return;
}
Date date = new Date();
session.write(date.toString());// 返回当前时间的字符串
}
}
//指定业务逻辑处理器
Spring+MINA中这个指定了<property name="handler" ref="xmppHandler" />默认的业务逻辑处理器,
package org.androidpn.server.xmpp.net.XmppIoHandler
package org.androidpn.server.xmpp.net..StanzaHandler
当监听到有数据的时候会执行XmppIoHandler的这个方法,message是客户端发送过来的数据,被封装成xmpp用的对象
中messageReceived(IoSession session, Object message){
.......
StanzaHandler handler = (StanzaHandler) session
.getAttribute(STANZA_HANDLER);
handler.process((String) message, parser);
.......
}
//以下是涉及到的构造函数的实现
public StanzaHandler(String serverName, Connection connection) {
this.serverName = serverName;
this.connection = connection;
this.router = new PacketRouter();
}
public PacketRouter() {
messageRouter = new MessageRouter();
presenceRouter = new PresenceRouter();
iqRouter = new IQRouter();
}
public IQRouter() {//业务逻辑处理器的分发就是在这个里实现的
sessionManager = SessionManager.getInstance();
iqHandlers.add(new IQAuthHandler());
iqHandlers.add(new IQRegisterHandler());
iqHandlers.add(new IQRosterHandler());
}
//StanzaHandler
public void process(String stanza, XMPPPacketReader reader){
根据判断message包含的字符串
Element doc = reader.read(new StringReader(stanza)).getRootElement();
String tag = doc.getName();
if ("iq".equals(tag)) {//客户端发送过来包含iq字段,androidpn-client端中代表的是注册用的
log.debug("iq...");
processIQ(doc);
}
private void processIQ(Element doc) {
packet = getIQ(doc);
。。。
packet.setFrom(session.getAddress());
router.route(packet);//业务逻辑处理器分发控制
session.incrementClientPacketCount();
}
//PacketRouter
public void route(IQ packet) {
iqRouter.route(packet);//注册业务逻辑的处理器的分发控制
}
//IQRouter
private Map<String, IQHandler> namespace2Handlers = new ConcurrentHashMap<String, IQHandler>();
public void route(IQ packet) {
判断message包含的字段 是否有iq //代表注册
"jabber:iq:register".equals(packet.getChildElement()
.getNamespaceURI())
handle(packet);
}
private void handle(IQ packet) {
try {
Element childElement = packet.getChildElement();
String namespace = null;
if (childElement != null) {
namespace = childElement.getNamespaceURI();
}
if (namespace == null) {
if (packet.getType() != IQ.Type.result
&& packet.getType() != IQ.Type.error) {
log.warn("Unknown packet " + packet);
}
} else {
//根据获得的message的命名空间获取对应的IQRegisterHandler 业务逻辑处理器
IQHandler handler = getHandler(namespace);
sendErrorPacket(packet,
PacketError.Condition.service_unavailable);
} else {
handler.process(packet);
}
private IQHandler getHandler(String namespace) {
IQHandler handler = namespace2Handlers.get(namespace);
if (handler == null) {
for (IQHandler handlerCandidate : iqHandlers) {
if (namespace.equalsIgnoreCase(handlerCandidate.getNamespace())) {
handler = handlerCandidate;
namespace2Handlers.put(namespace, handler);
break;
}
}
}
return handler;
}
//handler.process(packet);
public void process(Packet packet) {
IQ iq = (IQ) packet;
try {
IQ reply = handleIQ(iq); //这个方法是抽象的,在IQRegisterHandler 继承于IQHandler,同时也是继承了process方法
.......
}
到这里服务器端的当客户端连接上服务器的时候注册部分已经解释结束,剩下的同理可以实现了》》》
(好记性不如烂笔头-------)