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>