注解
注解的基本知识:
1.示列
@Deprecated :标注XX过时
@SuppressWarning:抑制警告:unused:抑制的警告类型{ "unused", "rawtypes", "unchecked" }:数组,抑制的多个警告类型;all:抑制所有警告
@Override:保证用户确实是覆盖了父类的某个方法。
2.自定义注解
使用@interface关键字来声明注解;public @interface MyAnn1{};声明注解的属性字段:类型 字段名()[defalut 默认值];
注解的类型只能是下面的几个:String Class 八个类型 注解类型 枚举类型 及以上类型的1维数组;
特殊属性:String value;或者String[] value(); 使用时候直接给定取值,而不用加属性名称;
3.元注解
服务于注解的注解就是元注解
@Retention:指定注解的存活范围。默认是CLASS
RetentionPolicy:SOURCE|CLASS|RUNTIME
ElementType:TYPE|METHOD|。。。
1 import java.lang.annotation.ElementType; 2 import java.lang.annotation.Retention; 3 import java.lang.annotation.RetentionPolicy; 4 import java.lang.annotation.Target; 5 6 @Retention(RetentionPolicy.RUNTIME) 7 @Target(ElementType.METHOD) 8 public @interface MyTest { 9 long time() default -1; 10 }
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.
@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解
注解的反射
1 import java.lang.reflect.InvocationTargetException; 2 import java.lang.reflect.Method; 3 4 //反射注解:所有注解类型都是Annotation类型的子类 5 /* 6 java.lang.reflect.AnnotatedElement: 7 <T extends Annotation> getAnnotation(Class<T> annotationType): 8 获取指定类型的注解 9 Annotation[] getAnnotations():获取所有的注解 10 Annotation[] getDeclareAnnotations():返回直接存在于此元素上的所有注释 11 boolean isAnnotationPresend(Class<? extends Annotation>):有木有指定的注解 12 13 Class, Constructor, Field, Method, Package都实现了该接口 14 */ 15 public class MyTestRunner { 16 //执行测试: 17 /* 18 * 获取要测试的java类:MyJunitTest 19 * 取到其中的所有方法:Method 20 * 看看谁的方法前面有@MyTest的注解,谁有就执行谁 21 */ 22 public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException { 23 test2(); 24 } 25 //反射带有属性的注解 26 private static void test2() throws IllegalAccessException, 27 InvocationTargetException, InstantiationException { 28 Class clazz = MyJunitTest.class; 29 Method ms[] = clazz.getMethods(); 30 for(Method m:ms){ 31 MyTest myTest = m.getAnnotation(MyTest.class); 32 if(myTest!=null){ 33 //得到注解的属性 34 long timeLimit = myTest.time(); 35 if(timeLimit>-1){ 36 //有性能测试需求 37 long startTime = System.nanoTime(); 38 m.invoke(clazz.newInstance(), null); 39 long useTime = System.nanoTime()-startTime; 40 if(useTime>timeLimit){ 41 System.out.println(m.getName()+"执行效率没有测试通过"); 42 } 43 }else{ 44 //没有性能测试需求 45 m.invoke(clazz.newInstance(), null); 46 } 47 48 } 49 } 50 } 51 //注解的基本反射 52 private static void test1() throws IllegalAccessException, 53 InvocationTargetException, InstantiationException { 54 Class clazz = MyJunitTest.class; 55 Method ms[] = clazz.getMethods(); 56 for(Method m:ms){ 57 boolean b = m.isAnnotationPresent(MyTest.class); 58 // System.out.println(m.getName()+"方法上有木有MyTest注解:"+b); 59 if(b){ 60 m.invoke(clazz.newInstance(), null); 61 } 62 } 63 } 64 65 }
1. 指定运行时生命周期才能进行测试
2.指定在指定时间内执行完,才算是测试成功
注解
替换传统的XML配置文件。
比如:映射一个Servlet
------------------ public class MyServlet extends HttpServlet{ ... }
web.xml
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>com.itheima.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/servlet/MyServlet</url-pattern> </servlet-mapping> --------------------------------------------------------------
@WebServlet(urlPattern=”/servlet/MyServlet”) public class MyServlet extends HttpServlet{}
Servlet3.0的新特征
JavaEE5.0:Servlet2.5
JavaEE6.0:Servlet3.0
1、前提:
Tomcat7.X JDK6.X
2、Servlet3.0比Servlet2.5多了哪些功能
1.不用配置xml文件的设置,用注解
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebInitParam; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(urlPatterns="/servlet/ServletDemo1",initParams=@WebInitParam(name="encoding",value="ANNVAUE")) //注册配置的和web.xml配置的都会实例化一次 //建议:要么用注解,要么用web.xml public class ServletDemo extends HttpServlet { public void init() throws ServletException { System.out.println("初始化了"); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println(this); System.out.println("ServletDemo1执行了"); String value = getServletConfig().getInitParameter("encoding"); System.out.println(value); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } ServletDemo1
2.文件上传的改变
2.1:上传形式不变:
2.2:
import java.io.IOException; import java.util.Collection; import java.util.Collections; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; @WebServlet("/servlet/UploadServlet") @MultipartConfig //告知处理的是multipart/form-data类型的数据 public class UploadServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Collection<Part> parts = request.getParts(); // for(Part p:parts) // System.out.println(p); //传统方式获取参数能用了 // String name = request.getParameter("name"); // System.out.println(name); //处理文件上传 Part part = request.getPart("photo"); //获取上传文件的文件名 String headerValue = part.getHeader("Content-Disposition");// form-data; name="photo"; filename="AOP.txt" int index = headerValue.indexOf("filename="); String filename = headerValue.substring(index+10, headerValue.length()-1); part.write(getServletContext().getRealPath("/files")+"/"+filename); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } UploadServlet
3.web片段:
注解的引入使得web.xml变成可选的了。但是,我们还是可以使用web.xml。容器会根据web.xml中的metadata- complete元素的值来决定使用web.xml还是使用注解。如果该元素的值是true,那么容器不处理注解,web.xml是所有信息的来源。如果 该元素不存在或者其值不为true,容器才会处理注解。
Web框架的可插入性
我们前面说过了Servlet3.0的改进之一就是使得我们能够将框架和库插入到web应用程序中。这种可插入性减少了配置,并且提高了web应用程序的模块化。Servlet3.0是通过web模块布署描述片段(简称web片段)来实现插入性的。
一个web片段就是web.xml文件的一部分,被包含在框架特定的Jar包的META-INF目录中。Web片段使得该框架组件逻辑上就是web应用程序的一部分,不需要编辑web布署描述文件。
Web
片段中使用的元素和布署文件中使用的元素基本相同,除了根元素不一样。Web片段的根元素是<web-fragment>,而且文件名必须叫
做web-fragment.xml。容器只会在放在WEB-INF\lib目录下的Jar包中查找web-fragment.xml文件。如果这些
Jar包含有web-fragment.xml文件,容器就会装载需要的类来处理他们。
在web.xml中,我们要求Servlet的name必须唯一。同样的,在web.xml和所有的web片段中,Servlet的name也必须唯一。
下面就是一个web-fragment的例子:
<web-fragment> <servlet> <servlet-name>ControllerServlet</servlet-name> <servlet-class>com.app.control.ControllerServlet</servlet-class> </servlet> <listener> <listener-class>com.listener.AppServletContextListener</listener-class> </listener>
框架的Jar包是放在WEB-INF\lib目录下的,但是Servlet3.0提供两种方法指定多个web片段之间的顺序:
1. 绝对顺序
2. 相对顺序
我
们通过web.xml文件中的<absolute-ordering>元素来指定绝对顺序。这个元素有之元素name,name的值是各个
web片段的name元素的值。这样就指定了web片段的顺序。如果多个web片段有相同的名字,容器会忽略后出现的web片段。下面是一个指定绝对顺序
的例子:
<web-app> <name>DemoApp</name> <absolute-ordering> <name>WebFragment1</name> <name>WebFragment2</name> </absolute-ordering> </web-app>
相对顺序通过web-fragment.xml中的<ordering>元素来确定。Web片段的顺序 由<ordering>的子元素<before>,<after>和<others>来决定。当前的 web片段会放在所有的<before>元素中的片段之前。同样的,会放在所有的<after>元素中的片段之 后。<others>用来代替所有的其他片段。注意只有当web.xml中没有<absolute-ordering>时,容器 才会使用web片段中定义的相对顺序。
下面是一个帮助理解相对顺序的例子:
<web-fragment> <name>WebFragment1</name> <ordering><after>WebFragment2</after></ordering> </web-fragment>
<web-fragment> <name>WebFragment2</name> </web-fragment>
<web-fragment> <name>WebFragment3</name> <ordering><before><others/></before></ordering> </web-fragment>
这些文件将会按照下面的顺序被处理:
1. WebFragment3 2. WebFragment2 3. WebFragment1
包含WebFragment3的Jar文件被最先处理,包含WebFragment2的文件被第二个处理,包含WebFragment1的文件被最后处理。
如果既没有定义绝对顺序,也没有定义相对顺序,那么容器就认为所有的web片段间没有顺序上的依赖关系。
4.同步和异步:
同步:
同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。
异步:
将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。
同步,是所有的操作都做完,才返回给用户结果。即写完数据库之后,在相应用户,用户体验不好。
异步,不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好。
异步操作例子:
为了避免短时间大量的数据库操作,就使用缓存机制,也就是消息队列。先将数据放入消息队列,然后再慢慢写入数据库。
引入消息队列机制,虽然可以保证用户请求的快速响应,但是并没有使得我数据迁移的时间变短(即80万条数据写入mysql需要1个小时,用了redis之后,还是需要1个小时,只是保证用户的请求的快速响应。用户输入完http url请求之后,就可以把浏览器关闭了,干别的去了。如果不用redis,浏览器不能关闭)。
同步就没有任何价值了吗?银行的转账功能。
1 import java.io.IOException; 2 import java.io.PrintWriter; 3 4 import javax.servlet.AsyncContext; 5 import javax.servlet.ServletException; 6 import javax.servlet.annotation.WebServlet; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 @WebServlet(urlPatterns="/RegistServlet",asyncSupported=true) 11 public class RegistServlet extends HttpServlet { 12 13 public void doGet(HttpServletRequest request, HttpServletResponse response) 14 throws ServletException, IOException { 15 response.setContentType("text/html;charset=UTF-8"); 16 PrintWriter out = response.getWriter(); 17 out.write("RegistServlet开始运行了<br/>"); 18 out.flush(); 19 try { 20 Thread.sleep(2000); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); 23 } 24 out.write("注册成功了<br/>"); 25 out.flush(); 26 //发送激活邮件 27 AsyncContext ac = request.startAsync();//开始异步 28 new Thread(new SendMail(ac)).start();//3秒 29 out.write("RegistServlet运行结束了<br/>"); 30 out.flush(); 31 } 32 33 public void doPost(HttpServletRequest request, HttpServletResponse response) 34 throws ServletException, IOException { 35 doGet(request, response); 36 } 37 38 } 39 class SendMail implements Runnable{ 40 41 private AsyncContext ac; 42 43 public SendMail(AsyncContext ac) { 44 this.ac= ac; 45 } 46 47 public void run() { 48 try { 49 Thread.sleep(3000); 50 } catch (InterruptedException e) { 51 e.printStackTrace(); 52 } 53 //打印信息 54 try { 55 PrintWriter out = ac.getResponse().getWriter(); 56 out.write("邮件发送成功!"); 57 out.flush(); 58 } catch (IOException e) { 59 e.printStackTrace(); 60 } 61 } 62 63 }