jdk 6中集成了WEB service的支持,通过WebService 的annotation来暴露服务的实现,并通过Endpoint.publish将服务发布到指定的地址,客户端通过wsimport来访问响应地址的wsdl文件,生成调用服务器端服务的stub类信息,客户端即可通过生成的类来调用服务器的服务了。
具体示例如下:
1.对外暴露的接口
public interface TestWebService { public String echo(); }
2.服务器端的实现类,并通过@WebService来指定对外提供服务的服务名称,客户端生成的类目和包名
import javax.jws.WebService; import javax.xml.ws.Endpoint; @WebService(name="MyTestWS",serviceName="MyWebService",targetNamespace="http://localhost/client") public class WebServiceImpl implements TestWebService{ @Override public String echo() { return "webservice return msg"; } public static void main(String[] args) { Endpoint.publish("http://localhost:8080/MyWebService", new WebServiceImpl()); } }
附javax.jws.WebService类中方案的说明
package javax.jws; import java.lang.annotation.Annotation; public interface WebService extends Annotation { /** * Web Service 的名称。 * 当映射到 WSDL 1.1 时,该名称被用作 wsdl:portType 的名称。 * specdefault Java 类或接口的简单名称。 * */ public abstract String name(); /** * 如果 @WebService.targetNamespace 注释是关于某一服务端点接口的, * 则 targetNamespace 用于 wsdl:portType(以及关联的 XML 元素)的名称空间。 * 如果 @WebService.targetNamespace 注释是关于某个没有引用服务端点接口(通过 endpointInterface 属性)的服务实现 bean 的, * 则 targetNamespace 既可以用于 wsdl:portType 也可以用于 wsdl:service(以及关联的 XML 元素)。 * 如果 @WebService.targetNamespace 注释是关于某个引用服务端点接口(通过 endpointInterface属性)的服务实现 bean 的, * 则 targetNamespace 仅用于 wsdl:service(以及关联的 XML 元素)。 * specdefault 随实现而定,正如 JAX-WS 2.0 [5] 第 3.2 节中描述的那样。 * */ public abstract String targetNamespace(); /** * Web Service 的服务名称。 * 当映射到 WSDL 1.1 时,此名称被用作 wsdl:service 的名称。 * 不允许在端点接口上使用此成员值。 * specdefault Java class + "Service" 的简单名称。 * */ public abstract String serviceName(); /** * Web Service 的端口名称。 * 当映射到 WSDL 1.1 时,此名称被用作 wsdl:port 的名称。 * 不允许在端点接口上使用此成员值。 * specdefault @WebService.name+"Port"。 * */ public abstract String portName(); /** * 描述服务的预定义 WSDL 的位置。 * wsdlLocation 是引用预先存在的 WSDL 文件的 URL(相对或绝对)。 * wsdlLocation值的存在指示服务实现 bean 将实现预先定义的 WSDL 协定。 * 如果服务实现 bean 与此 WSDL 中声明的 portType和绑定不一致,则 JSR-181 工具必须提供反馈。 * 注意,单个 WSDL 文件可能包含多个 portType 和多个绑定。 * 服务实现 bean上的注释确定对应于 Web Service 的特定 portType 和绑定。 * */ public abstract String wsdlLocation(); /** * 定义服务抽象 Web Service 协定的服务端点接口的完整名称。 * 此注释允许开发人员将接口协定与实现分离。 * 如果此注释存在,则使用服务端点接口来确定抽象 WSDL 协定(portType和绑定)。 * 服务端点接口可以包含用来定制 Java 到 WSDL的映射关系的 JSR-181 注释。 * 服务实现 bean 可以实现服务端点接口,但并不要求这样做。 * 如果此成员值不存在,则 Web Service协定是根据服务实现 bean 上的注释生成的。 * 如果目标环境需要一个服务端点接口,则将生成一个由实现定义的包,该包具有由实现定义的名称。 * 不允许在端点接口上使用此成员值。 * */ public abstract String endpointInterface(); }
3.然后运行服务器的WebServiceImpl的main函数,暴露服务并将服务注册到一个http服务地址上,客户端通过jdk的bin下面的wsimport命令来获取服务器的wsdl文件并生成客户端的stub类信息
wsimport -keep http://localhost:8080/MyWebService?wsdl
4.然后在你的路径上就会生成下面几个类
5.然后我们编写客户端的调用代码
import localhost.client.MyWebService; public class WebServiceClient { public static void main(String[] args) { MyWebService myWebService = new MyWebService(); System.out.println(myWebService.getMyTestWSPort().echo()); } }
6.执行客户端的调用代码,输出如下:
7.我们看下最终生成客户端服务调用的类内容
package localhost.client; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; import javax.xml.ws.WebEndpoint; import javax.xml.ws.WebServiceClient; /** * This class was generated by the JAXWS SI. * JAX-WS RI 2.0_02-b08-fcs * Generated source version: 2.0 * */ @WebServiceClient(name = "MyWebService", targetNamespace = "http://localhost/client", wsdlLocation = "http://localhost:8080/MyWebService?wsdl") public class MyWebService extends Service{ private final static URL MYWEBSERVICE_WSDL_LOCATION; static { URL url = null; try { url = new URL("http://localhost:8080/MyWebService?wsdl"); } catch (MalformedURLException e) { e.printStackTrace(); } MYWEBSERVICE_WSDL_LOCATION = url; } public MyWebService(URL wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); } public MyWebService() { super(MYWEBSERVICE_WSDL_LOCATION, new QName("http://localhost/client", "MyWebService")); } /** * * @return * returns MyTestWS */ @WebEndpoint(name = "MyTestWSPort") public MyTestWS getMyTestWSPort() { return (MyTestWS)super.getPort(new QName("http://localhost/client", "MyTestWSPort"), MyTestWS.class); } }]]>
Servlet是一个Java编写的程序,此程序是基于Http协议的,在服务器端运行的(如tomcat),是按照Servlet规范编写的一个Java类。
主要是处理客户端的请求并将其结果发送到客户端。
Servlet的生命周期是由Servlet的容器来控制的,它可以分为3个阶段;初始化,运行,销毁。
初始化阶段:
运行阶段:
当servlet容器接收到一个请求时,servlet容器会针对这个请求创建servletRequest和servletResponse对象。然后调用service方法。并把这两个参数传递给service方法。Service方法通过servletRequest对象获得请求的信息。并处理该请求。再通过servletResponse对象生成这个请求的响应结果。然后销毁servletRequest和servletResponse对象。我们不管这个请求是post提交的还是get提交的,最终这个请求都会由service方法来处理。
销毁阶段:
当Web应用被终止时,servlet容器会先调用servlet对象的destrory方法,然后再销毁servlet对象,同时也会销毁与servlet对象相关联的servletConfig对象。我们可以在destroy方法的实现中,释放servlet所占用的资源,如关闭数据库连接,关闭文件输入输出流等。
在这里该注意的地方:
在servlet生命周期中,servlet的初始化和和销毁阶段只会发生一次,而service方法执行的次数则取决于servlet被客户端访问的次数
当用户发送一个请求到某个Servlet的时候,Servlet容器会创建一个ServletRequst和ServletResponse对象。在ServletRequst对象中封装了用户的请求信息,然后Servlet容器把ServletRequst和ServletResponse对象传给用户所请求的Servlet,Servlet把处理好的结果写在ServletResponse中,然后Servlet容器把响应结果传给用户。
cookies是一种WEB服务器通过浏览器在访问者的硬盘上存储信息的手段,是由Netscape公司开发出来的。
cookie技术的好处:
1.过滤器的主要作用
2.怎么创建一个过滤器:
1.监听器的作用:自动执行一些操作。三种servlet监听器:对request的监听。对session的监听。对application的监听。
2.怎么创建一个session监听器:生成一个普通的class类,如果是对session的监听,则实现HttpSessionListener。然后重写里面的五个方法
public void sessionCreated(HttpSessionEvent arg0) {} // 创建 public void sessionDestroyed(HttpSessionEvent arg0) {} // 销毁 public void attributeAdded(HttpSessionEvent arg0) {} // 增加 public void attributeRemoved(HttpSessionEvent arg0) {} // 删除 public void attributeReplaced(HttpSessionEvent arg0) {} // 替换]]>
有时候在经常用Struts\Spring MVC这些优秀的MVC框架的时候,常常容易忘记这些底层简单的东西。本文纯粹做个备忘:-D
更多关于Servlet的知识,欢迎访问Servlet的相关的知识:-D
Java文件
public class HelloWorld extends HttpServlet { private static final long serialVersionUID = -5676313618441583225L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html"); PrintWriter writer = response.getWriter(); writer.println("<html>"); writer.println("<head>"); writer.println("<title>Sample Application Servlet Page</title>"); writer.println("</head>"); writer.println("<body bgcolor=white>"); writer.println("Hello , wrold!"); writer.println("</body>"); writer.println("</html>"); } }
web.xml配置
<!-- 定义servlet --> <servlet> <servlet-name>helloWorldServlet</servlet-name> <servlet-class>com.viluo.servlet.HelloWorld</servlet-class> </servlet> <!-- 定义url和servlet的映射关系 --> <servlet-mapping> <servlet-name>helloWorldServlet</servlet-name> <url-pattern>/hw</url-pattern> </servlet-mapping>
访问地址
http://localhost<:port>/projectName/hw]]>
自己也算是从业多年,对于AOP的概念应该算是听的烂的不能再烂了,这方面的书也看的不少,但是自己一直没有机会去实践下。
乘在这个稍微有点空闲的下午,就随手玩玩SPRING的AOP,也谈谈自己对于AOP的理解及其衍生的一些东西。
基本概念,也可以说是基本术语。任何一个软件概念提出时候,都少不了这个东西。CRM,AOP,SOA等等,伴随这些东西的都会有相应体系内的术语。
我个人的看法是一切术语的出现不是并不是向大众解释清楚这件事到底是怎么一回事,其主要是基于两个方面考虑:
(1)让自己提出观点显得系统化,更具有说服力。
(2)迷惑大众,或是迷糊那些刚进入这个领域的初学者。
两个看似矛盾的因素,其实归结到本质就是将一个简单的东西复杂化并迷糊那些辨别能力的一般的人,大家对于抽象到一定程度的东西但是心怀敬畏之心的,然后带着膜拜的心理去接受,生怕一不小心亵渎了内心的女神。扯开来讲现在社会,官员的道德沦丧,其中的一个诱因就是对于敬畏之心的缺失,当一个人无所畏时,才是最可怕的,因为这个时候已经没有任何约束能约束他的行为。
回归正题,既然提到术语,那么我们就将AOP中的那些术语列出来看看。
切面(Aspect)、连接点(Joinpoint)、通知(Advice)、切入点(Pointcut) 、目标对象(Target Object)、AOP代理(AOP Proxy)。
通知又分为几种:前置通知(Before advice)、后通知(After advice)、返回后通知(After return advice)、环绕通知(Around advice)、抛出异常后通知(After throwing advice) 等。
好了,现在我们来看看这些术语,谁能一眼就明白这些东西能告诉我们什么?谁能通畅的理清楚它们之间的关系。开始解释之前,我们看看维基百科上对AOP的定义是什么:
面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、觀點導向編程)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。
多么简单的解释,就是对于那些在主程序业务之外的事情,我们该怎么设计,看清楚,是程序设计,而不是程序编码,很多地方都将AOP理解成面向切面的编码,那是错误,AOP约定的是一种设计范型,具体到java上的实现例如aspectJ,例如spring的AOP。再具体到实现技术就是JDK自带的动态代理,cglib的字节码修改等等。AOP != spring AOP ,AOP != cglib 。一个是设计范型,一个是实现。
(这里扯开点说,一些所谓的架构师喜欢谈概念,还有人提出架构师更关注抽象的东西,普通的码农更关注具象的东西。这些东西本身没错,在大量的实践之后,我们确实应该去在这大量的实践中归纳,总结出规律,这就是进行抽象。但是,但是,那些只跟你扯抽象而不落地的架构师,还是远离些,因为他们不是基于大量的具象后,进行抽象,他们不过是邯郸学步的抄袭那些真正的架构师的想法,并转变为自己的观点,TMD就是个大忽悠)
我们知道,一个程序是会被编译成计算机能识别的机器码,交给机器去执行,那么我们想知道机器在执行我们的代码时候,发生的一些事,例如:
一个输入是否得到我们想要的输出呢?
一个函数执行的时间开销是多少呢?
若是一个良好的程序遇到无法处理的异常我们该怎么办呢?
存在多个数据源,我们需要在多个数据源的更新都完成后,再提交该怎么处理呢?
我们想将一些我们不认可的请求拒绝,那又该怎么处理呢?
当以上的这些杂事出现时,我们该怎么做呢,一种很简单粗暴的方式就是硬编码的将这些杂事写入到我们的主要业务程序中,我想这种方式大家在日常的开发经常能看到,包括你去看一些所谓平台级别的产品也是采用这种方式,笔者现在所在单位的部分产品也是如此。不管你爽不爽,老子爽了就可以了。
用个不恰当的比喻来说:你是个开饭店的,来了很多顾客,当你女服务员在招待顾客时,你突然发现北大院长来了,想来OOXX下。你就定了一个流程,来北大院长,可OOXX,硬编码的方式就是:
(1)你女服务员在招待
(2)北大院长跟她OOXX
(3)你女服务员在招待
(4)屌丝来了,无视之
......
这个过程中你不管你女服务员是否来例假,你不关心你女服务员是否今天心情不好。嗯,院长爽了,若是你得到了某种回报,也还好,爽了;若是什么都得不到,那可就欲哭无泪。
如果你足够幸福的话,有另一个口味美女服务员,她会隐藏技能---洗脚。恰巧经管学院院长也来了,这个家伙还喜欢洗脚,那怎么办,那就上吧:
(1)你女服务员在招待
(2)北大院长跟她OOXX+洗脚
(3)你女服务员在招待
(4)屌丝来了,无视之
......
如果你生意足够好,恰好北大院长又很多,好吧,你的美女们一直处在XXOO状态中..... 很high,很happy。但是,我们回到最开始,你为什么要招女服务员?找她们来,是因为你需要她们去招待顾客,一个屌丝在等吃饭没关系,若是一群的屌丝在等吃饭,你就悲剧,没人招待屌丝们了,因为你的那些服务员都在跟院长们OOXX中,因为命令已经固化到流程中,你改不了,至少在你修改流程之前。通过我们软件术语来说,就是不能及时、灵活的应对自身内部(你的美女们身体、心情)和外部(屌丝数量)的变化。当然, 你若是铁道部这样的共和国长子,那是没关系的,让那群屌丝们等去吧,因为方圆960万平方公里就此一家,别无分号。
若你不是,哪天觉得自己有点生意有点扛不住或是那点生殖器破事被某个黑心,吃不到葡萄的院长小弟揭发了,扛不住随之而来的社会舆论压力,不能跟院长们OOXX了,只准对他们笑个,这个时候你得通知那些女服务员,说不准OOXX了,只能看了。若是你只有一家店,还好,自己喊一声,重新打印流程规章表,若是全国连锁的话...... 一桌的杯具摆在你茶几上。
好了,扯了这么多,终于要该AOP兄弟出场了,再不出估计戏都散场了。
针对以上的种种问题,我们该怎么处理这些我们店主要生意之外的杂事呢(OOXX),有什么更好的方式来随时应对种种变化。这个就是我们AOP兄弟想干的事情,从主业中剥离出这些杂事,进行单独处理的设计。主业务只关注于自己的领域,对于特殊领域的处理(OOXX),通过侧面来封装维护,这样使得散落在不同口味美女的特殊操作可以很好的管理起来。来段专业点的说明吧:
从主关注点中分离出横切关注点是面向侧面的程序设计的核心概念。分离关注点使得解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过侧面来封装、维护,这样原本分散在在整个应用程序中的变动就可以很好的管理起来。
好了,AOP的就是个这么简单的东西,别去想那些繁杂的spring配置和概念术语。它只是一种设计范型。
绕了这么久,让我们来打倒那些纸老虎吧。
我开饭店,屌丝、院长来吃饭,美女们招待顾客 ,这个是我们的主业。 ======== 目标对象(Target Object) 就是店主我,我开了两个店,戏院和饭店
哦,北大院长来饭店吃饭了 ======== 切入点(Pointcut) 他们来我戏院看戏的话,不管,直管饭店的事
院长开始吃饭,喝酒了。 ======== 连接点(Joinpoint) ,就是我们的一些行为,院长如果来围观的话,无视之,哥是开饭店的。
院长想跟美女们OOXX了 ======== 通知(Advice)院长来了,也吃了饭了,那接下来干什么呢?通知就是决定干什么:OOXX或是洗脚
院长除了想OOXX之外,还想洗脚,那么怎么办呢? ======== 切面(Aspect) ,规定院长来了可以干什么,就是决定可以有多少个通知:OOXX||洗脚 或是 OOXX && 洗脚
--------------------------------------------------------------------------------------------------
院长想吃饭后洗脚 ======== 后通知(After advice)
院长想吃饭前洗脚 ======== 前置通知(Before advice)
院长想根据吃饭后的心情决定是OOXX还是洗脚 ======== 返回后通知(After return advice)
院长吃饭吃出脑中风了 ======== 抛出异常后通知(After throwing advice)这个时候有个通知跳出来:打120,送医院!
院长想饭前洗脚,饭后OOXX ======== 环绕通知(Around advice)
作为老板的我,应该怎么更好的切入这些洗脚啊,OOXX服务呢 ======== AOP代理(AOP Proxy)怎么在干好招待顾客这件事上切入 洗脚||OOXX
若是上面的这些你还是看不明白的话,那么我们就具象到spring上,看看到底是件上面事吧。spring中Aspect叫Advisor。Joinpoint叫Weaving。很操蛋,也很让人无语的术语啊
切面: package com.zhaming.aop.advice; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; /** * 后置通知 * @author inter12 * */ public class AfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("拦截了:" + method.getName() + "方法"); System.out.println("洗脚"); } } package com.zhaming.aop.advice; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * 前置通知 * * @author inter12 */ public class BeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("拦截了:" + method.getName() + "方法"); System.out.println("OOXX"); } } package com.zhaming.aop.advice; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * 环绕通知 * * @author inter12 */ public class CompareAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { Object result = null; String userName = invocation.getArguments()[0].toString(); if (null != userName && userName.equals("yuanzhang")) { System.out.println("院长通过---------------"); result = invocation.proceed(); } else { System.out.println("屌丝拒绝---------------"); } return result; } } 目标对象: package com.zhaming.aop.restaurant; public interface RestaurantService { public void zhaodaiguke(String userName); public void weiguan(String userName); } package com.zhaming.aop.restaurant; /** * 目标对象 * * @author inter12 */ public class RestaurantServiceImpl implements RestaurantService { @Override public void zhaodaiguke(String userName) { System.out.println("--------- 姑娘们在招待顾客:" + userName); } @Override public void weiguan(String userName) { System.out.println(userName + ":在围观"); } } 客户端: package com.zhaming.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import com.zhaming.aop.restaurant.RestaurantService; public class Main { public static void main(String[] args) { ApplicationContext applicationContext = new FileSystemXmlApplicationContext( "//home/inter12/workspace/Light/src/main/java/appcontext-aop.xml"); RestaurantService bean = (RestaurantService) applicationContext.getBean("restaurantService"); bean.zhaodaiguke("yuanzhang"); bean.zhaodaiguke("diaosi"); } } 配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- 通知 --> <bean id="beforeAdvice" class="com.zhaming.aop.advice.BeforeAdvice"></bean> <bean id="afterAdvice" class="com.zhaming.aop.advice.AfterAdvice"></bean> <bean id="compareAdvice" class="com.zhaming.aop.advice.CompareAdvice"></bean> <!-- 目标对象 --> <bean id="restaurantServiceTarget" class="com.zhaming.aop.restaurant.RestaurantServiceImpl"></bean> <bean id="restaurantService" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 拦截那些接口 : 切入点 只关心饭店的事--> <property name="proxyInterfaces"> <value>com.zhaming.aop.restaurant.RestaurantService</value> </property> <!-- 对这些方式做那些拦截:切面 --> <property name="interceptorNames"> <list> <!-- <value>beforeAdvice</value> <value>afterAdvice</value> --> <value>compareAdvice</value> </list> </property> <property name="target"> <ref bean="restaurantServiceTarget" /> </property> </bean> </beans>
现在回头看看最初问的五个问题,那些杂事,是不是可以对应到软件中的几个概念:日志记录,性能统计,安全控制,事务处理,异常处理,更衍生的提还有缓存,持久化,同步等
原文链接:AOP的简单入门
]]>