org.apache.cxf.phase.Phase
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.phase; public class Phase implements Comparable { // can be removed from once defined as default value in configuration metadata for bus public static final String SETUP = "setup"; public static final String SETUP_ENDING = "setup-ending"; public static final String PRE_LOGICAL = "pre-logical"; public static final String PRE_LOGICAL_ENDING = "pre-logical-ending"; public static final String USER_LOGICAL = "user-logical"; public static final String USER_LOGICAL_ENDING = "user-logical-ending"; public static final String POST_LOGICAL = "post-logical"; public static final String POST_LOGICAL_ENDING = "post-logical-ending"; public static final String PRE_MARSHAL = "pre-marshal"; public static final String MARSHAL = "marshal"; public static final String POST_MARSHAL = "post-marshal"; public static final String MARSHAL_ENDING = "marshal-ending"; public static final String PRE_PROTOCOL = "pre-protocol"; public static final String PRE_PROTOCOL_FRONTEND = "pre-protocol-frontend"; public static final String PRE_PROTOCOL_ENDING = "pre-protocol-ending"; public static final String USER_PROTOCOL = "user-protocol"; public static final String USER_PROTOCOL_ENDING = "user-protocol-ending"; public static final String POST_PROTOCOL = "post-protocol"; public static final String POST_PROTOCOL_ENDING = "post-protocol-ending"; public static final String PREPARE_SEND = "prepare-send"; public static final String PREPARE_SEND_ENDING = "prepare-send-ending"; public static final String PRE_STREAM = "pre-stream"; public static final String PRE_STREAM_ENDING = "pre-stream-ending"; public static final String USER_STREAM = "user-stream"; public static final String USER_STREAM_ENDING = "user-stream-ending"; public static final String POST_STREAM = "post-stream"; public static final String POST_STREAM_ENDING = "post-stream-ending"; public static final String WRITE = "write"; public static final String WRITE_ENDING = "write-ending"; public static final String SEND = "send"; public static final String SEND_ENDING = "send-ending"; public static final String RECEIVE = "receive"; public static final String READ = "read"; public static final String PROTOCOL = "protocol"; public static final String UNMARSHAL = "unmarshal"; public static final String PRE_INVOKE = "pre-invoke"; public static final String INVOKE = "invoke"; public static final String POST_INVOKE = "post-invoke"; private String name; private int priority; public Phase() { } public Phase(String n, int p) { this.name = n; this.priority = p; } public String getName() { return name; } public void setName(String n) { this.name = n; } public int getPriority() { return priority; } public void setPriority(int p) { this.priority = p; } public int hashCode() { return priority; } public boolean equals(Object o) { Phase p = (Phase)o; return p.priority == priority && p.name.equals(name); } public int compareTo(Object o) { Phase p = (Phase)o; if (priority == p.priority) { return name.compareTo(p.name); } return priority - p.priority; } public String toString() { return "Phase(" + getName() + ")"; } }
cxf 把web service 的过程分为以上很多个片段,下面我们分析一下如何去开发一个cxf拦截器:
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.phase; import java.util.Collection; import java.util.Set; import javax.xml.stream.XMLStreamReader; import org.apache.cxf.common.util.SortedArraySet; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageUtils; /** * Provides a starting point implementation for a interceptors that * participate in phased message processing. Developers should extend from * this class when implementing custom interceptors. * Developers need to provide an implementation for handleMessage() and * can overide the handleFault() implementation. They should not overide * the other methods. */ public abstract class AbstractPhaseInterceptor<T extends Message> implements PhaseInterceptor<T> { private final String id; private final String phase; private final Set<String> before = new SortedArraySet<String>(); private final Set<String> after = new SortedArraySet<String>(); /** * Instantiates the interceptor to live in a specified phase. The * interceptor's id will be set to the name of the implementing class. * * @param phase the interceptor's phase */ public AbstractPhaseInterceptor(String phase) { this(null, phase, false); } /** * Instantiates the interceptor with a specified id. * * @param i the interceptor's id * @param p the interceptor's phase */ public AbstractPhaseInterceptor(String i, String p) { this(i, p, false); } /** * Instantiates the interceptor and specifies if it gets a system * determined unique id. If <code>uniqueId</code> is set to true the * interceptor's id will be determined by the runtime. If * <code>uniqueId</code> is set to false, the implementing class' name * is used as the id. * * @param phase the interceptor's phase * @param uniqueId true to have a unique ID generated */ public AbstractPhaseInterceptor(String phase, boolean uniqueId) { this(null, phase, uniqueId); } /** * Instantiates the interceptor with a specified id or with a system * determined unique id. The specified id will be used unless * <code>uniqueId</code> is set to true. * * @param i the interceptor's id * @param p the interceptor's phase * @param uniqueId */ public AbstractPhaseInterceptor(String i, String p, boolean uniqueId) { if (i == null) { i = getClass().getName(); } if (uniqueId) { i += System.identityHashCode(this); } id = i; phase = p; } /** * Specifies that the current interceptor needs to be added to the * interceptor chain before the specified collection of interceptors. * This method replaces any existing list with the provided list. * * @param i a collection of interceptor ids */ public void setBefore(Collection<String> i) { before.clear(); before.addAll(i); } /** * Specifies that the current interceptor needs to be added to the * interceptor chain after the specified collection of interceptors. * This method replaces any existing list with the provided list. * * @param i a collection of interceptor ids */ public void setAfter(Collection<String> i) { after.clear(); after.addAll(i); } /** * Specifies that the current interceptor needs to be added to the * interceptor chain before the specified collection of interceptors. * * @param i a collection of interceptor ids */ public void addBefore(Collection<String> i) { before.addAll(i); } /** * Specifies that the current interceptor needs to be added to the * interceptor chain after the specified collection of interceptors. * * @param i a collection of interceptor ids */ public void addAfter(Collection<String> i) { after.addAll(i); } /** * Specifies that the current interceptor needs to be added to the * interceptor chain before the specified interceptor. * * @param i an interceptor id */ public void addBefore(String i) { before.add(i); } /** * Specifies that the current interceptor needs to be added to the * interceptor chain after the specified interceptor. * * @param i an interceptor id */ public void addAfter(String i) { after.add(i); } public final Set<String> getAfter() { return after; } public final Set<String> getBefore() { return before; } public Collection<PhaseInterceptor<? extends Message>> getAdditionalInterceptors() { return null; } public final String getId() { return id; } public final String getPhase() { return phase; } public void handleFault(T message) { } public boolean isGET(T message) { String method = (String)message.get(Message.HTTP_REQUEST_METHOD); return "GET".equals(method) && message.getContent(XMLStreamReader.class) == null; } /** * Determine if current messaging role is that of requestor. * * @param message the current Message * @return true if the current messaging role is that of requestor */ protected boolean isRequestor(T message) { return MessageUtils.isRequestor(message); } }
AbstractPhaseInterceptor 类中有如下构造器,
public AbstractPhaseInterceptor(String phase) { this(null, phase, false); } /** * Instantiates the interceptor with a specified id. * * @param i the interceptor's id * @param p the interceptor's phase */ public AbstractPhaseInterceptor(String i, String p) { this(i, p, false); } /** * Instantiates the interceptor and specifies if it gets a system * determined unique id. If <code>uniqueId</code> is set to true the * interceptor's id will be determined by the runtime. If * <code>uniqueId</code> is set to false, the implementing class' name * is used as the id. * * @param phase the interceptor's phase * @param uniqueId true to have a unique ID generated */ public AbstractPhaseInterceptor(String phase, boolean uniqueId) { this(null, phase, uniqueId); } /** * Instantiates the interceptor with a specified id or with a system * determined unique id. The specified id will be used unless * <code>uniqueId</code> is set to true. * * @param i the interceptor's id * @param p the interceptor's phase * @param uniqueId */ public AbstractPhaseInterceptor(String i, String p, boolean uniqueId) { if (i == null) { i = getClass().getName(); } if (uniqueId) { i += System.identityHashCode(this); } id = i; phase = p; }
AbstractPhaseInterceptor 类中的private final String phase; 属性,是确定这个拦截器是在过程的哪个阶段拦截的,所有我们在创建拦截器是一定要指定phase 过程。
cxf中的所有自定义拦截器都必须继承于AbstractPhaseInterceptor
LoggingInInterceptor (系统日志入拦截器)
LoggingOutInterceptor (系统日志出拦截器)
webservice 服务器端获取拦截器集合
String address="http://192.168.70.51:8888/ws/dataws"; Endpoint endpoint=Endpoint.publish(address, new DataTypeWSImpl()); System.out.println(endpoint); EndpointImpl endpointImpl=(EndpointImpl)endpoint; //获取拦截器链 List<Interceptor<? extends Message>> inInterceptors=endpointImpl.getInInterceptors(); //添加服务器端日志入拦截器 inInterceptors.add(new LoggingInInterceptor()); System.out.println("web service 发布成功");
webservice 客户端获取拦截器集合:
DataTypeWSImplService factory=new DataTypeWSImplService(); DataTypeWS ws=factory.getDataTypeWSImplPort(); Client client=ClientProxy.getClient(ws); List<Interceptor<? extends Message>> outIntercepter=client.getOutInterceptors(); outIntercepter.add(new LoggingOutInterceptor()); List<Interceptor<? extends Message>> inIntercepter=client.getInInterceptors(); inIntercepter.add(new LoggingInInterceptor());
自定义拦截器:
服务器端拦截器:
a. 编写一个类继承AbstractPhaseInterceptor<SoapMessage>,并且实现 public void handleMessage(SoapMessage msg) throws Fault 方法,在里面实现拦截的业务逻辑
注意,在自定拦截器中必须要指定父类的phase属性的值:
public CheckUserInterceptor() { super(Phase.PRE_PROTOCOL); }
package com.mscncn.ws.sayhi.interceptor; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.Element; public class CheckUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> { public CheckUserInterceptor() { super(Phase.PRE_PROTOCOL); } public void handleMessage(SoapMessage msg) throws Fault { Header header=msg.getHeader(new QName("mscncn")); if(header!=null){ Element rootEle=(Element) header.getObject(); String name=rootEle.getElementsByTagName("name").item(0).getTextContent(); String password=rootEle.getElementsByTagName("password").item(0).getTextContent(); if(name.equals("zs")&&password.equals("123456")){ System.out.println(" Service 通过了拦截器"); } } //没有通过 System.out.println("Service 没有通过拦截器"); } }
b. 拦截器写好了,那么就需要在服务器端注册,然后才能使用:
String address="http://192.168.70.51:1111/day01_ws/hellows"; Endpoint point=Endpoint.publish(address, new HelloWSImpl()); EndpointImpl endpointImpl=(EndpointImpl)point; //获取服务器端入拦截器链 List<Interceptor<? extends Message>> inTerceptors=endpointImpl.getInInterceptors(); //注册自定义拦截器 inTerceptors.add(new CheckUserInterceptor()); System.out.println("web service 发布成功!");
服务器端入(in)拦截器的原理就是检查客服端的out拦截器是否符合规定
客户端(out)-> 服务端(in)->处理业务->服务端(out)->客户端(in),并不是每一步都需要拦截器。在这里我们用到的是客户端Out拦截器和服务端in拦截器。服务端in拦截器判断是否符合规范,客户端out浏览器发送用户信息给服务端。
客户端通过消息头的信息发送信息给服务器端in拦截器:
<Envelope> <head> <mscncn> <name></name> <password></password> </mscncn> </head> <!--请求体--> <body> <!--方法名--> <sayHello> <!--方法参数--> <arg0>tom</arg0> </sayHello> </body> </Envelope>