Java基础加强第一天 : JDJava基础加强第一天 : JDK5.0新特性(泛型、枚举、for/in、可变参数、自动装箱拆箱、静态导入) + 反射 API(Class、Construtctor 、Field、Method )
字符串格式化 StringFormat、System.out.printf
注解技术
线程并发库
Java基础加强第二天 :上午:注解技术使用 @override ----- Servlet3.0 新特性 (之前课程中2.5 特性) 、动态代理技术(方法增强三种方式)
下午:复习线程基础知识、多线程编写案例 、Java5 提供线程并发库 线程池 、Socket网络编程(自定义服务器案例 tomcat)
Java Annotation 注解技术 是java5.0 新特性 (如果编译环境是java1.4 之前版本 无法对注解进行编译)
JDK官方提供了三个注解
@Override: 限定重写父类方法, 该注解只能用于方法 ------ 编译时检查,不构成覆盖 报错
* JDK5.0 override注解只能用于方法覆盖 JDK6.0 该注解可以用于接口的方法实现
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时 ----- 在编译器进行编译时 报出一个警告
* 为什么会有过时方法: 提供了新的方法取代 之前方法、发现某个方法存在安全隐患,不建议用户再使用
@SuppressWarnings: 抑制编译器警告. ---- 通知编译器在编译时 不要报出警告信息
* 使用 all 忽略所有警告信息
@SuppressWarnings("all")
// 抑制警告信息 类型
public static void main(String[] args) {
int a;
List list = new ArrayList();
Thread t = new Thread();
t.start();
t.stop();// 删除线,因为stop 方法已经过时
show();
}
// 通过deprecated 使 show 方法过时
@Deprecated
public static void show() {
}
}
interface I {
void p();
}
class A implements I {
@Override
// 这是JDK6 特性
public void p() {
}
}
class B extends A {
@Override
// 使用override 通知编译器,该方法是一个方法覆盖
// 如果该方法 不构成 方法覆盖,编译器就会报错
public void p() {
}
}
Annotation 其实就是代码里的特殊标记, 它用于替代配置文件!!
* 注解不但可以通知编译器,在运行时通知信息给 JVM虚拟机
注解典型应用:在一个类上面使用注解(配置信息),在程序中通过反射技术 获得配置注解信息 ---- 充当配置文件
已经有配置文件技术 xml、properties ,为什么还需要注解 ??
随着企业端软件应用越来越复杂,配置文件内容越来越多,导致上万行配置文件(配置文件过大,可读性会变得很差) ---- 反射案例:办晚会
* 引入注解目的:解决程序配置可读性问题 ,注解相当于代码中配置文件
注解程序开发流程
1、编写注解类
使用@interface 定义
所有注解类都默认继承 java.lang.annotation.Annotation 接口
注解支持类型:八种基本数据类型和String、Enum、Class、Annotation以及以上类型的数组)
如果注解属性提供默认值 ,使用注解是 不设置新的值
如果注解只有一个value 属性,使用注解 省略value=
public class AnnotationTest2 {
}
// 使用元注解修改 自定义注解
@interface MyAnnotation2 {
String[] value();// 只有一个value 属性
}
// 这就是一个注解
@interface MyAnnotation {
// 定义注解属性,和定义接口方法类似
// 格式:返回值、属性名() 默认值
int id(); // 这里id 是注解的 属性
String name(); // 默认 required
Class c() default MyAnnotation.class;
// 这里Date 不属于 8种基本类型 String enum Class Annotation --- 报错
// Date date();
}
@MyAnnotation(id = 0, name = "")
// 因为只有一个value 属性 省略 value=
@MyAnnotation2( { "aaa", "bbb" })
class MyAnnotationBean {
}
2、在一个类 应用注解类
3、通过反射技术获得注解信息
通过java.lang.reflect.AnnotatedElement 在程序运行时 获得注解信息
元注解:修饰注解的注解
@Retention 声明注解存活生命周期 --Source Class Runtime --- 开发中主要使用Runtime
@Target 声明注解可以修饰对象类型 ---- FIELD 、TYPE、METHOD
@Documented 注解可以被 生成API文档
@Inherited 注解在使用时,可以被子类继承
/**
* 元注解的使用
*
* @author seawind
*
*/
@Annotation1(name = "abc")
public class AnnotationTest3 {
@Annotation1(name = "abc")
int a;
@Annotation1(name = "abc")
public void p() {
}
}
// 因为父类使用@Inherited 注解,所以子类自动继承该注解
// @Annotation1(name = "abc")
class AnnotationTest3_2 extends AnnotationTest3 {
}
// 使用@Retention 声明注解声明周期
@Retention(RetentionPolicy.RUNTIME)
// RetentionPolicy.RUNTIME 运行时可见
// RetentionPolicy.CLASS 在字节码阶段仍然可见 --- 运行时丢失
// RetentionPolicy.SOURCE 在源码阶段可见 ---- 给编译器使用
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
// Target修饰注解可以应用目标类型
// Type 该注解可以用于修饰一个类 、接口、枚举
// FIELD 该注解可以修饰成员变量
@Documented
// 该注解的信息 在AnnotationTest3 生成API文档 时 存在
@Inherited
// 如果A类使用该注解,B类继承A类,B类自动继承该注解
@interface Annotation1 {
String name();
}
注解案例 : 在运行阶段,通过注解充当配置文件,利用反射技术获得注解中信息
银行转账 : 最大一次只能汇款XXX钱 (转账金额大小限制)
读取注解信息
步骤一:获得注解修饰反射对象 Class Field Method ---- 这些所有反射对象 都实现了 AnnotatedElement接口
步骤二:通过 AnnotatedElement 接口 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断目标注解是否存在
步骤三:通过 AnnotatedElement 接口 getAnnotation(Class<T> annotationClass) 获得目标注解
@Retention(RetentionPolicy.RUNTIME)
// 运行可见
@Target(ElementType.METHOD)//必须得写这句
// 修饰类
public @interface BankProperties {
double max();
}
/**
* 银行账户
*
* @author seawind
*
*/
public class BankAccount {
// 账户余额
private double amount;
public BankAccount(double amount) {
this.amount = amount;
}
@BankProperties(max = 5000)
public void transfer(double money) throws SecurityException,
NoSuchMethodException {
if (money > amount) {
throw new RuntimeException("余额不足!");
}
// 限制转账金额
// 方式一 读取配置文件
// String maxStr = ResourceBundle.getBundle("bank").getString("max");
// double max = Double.parseDouble(maxStr);
// if (money > max) {
// throw new RuntimeException("一次转账最大允许 " + max + "金额,您的转账额度超出了最大额度!");
// }
// 方式二 使用注解充当配置文件
// 读取注解中信息 AnnotatedElement
// 获得注解修饰反射对象
Class c = BankAccount.class;
Method m = c.getMethod("transfer", double.class);
// 判断目标注解是否存在
boolean isExist = m.isAnnotationPresent(BankProperties.class);
if (isExist) {// 注解存在
// 获得目标注解 --- 返回值可以强制转换为目标注解
BankProperties bankProperties = (BankProperties) m
.getAnnotation(BankProperties.class);
double max = bankProperties.max();// 获得max 属性
if (money > max) {
throw new RuntimeException("一次转账最大允许 " + max
+ "金额,您的转账额度超出了最大额度!");
}
}
System.out.println("该账户转出金额 :" + money);
amount -= money;
System.out.println("余额:" + amount);
}
}
Servlet3.0 新特性 ----- 对于web 开发很有用的 ---- JavaEE6 最新开发工具
1、web.xml 关于 Servlet 、Filter、Listener 通过注解进行配置
2、服务器异步处理机制
3、集成文件上传API
安装eclipse3.7 和 tomcat7.0
启动Eclipse 版本必须和 JDK版本 位数匹配
启动错误 eclipse.ini -Xmx512m 尝试 修改256 或者 128
在Eclipse集成tomcat 编写web工程
1、创建Dynamic web project --- 配置target runtime 运行环境 tomcat
* eclipse目录默认 没有WebRoot 目录 --- 有WebContent
2、eclipse和my eclipse发布方式不同
* myeclipse 将目录复制tomcat/webapps
* eclipse 内部有tomcat插件,将web目录复制插件目录/webapps
* 自动生成Servers工程目录 --- 保存tomcat启动需要配置文件
1、3.0 web 工程没有web.xml
@WebServlet("/hello")
@WebFilter("/hello")
@WebListener
* 当你配置欢迎页面、错误页面 编写web.xml
* metadata-complete web-app元素的属性 设置为true 将不支持注解技
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
metadata-complete="false"
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" >
</web-app>
2、异步处理支持
运行服务器端对Response 用多个线程统计信息响应生成
* 作用 改善用户体验
@WebServlet(value="/hello2",asyncSupported=true)//必须写上asyncSupported=true否则报异常
public class HelloServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloServlet2() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("start servlet ...<br/>");
// 模拟用户注册:将数据保存到数据库,发送激活邮件
response.getWriter().println("regist success... <br/>");
// 因为将用户数据保存到数据库后,发邮件是不是很复杂,很浪费时间
// 启动一个单独线程发送邮件,先将响应会送给客户端,等发送邮件成功后,再提升用户激活邮件已经发送
AsyncContext asyncContext = request.startAsync();
asyncContext.addListener(new AsyncListener() {
@Override
public void onTimeout(AsyncEvent arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onStartAsync(AsyncEvent arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onError(AsyncEvent arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onComplete(AsyncEvent arg0) throws IOException {
System.out.println("servlet 完成");
}
});
new Thread(new Exccutor(asyncContext)).start();
response.getWriter().println("end servlet...<br/>");
response.getWriter().flush();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
// 异步发送邮件程序
public class Exccutor implements Runnable {
private AsyncContext asyncContext;
public Exccutor(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public void run() {
// 模拟发送邮件
try {
Thread.sleep(5000);// 发邮件需要时间
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
asyncContext.getResponse().getWriter().print("active mail has been send!");
asyncContext.getResponse().getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、内部提供一套API 完成文件上传
编写文件上传form 表单
在服务器端Servlet 中 @MultipartConfig
* getParameter位于getPart操作之前 --- 必须先处理普通form域,再处理上传域
import java.io.IOException;
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;
/**
* Servlet implementation class UploadServlet
*/
@WebServlet("/upload")
@MultipartConfig//必须写
// 写注解 通知服务器form 是一个文件上传表单
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// 文件上传逻辑
// 获得用户名
String username = request.getParameter("username");
System.out.println(username);
// 获得上传文件内容
Part part = request.getPart("upload");
// 获得上传文件名 解析请求头中 Content-Dispostion
String filename = getFileName(part);
// 将文件写入c盘
part.write("c:\\"+filename);
}
public String getFileName(Part part) {
String filename = part.getHeader("content-disposition");
filename = filename.substring(filename.indexOf("filename=")+10,filename.length()-1);
int index = filename.lastIndexOf("\\");
if(index != -1){
filename = filename.substring(index+1);
}
return filename;
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
动态代理价值: 当.class文件 被类加载器加载 到内存 形成Class对象,所有程序访问都是针对Class对象 ,动态代理技术可以根据Class对象的实现接口,在内存中虚拟构造一个对象,该对象成为代理对象,访问真实对象的所有API的过程中 都将通过代理对象去访问 。
* 拦截对真实对象的访问 修改访问参数、拦截访问请求
* Java Spring 内部拦截器技术 -- 使用动态代理
动态代理案例
1、编写真实业务对象
2、使用动态代理,必须为真实对象提供一个接口
3、使用Proxy的newInstance 根据真实业务对象,创建代理对象
4. 根据代理对象取间接访问真实对象
5、拦截真实访问后,阻止对目标访问、修改参数、修改返回值
public class Liudehua implements Singable {
public void sing(double money) {
System.out.println("出场费:" + money);
System.out.println("德华演唱歌曲");
}
@Override
public void dance(double money) {
System.out.println("出场费:" + money);
System.out.println("德华跳舞了!");
}
}
public class MainApp {
public static void main(String[] args) {
final Liudehua liudehua = new Liudehua();
// 根据真实业务对象创建代理对象
Singable proxy = (Singable) Proxy.newProxyInstance(liudehua.getClass()
.getClassLoader(), liudehua.getClass().getInterfaces(),
new InvocationHandler() {
@Override
/*
* proxy 代理对象本身,method 当前执行方法,args 方法真实参数
*/
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("被代理了");
// 拦截后,修改参数 阻止
if (method.getName().equals("sing")) {
double money = (Double) args[0];
if (money < 5000) {
throw new RuntimeException("免谈");
}
money -= 20000; // 取走20000
method.invoke(liudehua, money);
}
if (method.getName().equals("dance")) {
double money = (Double) args[0];
if (money < 100000) {
throw new RuntimeException("免谈");
}
money -= 30000; // 取走30000
method.invoke(liudehua, money);
}
return null;
}
});
// 通过代理对象 访问 真实业务对象 --- 无论执行什么方法 invoke都将执行
proxy.sing(50000); // invoke 执行 method --- sing args --- 50000
proxy.dance(100000); // invoke 执行 method --- dance args ---- 100000
}
}
银行取钱案例 ATM : 取款手续费用
真实业务对象如果想动态代理,生成代理对象 -------- 实现接口
* 在实际企业开发中,动态代理经常用于加强方法原来逻辑功能 ---- 无需修改原来程序逻辑,就可以实现方法增强
public interface Account {
// 存钱
public void saveMoney(double money);
// 取钱
public double getMoney(double money);
// 查询账户余额
public double queryRestMoney();
}
public class MyAccount implements Account {
private double amount;
@Override
public double getMoney(double money) {
if (money > amount) {
// 余额不足
throw new RuntimeException("余额不足!");
}
amount = amount - money;
return money;
}
@Override
public double queryRestMoney() {
return amount;
}
@Override
public void saveMoney(double money) {
amount = amount + money;
}
}
public class ATM {
public static void main(String[] args) {
final Account account = new MyAccount();// 账户对象
// 使用动态代理,根据真实账户 生成代理对象
// 代理对象返回类型 必须转换 接口类型
Account accountProxy = (Account) Proxy.newProxyInstance(account
.getClass().getClassLoader(), account.getClass()
.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 取款时 收取1%手续费用
// 需要加强的方法
// 使用if 判断 该方法 逻辑需要加强
if (method.getName().equals("getMoney")) {// 用户在取款
// 从账户中取出 101% 金额
// 获得要取款金额
double want_money = (Double) args[0];
// 从账户中 取出101% 金额
double real_money = want_money * 1.01;
// 进行取款
double getMoney = (Double) method.invoke(account,
real_money);
System.out.println("取款:" + want_money + ",收取手续费用 "
+ (real_money - want_money));
return want_money;// 返回要取款金额
}
// 不需要加强的方法
return method.invoke(account, args);
}
});
accountProxy.saveMoney(10000);
System.out.println("存款 10000");
double money = accountProxy.getMoney(5000);
System.out.println("取款 5000");
double restMoney = accountProxy.queryRestMoney();
System.out.println("查询余额:" + restMoney);
}
}
线程和进程区别 ?一个进程是多个线程组成的,进程是操作系统管理内存最小单位,线程使用内存,从进程申请
线程的创建有两种方式:extends Thread、implements Runnable接口
* 获得当前线程的名字 Thread.currentThread().getName();
* 优先使用Runnable 接口 ---- 因为java单继承,如果继承Thread 就不能继承其他类
线程的四种状态:创建(new Thread().start())、执行状态 (线程run方法正在运行)、阻塞状态(run方法在执行一段时间后暂停执行)、线程死亡(run方法执行结束、发生异常)
* 新建 --- 运行 (获得cpu的使用权)
* 运行 --- 阻塞 (Thread.sleep join 使用同步锁 wait IO读写、网络传输)
* 阻塞 --- 运行 结束阻塞,重新获得cpu使用权
sleep 使当前线程睡眠一段时间,睡眠过程中,不释放锁资源
join 等待目标线程执行结束后,其他线程才能继续执行
同步锁,当运行一个代码块,使用同步锁机制,一个线程已经将代码块锁定,另一个线程无法进入代码块 ---- 执行等待锁
wait 当你获得一个同步锁后,选择在锁上面监视器进行等待,等待必须由别人进行 唤醒 notify notifyAll
锁:保证一段程序同一时间只能由一个线程进行执行 ---- 阻止两个线程同时执行一段代码
* java中每个对象都可以作为锁 ----- 锁的本质,锁定一块内存地址
public class MyThread2 {
public static void main(String[] args) {
Object lock = new Object();
ThreadA a = new ThreadA(lock);
new Thread(a).start();
ThreadB b = new ThreadB(lock);
new Thread(b).start();
// 保证顺序不乱 --- 加锁 锁定同一个内存
}
}
class ThreadA implements Runnable {
private Object lock;
public ThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class ThreadB implements Runnable {
private Object lock;
public ThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
* 特殊锁 锁定方法
public static synchronized void a() {} ---- 锁定 类的Class对象
public synchronized void b() {} --- 锁定this 对象
同步锁案例 : 售票系统 模拟火车站多个售票窗口同时售票 ---- 确保同一个时间 只能有一个窗口打票
public class SaleTicketSystem {
public static void main(String[] args) {
TicketSystem system = new TicketSystem();// 票源唯一
for (int i = 0; i < 5; i++) {// 模拟5个窗口同时卖票
SaleTicket saleTicket = new SaleTicket(system);
new Thread(saleTicket).start();
}
}
}
// 票源
class TicketSystem {
private int totalTickets = 100; // 总票数
private int hasSaleTickets = 0; // 已经售票编号
// 添加同步后,同一时间只能有一个窗口卖票
public synchronized void saleTicket() {
if (totalTickets <= 0) {
throw new RuntimeException("票已经卖完");
}
// 卖掉一张票
hasSaleTickets++;
System.out.println("打印一张票!" + hasSaleTickets);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 总票数 -1
totalTickets--;
System.out.println("剩余票数:" + totalTickets);
}
}
//售票
class SaleTicket implements Runnable {
private TicketSystem ticketSystem;
public SaleTicket(TicketSystem ticketSystem) {
this.ticketSystem = ticketSystem;
}
@Override
public void run() {
while (true) {
try {
ticketSystem.saleTicket();
} catch (RuntimeException e) {
break;
}
}
}
死锁原因:互相等待 ------ 同步代码块嵌套
* 尽量同步代码块不要嵌套
public class DeadLockTest {
public static void main(String[] args) {
Object pen = new Object();// 笔
Object note = new Object(); // 本
new Thread(new AThread(pen, note)).start();
new Thread(new BThread(pen, note)).start();
}
}
class AThread implements Runnable {
private Object pen;
private Object note;
public AThread(Object pen, Object note) {
this.pen = pen;
this.note = note;
}
@Override
public void run() {
// 先获得笔 --- 再获得本
synchronized (pen) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (note) {
System.out.println("A 写字");
}
}
}
}
class BThread implements Runnable {
private Object pen;
private Object note;
public BThread(Object pen, Object note) {
this.pen = pen;
this.note = note;
}
@Override
public void run() {
// 先获得 本 --- 再获得笔
synchronized (note) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (pen) {
System.out.println("B 写字");
}
}
}
}
锁监视器操作 ----- java中所有对象都可以作为锁,java 中 Object类 提供 wait notify notifyAll
wait :当前线程 在锁对象的监视器上进行等待
notify : 唤醒 一个 在 指定锁对象的监视器上等待的线程
notifyAll : 唤醒所有在指定 锁对象的监视器上等待的线程
* 线程通信案例 (当两个线程协同完成某个任务 )---- 生产者消费者模型
生产者消费者场景 :一个生产者、一个消费者,生产者生产一个面包,通知消费者来吃,消费者吃完了,通知生产者生产
* 生产者发现面包还没吃 需要等待
* 消费者发现面包已经吃了 需要等待
/**
* 生产者 消费者案例
*
* @author seawind
*
*/
public class ProducerConsumerTest {
public static void main(String[] args) {
CakeHouse cakeHouse = new CakeHouse();
new Thread(new Producer(cakeHouse)).start();
new Thread(new Consumer(cakeHouse)).start();
}
}
// 生产者
class Producer implements Runnable {
private CakeHouse cakeHouse;
public Producer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
// 生产100个蛋糕
for (int i = 0; i < 100; i++) {
cakeHouse.put();
}
}
}
// 消费者
class Consumer implements Runnable {
private CakeHouse cakeHouse;
public Consumer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
cakeHouse.take();
}
}
}
class CakeHouse {
// 蛋糕房 蛋糕窗口
private List<Object> list = new LinkedList<Object>();
private int index;
// 必须先同步,才能使用锁监视器
public synchronized void put() {
while (!list.isEmpty()) {
// 已经有蛋糕
try {
this.wait(); // 调用wait的对象 就是锁定对象
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产蛋糕
list.add(new Object());
index++;
System.out.println("生产者 生产蛋糕 " + index);
// 通知消费者 快去吃
this.notify();
}
public synchronized void take() {
while (list.isEmpty()) {
// 没蛋糕
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 吃掉蛋糕
list.remove(0);
System.out.println("消费者消费蛋糕 " + index);
// 通知生产者生产
this.notify();
}
}
JDK5.0 之后提供两个接口 Lock 和 Condition ,简化同步和锁编程
java.util.concurrent.locks.Lock ---- 取代 synchronized
java.util.concurrent.locks.Condition ---- 取代 wait notify
* 在同一个锁上面 建立多个监视器
public class SaleTicketSystem {
public static void main(String[] args) {
TicketSystem system = new TicketSystem();// 票源唯一
for (int i = 0; i < 5; i++) {// 模拟5个窗口同时卖票
SaleTicket saleTicket = new SaleTicket(system);
new Thread(saleTicket).start();
}
}
}
// 票源
class TicketSystem {
private int totalTickets = 100; // 总票数
private int hasSaleTickets = 0; // 已经售票编号
private Lock lock = new ReentrantLock();
// 添加同步后,同一时间只能有一个窗口卖票
public void saleTicket() {
// 加锁
lock.lock();
if (totalTickets <= 0) {
throw new RuntimeException("票已经卖完");
}
// 卖掉一张票
hasSaleTickets++;
System.out.println("打印一张票!" + hasSaleTickets);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 总票数 -1
totalTickets--;
System.out.println("剩余票数:" + totalTickets);
// 解锁
lock.unlock();
}
}
class SaleTicket implements Runnable {
private TicketSystem ticketSystem;
public SaleTicket(TicketSystem ticketSystem) {
this.ticketSystem = ticketSystem;
}
@Override
public void run() {
while (true) {
try {
ticketSystem.saleTicket();
} catch (RuntimeException e) {
break;
}
}
}
}
/**
* 生产者 消费者案例
*
* @author seawind
*
*/
public class ProducerConsumerTest {
public static void main(String[] args) {
CakeHouse cakeHouse = new CakeHouse();
new Thread(new Producer(cakeHouse)).start();
new Thread(new Consumer(cakeHouse)).start();
}
}
// 生产者
class Producer implements Runnable {
private CakeHouse cakeHouse;
public Producer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
// 生产100个蛋糕
for (int i = 0; i < 100; i++) {
cakeHouse.put();
}
}
}
// 消费者
class Consumer implements Runnable {
private CakeHouse cakeHouse;
public Consumer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
cakeHouse.take();
}
}
}
class CakeHouse {
// 蛋糕房 蛋糕窗口
private List<Object> list = new LinkedList<Object>();
private int index;
private Lock lock = new ReentrantLock();
// 生产者专用监视器
private Condition producerCondition = lock.newCondition();
// 消费者专用监视器
private Condition consumerCondition = lock.newCondition();
public void put() {
lock.lock();
while (!list.isEmpty()) {
// 已经有蛋糕
try {
producerCondition.await(); // 在生产者监视器上等
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产蛋糕
list.add(new Object());
index++;
System.out.println("生产者 生产蛋糕 " + index);
// 通知消费者 快去吃
consumerCondition.signal();
lock.unlock();
}
public void take() {
lock.lock();
while (list.isEmpty()) {
// 没蛋糕
try {
consumerCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 吃掉蛋糕
list.remove(0);
System.out.println("消费者消费蛋糕 " + index);
// 通知生产者生产
producerCondition.signal();
lock.unlock();
}
}
java.util.concurrent 包 和 子包 ---- ArrayBlockingQueue<E> CopyOnWriteArrayList<E> LinkedBlockingQueue<E>
线程池技术 Excutors
为什么用线程池,线程创建、关闭释放资源 ---- 消耗程序性能
一次创建多个线程,做任务,随机获得一个线程,完成任务,将线程归还线程池
newFixedThreadPool(int nThreads) 固定线程数量线程池
newCachedThreadPool() 返回根据程序需要自动扩充大小 线程池 ----- 最常用
newSingleThreadExecutor() 返回单线程处理程序
shutdown与shutdownNow的比较
shutdown 完成当前线程池中所有任务 再关闭
shutdownNow 会对当前线程池中所有线程,调用interrupt 尝试打断当前线程,如果无法打断,会执行结束
public class ExcutorsTest {
// java中编写程序测试多线程,一定不能用 junit --- System.exit
public static void main(String[] args) {
// 创建线程池
// 创建固定数量为3 线程池
// ExecutorService service = Executors.newFixedThreadPool(5);
// 创建 自增扩充大小 线程池
ExecutorService service = Executors.newCachedThreadPool();
// 单一线程对象
// ExecutorService service = Executors.newSingleThreadExecutor();
// 开启十个线程 分别输出
for (int i = 0; i < 10; i++) {
service.execute(new MyExcutor());
}
// 关闭连接池
service.shutdown();// 当之前任务都结束后,尝试关闭连接池
// service.shutdownNow();// 尝试马上关闭连接池,但是不一定能关闭
// interrupt
}
}
class MyExcutor implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
------------------------------------------------------------------------------------------------------------------
OSI 七层体系结构: 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
*协议层次越高,越容易让人理解, 层次越低,数据越接近0 1
TCP/IP 四层 : 应用层、传输层、网际层、网络接口层
应用层、传输层
应用层:HTTP SMTP POP3 FTP TELNET
传输层:TCP(不允许丢包 三次握手) UDP(广播 允许丢包)
三次握手:
A 向 B 发送一个消息:能听到我说话吗
B 回复 A 消息:我能听到,你能听到我说话吗
A 回复 B :我能听到
TCP发送数据没有收到对方回应,选择重新发送 ---- 时间限制 超时
Socket 两台计算机之间一个连接 ---- 两台计算机可以通信
使用socket建立双方连接 -----传输协议需要自己编写 面向底层协议
socket 编写程序 可以模拟服务器,可以模拟客户端
服务器如何编写
* 使用socket进行通信过程中,如果调用in.readLine 但是对方没有写 ---- 程序一直等待 、out.print向对方发送信息 没有阻塞
/**
* 模拟服务器
*
* @author seawind
*
*/
public class Server {
public static void main(String[] args) throws IOException {
// 步骤一 创建ServerSocket 对象
ServerSocket serverSocket = new ServerSocket(9000);
// 连接服务器需要 ip 和 端口
// 步骤二 等待客户端来连接
Socket socket = serverSocket.accept(); // socket代表一个连接
// 步骤三 需要获得流
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 收取对方信息 用 in
// 发送给对方信息 用 out
out.println("Hello !");// 输出信息 因为用字符流 ,所以flush
out.flush();
System.out.println(in.readLine());
}
}
/**
* 客户端
*
* @author seawind
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException,
IOException {
// 步骤一 连接服务器
Socket socket = new Socket("localhost", 9000);
// 步骤二 获得流
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 通过in 获得信息
System.out.println(in.readLine());
out.println("你好服务器!");
out.flush();
}
}
socket 案例 ----- 模拟tomcat服务器
/**
* 模拟tomcat server
*
* @author seawind
*
*/
public class TomcatServer {
public static void main(String[] args) throws IOException {
// 步骤一
ServerSocket serverSocket = new ServerSocket(9000);
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
while (true) {
// 步骤二 获得与客户端连接
Socket socket = serverSocket.accept();
DealResponse dealResponse = new DealResponse(socket);
// 将处理任务 加入线程池
executorService.execute(dealResponse);
}
}
static class DealResponse implements Runnable {
private Socket socket;
public DealResponse(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 步骤三 流
OutputStream bout = new BufferedOutputStream(socket
.getOutputStream());
// PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// 浏览器连接服务器 发送HTTP请求
String requestline = in.readLine();// 获得请求行
// 解析资源路径
String path = parse(requestline);
System.out.println(path);
// 判断目标文件是否存在
File file = new File("webroot" + path);
// 判断服务器上面 有没有客户访问文件
if (file.exists()) {
// 回写HTTP协议格式
bout.write("HTTP/1.1 200 OK\r\n".getBytes());
// 根据文件扩展名得到文件格式
bout
.write(("Content-Type:" + getType(file.getName()) + "\r\n")
.getBytes()); // 不同文件类型是不同的
bout.write(("Content-Length:" + file.length() + "\r\n\r\n")
.getBytes());
// 存在
InputStream fis = new BufferedInputStream(
new FileInputStream(file));
int temp;
while ((temp = fis.read()) != -1) {
bout.write(temp);
}
bout.flush();
bout.close();
fis.close();
System.out.println("文件找到了");
} else {
// 不存在
bout.write("file not found".getBytes());
bout.flush();
System.out.println("文件找不到!");
bout.close();
}
// 断开socket连接
in.close();
socket.close();
} catch (FileNotFoundException e) {
// e.printStackTrace();
} catch (IOException e) {
// e.printStackTrace();
}
}
}
private static String getType(String name) {
// 获得扩展名
String ext = name.substring(name.lastIndexOf(".") + 1);
String type = ResourceBundle.getBundle("mime").getString(ext);
return type;
}
private static String parse(String requestline) {
return requestline.split(" ")[1];
}
}
---------------------------------------------------------------------------------------
注解的使用 ---- 定义注解,利用反射解析注解内容 (案例:银行转账最大金额)
Servlet3.0 注解开发Servlet、异步技术、文件上传
动态代理 (案例:德华案例、银行取款 收取手续费用)
多线程:两种线程创建方式、四种状态、同步和锁、死锁、wait和notify (案例:卖票、生产蛋糕) ---- 使用JDK5 Lock和Condition 重写
socket编程 服务器怎么写 客户端怎么写
* 实际socket案例 按照协议发送内容 模拟tomcat 服务器 遵循HTTP协议
K5.0新特性(泛型、枚举、for/in、可变参数、自动装箱拆箱、静态导入) + 反射 API(Class、Construtctor 、Field、Method )
字符串格式化 StringFormat、System.out.printf
注解技术
线程并发库
Java基础加强第二天 :上午:注解技术使用 @override ----- Servlet3.0 新特性 (之前课程中2.5 特性) 、动态代理技术(方法增强三种方式)
下午:复习线程基础知识、多线程编写案例 、Java5 提供线程并发库 线程池 、Socket网络编程(自定义服务器案例 tomcat)
Java Annotation 注解技术 是java5.0 新特性 (如果编译环境是java1.4 之前版本 无法对注解进行编译)
JDK官方提供了三个注解
@Override: 限定重写父类方法, 该注解只能用于方法 ------ 编译时检查,不构成覆盖 报错
* JDK5.0 override注解只能用于方法覆盖 JDK6.0 该注解可以用于接口的方法实现
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时 ----- 在编译器进行编译时 报出一个警告
* 为什么会有过时方法: 提供了新的方法取代 之前方法、发现某个方法存在安全隐患,不建议用户再使用
@SuppressWarnings: 抑制编译器警告. ---- 通知编译器在编译时 不要报出警告信息
* 使用 all 忽略所有警告信息
@SuppressWarnings("all")
// 抑制警告信息 类型
public static void main(String[] args) {
int a;
List list = new ArrayList();
Thread t = new Thread();
t.start();
t.stop();// 删除线,因为stop 方法已经过时
show();
}
// 通过deprecated 使 show 方法过时
@Deprecated
public static void show() {
}
}
interface I {
void p();
}
class A implements I {
@Override
// 这是JDK6 特性
public void p() {
}
}
class B extends A {
@Override
// 使用override 通知编译器,该方法是一个方法覆盖
// 如果该方法 不构成 方法覆盖,编译器就会报错
public void p() {
}
}
Annotation 其实就是代码里的特殊标记, 它用于替代配置文件!!
* 注解不但可以通知编译器,在运行时通知信息给 JVM虚拟机
注解典型应用:在一个类上面使用注解(配置信息),在程序中通过反射技术 获得配置注解信息 ---- 充当配置文件
已经有配置文件技术 xml、properties ,为什么还需要注解 ??
随着企业端软件应用越来越复杂,配置文件内容越来越多,导致上万行配置文件(配置文件过大,可读性会变得很差) ---- 反射案例:办晚会
* 引入注解目的:解决程序配置可读性问题 ,注解相当于代码中配置文件
注解程序开发流程
1、编写注解类
使用@interface 定义
所有注解类都默认继承 java.lang.annotation.Annotation 接口
注解支持类型:八种基本数据类型和String、Enum、Class、Annotation以及以上类型的数组)
如果注解属性提供默认值 ,使用注解是 不设置新的值
如果注解只有一个value 属性,使用注解 省略value=
public class AnnotationTest2 {
}
// 使用元注解修改 自定义注解
@interface MyAnnotation2 {
String[] value();// 只有一个value 属性
}
// 这就是一个注解
@interface MyAnnotation {
// 定义注解属性,和定义接口方法类似
// 格式:返回值、属性名() 默认值
int id(); // 这里id 是注解的 属性
String name(); // 默认 required
Class c() default MyAnnotation.class;
// 这里Date 不属于 8种基本类型 String enum Class Annotation --- 报错
// Date date();
}
@MyAnnotation(id = 0, name = "")
// 因为只有一个value 属性 省略 value=
@MyAnnotation2( { "aaa", "bbb" })
class MyAnnotationBean {
}
2、在一个类 应用注解类
3、通过反射技术获得注解信息
通过java.lang.reflect.AnnotatedElement 在程序运行时 获得注解信息
元注解:修饰注解的注解
@Retention 声明注解存活生命周期 --Source Class Runtime --- 开发中主要使用Runtime
@Target 声明注解可以修饰对象类型 ---- FIELD 、TYPE、METHOD
@Documented 注解可以被 生成API文档
@Inherited 注解在使用时,可以被子类继承
/**
* 元注解的使用
*
* @author seawind
*
*/
@Annotation1(name = "abc")
public class AnnotationTest3 {
@Annotation1(name = "abc")
int a;
@Annotation1(name = "abc")
public void p() {
}
}
// 因为父类使用@Inherited 注解,所以子类自动继承该注解
// @Annotation1(name = "abc")
class AnnotationTest3_2 extends AnnotationTest3 {
}
// 使用@Retention 声明注解声明周期
@Retention(RetentionPolicy.RUNTIME)
// RetentionPolicy.RUNTIME 运行时可见
// RetentionPolicy.CLASS 在字节码阶段仍然可见 --- 运行时丢失
// RetentionPolicy.SOURCE 在源码阶段可见 ---- 给编译器使用
@Target(value = { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD })
// Target修饰注解可以应用目标类型
// Type 该注解可以用于修饰一个类 、接口、枚举
// FIELD 该注解可以修饰成员变量
@Documented
// 该注解的信息 在AnnotationTest3 生成API文档 时 存在
@Inherited
// 如果A类使用该注解,B类继承A类,B类自动继承该注解
@interface Annotation1 {
String name();
}
注解案例 : 在运行阶段,通过注解充当配置文件,利用反射技术获得注解中信息
银行转账 : 最大一次只能汇款XXX钱 (转账金额大小限制)
读取注解信息
步骤一:获得注解修饰反射对象 Class Field Method ---- 这些所有反射对象 都实现了 AnnotatedElement接口
步骤二:通过 AnnotatedElement 接口 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断目标注解是否存在
步骤三:通过 AnnotatedElement 接口 getAnnotation(Class<T> annotationClass) 获得目标注解
@Retention(RetentionPolicy.RUNTIME)
// 运行可见
@Target(ElementType.METHOD)//必须得写这句
// 修饰类
public @interface BankProperties {
double max();
}
/**
* 银行账户
*
* @author seawind
*
*/
public class BankAccount {
// 账户余额
private double amount;
public BankAccount(double amount) {
this.amount = amount;
}
@BankProperties(max = 5000)
public void transfer(double money) throws SecurityException,
NoSuchMethodException {
if (money > amount) {
throw new RuntimeException("余额不足!");
}
// 限制转账金额
// 方式一 读取配置文件
// String maxStr = ResourceBundle.getBundle("bank").getString("max");
// double max = Double.parseDouble(maxStr);
// if (money > max) {
// throw new RuntimeException("一次转账最大允许 " + max + "金额,您的转账额度超出了最大额度!");
// }
// 方式二 使用注解充当配置文件
// 读取注解中信息 AnnotatedElement
// 获得注解修饰反射对象
Class c = BankAccount.class;
Method m = c.getMethod("transfer", double.class);
// 判断目标注解是否存在
boolean isExist = m.isAnnotationPresent(BankProperties.class);
if (isExist) {// 注解存在
// 获得目标注解 --- 返回值可以强制转换为目标注解
BankProperties bankProperties = (BankProperties) m
.getAnnotation(BankProperties.class);
double max = bankProperties.max();// 获得max 属性
if (money > max) {
throw new RuntimeException("一次转账最大允许 " + max
+ "金额,您的转账额度超出了最大额度!");
}
}
System.out.println("该账户转出金额 :" + money);
amount -= money;
System.out.println("余额:" + amount);
}
}
Servlet3.0 新特性 ----- 对于web 开发很有用的 ---- JavaEE6 最新开发工具
1、web.xml 关于 Servlet 、Filter、Listener 通过注解进行配置
2、服务器异步处理机制
3、集成文件上传API
安装eclipse3.7 和 tomcat7.0
启动Eclipse 版本必须和 JDK版本 位数匹配
启动错误 eclipse.ini -Xmx512m 尝试 修改256 或者 128
在Eclipse集成tomcat 编写web工程
1、创建Dynamic web project --- 配置target runtime 运行环境 tomcat
* eclipse目录默认 没有WebRoot 目录 --- 有WebContent
2、eclipse和my eclipse发布方式不同
* myeclipse 将目录复制tomcat/webapps
* eclipse 内部有tomcat插件,将web目录复制插件目录/webapps
* 自动生成Servers工程目录 --- 保存tomcat启动需要配置文件
1、3.0 web 工程没有web.xml
@WebServlet("/hello")
@WebFilter("/hello")
@WebListener
* 当你配置欢迎页面、错误页面 编写web.xml
* metadata-complete web-app元素的属性 设置为true 将不支持注解技
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
metadata-complete="false"
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" >
</web-app>
2、异步处理支持
运行服务器端对Response 用多个线程统计信息响应生成
* 作用 改善用户体验
@WebServlet(value="/hello2",asyncSupported=true)//必须写上asyncSupported=true否则报异常
public class HelloServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloServlet2() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("start servlet ...<br/>");
// 模拟用户注册:将数据保存到数据库,发送激活邮件
response.getWriter().println("regist success... <br/>");
// 因为将用户数据保存到数据库后,发邮件是不是很复杂,很浪费时间
// 启动一个单独线程发送邮件,先将响应会送给客户端,等发送邮件成功后,再提升用户激活邮件已经发送
AsyncContext asyncContext = request.startAsync();
asyncContext.addListener(new AsyncListener() {
@Override
public void onTimeout(AsyncEvent arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onStartAsync(AsyncEvent arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onError(AsyncEvent arg0) throws IOException {
// TODO Auto-generated method stub
}
@Override
public void onComplete(AsyncEvent arg0) throws IOException {
System.out.println("servlet 完成");
}
});
new Thread(new Exccutor(asyncContext)).start();
response.getWriter().println("end servlet...<br/>");
response.getWriter().flush();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
// 异步发送邮件程序
public class Exccutor implements Runnable {
private AsyncContext asyncContext;
public Exccutor(AsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public void run() {
// 模拟发送邮件
try {
Thread.sleep(5000);// 发邮件需要时间
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
asyncContext.getResponse().getWriter().print("active mail has been send!");
asyncContext.getResponse().getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、内部提供一套API 完成文件上传
编写文件上传form 表单
在服务器端Servlet 中 @MultipartConfig
* getParameter位于getPart操作之前 --- 必须先处理普通form域,再处理上传域
import java.io.IOException;
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;
/**
* Servlet implementation class UploadServlet
*/
@WebServlet("/upload")
@MultipartConfig//必须写
// 写注解 通知服务器form 是一个文件上传表单
public class UploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UploadServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// 文件上传逻辑
// 获得用户名
String username = request.getParameter("username");
System.out.println(username);
// 获得上传文件内容
Part part = request.getPart("upload");
// 获得上传文件名 解析请求头中 Content-Dispostion
String filename = getFileName(part);
// 将文件写入c盘
part.write("c:\\"+filename);
}
public String getFileName(Part part) {
String filename = part.getHeader("content-disposition");
filename = filename.substring(filename.indexOf("filename=")+10,filename.length()-1);
int index = filename.lastIndexOf("\\");
if(index != -1){
filename = filename.substring(index+1);
}
return filename;
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
动态代理价值: 当.class文件 被类加载器加载 到内存 形成Class对象,所有程序访问都是针对Class对象 ,动态代理技术可以根据Class对象的实现接口,在内存中虚拟构造一个对象,该对象成为代理对象,访问真实对象的所有API的过程中 都将通过代理对象去访问 。
* 拦截对真实对象的访问 修改访问参数、拦截访问请求
* Java Spring 内部拦截器技术 -- 使用动态代理
动态代理案例
1、编写真实业务对象
2、使用动态代理,必须为真实对象提供一个接口
3、使用Proxy的newInstance 根据真实业务对象,创建代理对象
4. 根据代理对象取间接访问真实对象
5、拦截真实访问后,阻止对目标访问、修改参数、修改返回值
public class Liudehua implements Singable {
public void sing(double money) {
System.out.println("出场费:" + money);
System.out.println("德华演唱歌曲");
}
@Override
public void dance(double money) {
System.out.println("出场费:" + money);
System.out.println("德华跳舞了!");
}
}
public class MainApp {
public static void main(String[] args) {
final Liudehua liudehua = new Liudehua();
// 根据真实业务对象创建代理对象
Singable proxy = (Singable) Proxy.newProxyInstance(liudehua.getClass()
.getClassLoader(), liudehua.getClass().getInterfaces(),
new InvocationHandler() {
@Override
/*
* proxy 代理对象本身,method 当前执行方法,args 方法真实参数
*/
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("被代理了");
// 拦截后,修改参数 阻止
if (method.getName().equals("sing")) {
double money = (Double) args[0];
if (money < 5000) {
throw new RuntimeException("免谈");
}
money -= 20000; // 取走20000
method.invoke(liudehua, money);
}
if (method.getName().equals("dance")) {
double money = (Double) args[0];
if (money < 100000) {
throw new RuntimeException("免谈");
}
money -= 30000; // 取走30000
method.invoke(liudehua, money);
}
return null;
}
});
// 通过代理对象 访问 真实业务对象 --- 无论执行什么方法 invoke都将执行
proxy.sing(50000); // invoke 执行 method --- sing args --- 50000
proxy.dance(100000); // invoke 执行 method --- dance args ---- 100000
}
}
银行取钱案例 ATM : 取款手续费用
真实业务对象如果想动态代理,生成代理对象 -------- 实现接口
* 在实际企业开发中,动态代理经常用于加强方法原来逻辑功能 ---- 无需修改原来程序逻辑,就可以实现方法增强
public interface Account {
// 存钱
public void saveMoney(double money);
// 取钱
public double getMoney(double money);
// 查询账户余额
public double queryRestMoney();
}
public class MyAccount implements Account {
private double amount;
@Override
public double getMoney(double money) {
if (money > amount) {
// 余额不足
throw new RuntimeException("余额不足!");
}
amount = amount - money;
return money;
}
@Override
public double queryRestMoney() {
return amount;
}
@Override
public void saveMoney(double money) {
amount = amount + money;
}
}
public class ATM {
public static void main(String[] args) {
final Account account = new MyAccount();// 账户对象
// 使用动态代理,根据真实账户 生成代理对象
// 代理对象返回类型 必须转换 接口类型
Account accountProxy = (Account) Proxy.newProxyInstance(account
.getClass().getClassLoader(), account.getClass()
.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 取款时 收取1%手续费用
// 需要加强的方法
// 使用if 判断 该方法 逻辑需要加强
if (method.getName().equals("getMoney")) {// 用户在取款
// 从账户中取出 101% 金额
// 获得要取款金额
double want_money = (Double) args[0];
// 从账户中 取出101% 金额
double real_money = want_money * 1.01;
// 进行取款
double getMoney = (Double) method.invoke(account,
real_money);
System.out.println("取款:" + want_money + ",收取手续费用 "
+ (real_money - want_money));
return want_money;// 返回要取款金额
}
// 不需要加强的方法
return method.invoke(account, args);
}
});
accountProxy.saveMoney(10000);
System.out.println("存款 10000");
double money = accountProxy.getMoney(5000);
System.out.println("取款 5000");
double restMoney = accountProxy.queryRestMoney();
System.out.println("查询余额:" + restMoney);
}
}
线程和进程区别 ?一个进程是多个线程组成的,进程是操作系统管理内存最小单位,线程使用内存,从进程申请
线程的创建有两种方式:extends Thread、implements Runnable接口
* 获得当前线程的名字 Thread.currentThread().getName();
* 优先使用Runnable 接口 ---- 因为java单继承,如果继承Thread 就不能继承其他类
线程的四种状态:创建(new Thread().start())、执行状态 (线程run方法正在运行)、阻塞状态(run方法在执行一段时间后暂停执行)、线程死亡(run方法执行结束、发生异常)
* 新建 --- 运行 (获得cpu的使用权)
* 运行 --- 阻塞 (Thread.sleep join 使用同步锁 wait IO读写、网络传输)
* 阻塞 --- 运行 结束阻塞,重新获得cpu使用权
sleep 使当前线程睡眠一段时间,睡眠过程中,不释放锁资源
join 等待目标线程执行结束后,其他线程才能继续执行
同步锁,当运行一个代码块,使用同步锁机制,一个线程已经将代码块锁定,另一个线程无法进入代码块 ---- 执行等待锁
wait 当你获得一个同步锁后,选择在锁上面监视器进行等待,等待必须由别人进行 唤醒 notify notifyAll
锁:保证一段程序同一时间只能由一个线程进行执行 ---- 阻止两个线程同时执行一段代码
* java中每个对象都可以作为锁 ----- 锁的本质,锁定一块内存地址
public class MyThread2 {
public static void main(String[] args) {
Object lock = new Object();
ThreadA a = new ThreadA(lock);
new Thread(a).start();
ThreadB b = new ThreadB(lock);
new Thread(b).start();
// 保证顺序不乱 --- 加锁 锁定同一个内存
}
}
class ThreadA implements Runnable {
private Object lock;
public ThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class ThreadB implements Runnable {
private Object lock;
public ThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
* 特殊锁 锁定方法
public static synchronized void a() {} ---- 锁定 类的Class对象
public synchronized void b() {} --- 锁定this 对象
同步锁案例 : 售票系统 模拟火车站多个售票窗口同时售票 ---- 确保同一个时间 只能有一个窗口打票
public class SaleTicketSystem {
public static void main(String[] args) {
TicketSystem system = new TicketSystem();// 票源唯一
for (int i = 0; i < 5; i++) {// 模拟5个窗口同时卖票
SaleTicket saleTicket = new SaleTicket(system);
new Thread(saleTicket).start();
}
}
}
// 票源
class TicketSystem {
private int totalTickets = 100; // 总票数
private int hasSaleTickets = 0; // 已经售票编号
// 添加同步后,同一时间只能有一个窗口卖票
public synchronized void saleTicket() {
if (totalTickets <= 0) {
throw new RuntimeException("票已经卖完");
}
// 卖掉一张票
hasSaleTickets++;
System.out.println("打印一张票!" + hasSaleTickets);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 总票数 -1
totalTickets--;
System.out.println("剩余票数:" + totalTickets);
}
}
//售票
class SaleTicket implements Runnable {
private TicketSystem ticketSystem;
public SaleTicket(TicketSystem ticketSystem) {
this.ticketSystem = ticketSystem;
}
@Override
public void run() {
while (true) {
try {
ticketSystem.saleTicket();
} catch (RuntimeException e) {
break;
}
}
}
死锁原因:互相等待 ------ 同步代码块嵌套
* 尽量同步代码块不要嵌套
public class DeadLockTest {
public static void main(String[] args) {
Object pen = new Object();// 笔
Object note = new Object(); // 本
new Thread(new AThread(pen, note)).start();
new Thread(new BThread(pen, note)).start();
}
}
class AThread implements Runnable {
private Object pen;
private Object note;
public AThread(Object pen, Object note) {
this.pen = pen;
this.note = note;
}
@Override
public void run() {
// 先获得笔 --- 再获得本
synchronized (pen) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (note) {
System.out.println("A 写字");
}
}
}
}
class BThread implements Runnable {
private Object pen;
private Object note;
public BThread(Object pen, Object note) {
this.pen = pen;
this.note = note;
}
@Override
public void run() {
// 先获得 本 --- 再获得笔
synchronized (note) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (pen) {
System.out.println("B 写字");
}
}
}
}
锁监视器操作 ----- java中所有对象都可以作为锁,java 中 Object类 提供 wait notify notifyAll
wait :当前线程 在锁对象的监视器上进行等待
notify : 唤醒 一个 在 指定锁对象的监视器上等待的线程
notifyAll : 唤醒所有在指定 锁对象的监视器上等待的线程
* 线程通信案例 (当两个线程协同完成某个任务 )---- 生产者消费者模型
生产者消费者场景 :一个生产者、一个消费者,生产者生产一个面包,通知消费者来吃,消费者吃完了,通知生产者生产
* 生产者发现面包还没吃 需要等待
* 消费者发现面包已经吃了 需要等待
/**
* 生产者 消费者案例
*
* @author seawind
*
*/
public class ProducerConsumerTest {
public static void main(String[] args) {
CakeHouse cakeHouse = new CakeHouse();
new Thread(new Producer(cakeHouse)).start();
new Thread(new Consumer(cakeHouse)).start();
}
}
// 生产者
class Producer implements Runnable {
private CakeHouse cakeHouse;
public Producer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
// 生产100个蛋糕
for (int i = 0; i < 100; i++) {
cakeHouse.put();
}
}
}
// 消费者
class Consumer implements Runnable {
private CakeHouse cakeHouse;
public Consumer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
cakeHouse.take();
}
}
}
class CakeHouse {
// 蛋糕房 蛋糕窗口
private List<Object> list = new LinkedList<Object>();
private int index;
// 必须先同步,才能使用锁监视器
public synchronized void put() {
while (!list.isEmpty()) {
// 已经有蛋糕
try {
this.wait(); // 调用wait的对象 就是锁定对象
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产蛋糕
list.add(new Object());
index++;
System.out.println("生产者 生产蛋糕 " + index);
// 通知消费者 快去吃
this.notify();
}
public synchronized void take() {
while (list.isEmpty()) {
// 没蛋糕
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 吃掉蛋糕
list.remove(0);
System.out.println("消费者消费蛋糕 " + index);
// 通知生产者生产
this.notify();
}
}
JDK5.0 之后提供两个接口 Lock 和 Condition ,简化同步和锁编程
java.util.concurrent.locks.Lock ---- 取代 synchronized
java.util.concurrent.locks.Condition ---- 取代 wait notify
* 在同一个锁上面 建立多个监视器
public class SaleTicketSystem {
public static void main(String[] args) {
TicketSystem system = new TicketSystem();// 票源唯一
for (int i = 0; i < 5; i++) {// 模拟5个窗口同时卖票
SaleTicket saleTicket = new SaleTicket(system);
new Thread(saleTicket).start();
}
}
}
// 票源
class TicketSystem {
private int totalTickets = 100; // 总票数
private int hasSaleTickets = 0; // 已经售票编号
private Lock lock = new ReentrantLock();
// 添加同步后,同一时间只能有一个窗口卖票
public void saleTicket() {
// 加锁
lock.lock();
if (totalTickets <= 0) {
throw new RuntimeException("票已经卖完");
}
// 卖掉一张票
hasSaleTickets++;
System.out.println("打印一张票!" + hasSaleTickets);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 总票数 -1
totalTickets--;
System.out.println("剩余票数:" + totalTickets);
// 解锁
lock.unlock();
}
}
class SaleTicket implements Runnable {
private TicketSystem ticketSystem;
public SaleTicket(TicketSystem ticketSystem) {
this.ticketSystem = ticketSystem;
}
@Override
public void run() {
while (true) {
try {
ticketSystem.saleTicket();
} catch (RuntimeException e) {
break;
}
}
}
}
/**
* 生产者 消费者案例
*
* @author seawind
*
*/
public class ProducerConsumerTest {
public static void main(String[] args) {
CakeHouse cakeHouse = new CakeHouse();
new Thread(new Producer(cakeHouse)).start();
new Thread(new Consumer(cakeHouse)).start();
}
}
// 生产者
class Producer implements Runnable {
private CakeHouse cakeHouse;
public Producer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
// 生产100个蛋糕
for (int i = 0; i < 100; i++) {
cakeHouse.put();
}
}
}
// 消费者
class Consumer implements Runnable {
private CakeHouse cakeHouse;
public Consumer(CakeHouse cakeHouse) {
this.cakeHouse = cakeHouse;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
cakeHouse.take();
}
}
}
class CakeHouse {
// 蛋糕房 蛋糕窗口
private List<Object> list = new LinkedList<Object>();
private int index;
private Lock lock = new ReentrantLock();
// 生产者专用监视器
private Condition producerCondition = lock.newCondition();
// 消费者专用监视器
private Condition consumerCondition = lock.newCondition();
public void put() {
lock.lock();
while (!list.isEmpty()) {
// 已经有蛋糕
try {
producerCondition.await(); // 在生产者监视器上等
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生产蛋糕
list.add(new Object());
index++;
System.out.println("生产者 生产蛋糕 " + index);
// 通知消费者 快去吃
consumerCondition.signal();
lock.unlock();
}
public void take() {
lock.lock();
while (list.isEmpty()) {
// 没蛋糕
try {
consumerCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 吃掉蛋糕
list.remove(0);
System.out.println("消费者消费蛋糕 " + index);
// 通知生产者生产
producerCondition.signal();
lock.unlock();
}
}
java.util.concurrent 包 和 子包 ---- ArrayBlockingQueue<E> CopyOnWriteArrayList<E> LinkedBlockingQueue<E>
线程池技术 Excutors
为什么用线程池,线程创建、关闭释放资源 ---- 消耗程序性能
一次创建多个线程,做任务,随机获得一个线程,完成任务,将线程归还线程池
newFixedThreadPool(int nThreads) 固定线程数量线程池
newCachedThreadPool() 返回根据程序需要自动扩充大小 线程池 ----- 最常用
newSingleThreadExecutor() 返回单线程处理程序
shutdown与shutdownNow的比较
shutdown 完成当前线程池中所有任务 再关闭
shutdownNow 会对当前线程池中所有线程,调用interrupt 尝试打断当前线程,如果无法打断,会执行结束
public class ExcutorsTest {
// java中编写程序测试多线程,一定不能用 junit --- System.exit
public static void main(String[] args) {
// 创建线程池
// 创建固定数量为3 线程池
// ExecutorService service = Executors.newFixedThreadPool(5);
// 创建 自增扩充大小 线程池
ExecutorService service = Executors.newCachedThreadPool();
// 单一线程对象
// ExecutorService service = Executors.newSingleThreadExecutor();
// 开启十个线程 分别输出
for (int i = 0; i < 10; i++) {
service.execute(new MyExcutor());
}
// 关闭连接池
service.shutdown();// 当之前任务都结束后,尝试关闭连接池
// service.shutdownNow();// 尝试马上关闭连接池,但是不一定能关闭
// interrupt
}
}
class MyExcutor implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
------------------------------------------------------------------------------------------------------------------
OSI 七层体系结构: 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
*协议层次越高,越容易让人理解, 层次越低,数据越接近0 1
TCP/IP 四层 : 应用层、传输层、网际层、网络接口层
应用层、传输层
应用层:HTTP SMTP POP3 FTP TELNET
传输层:TCP(不允许丢包 三次握手) UDP(广播 允许丢包)
三次握手:
A 向 B 发送一个消息:能听到我说话吗
B 回复 A 消息:我能听到,你能听到我说话吗
A 回复 B :我能听到
TCP发送数据没有收到对方回应,选择重新发送 ---- 时间限制 超时
Socket 两台计算机之间一个连接 ---- 两台计算机可以通信
使用socket建立双方连接 -----传输协议需要自己编写 面向底层协议
socket 编写程序 可以模拟服务器,可以模拟客户端
服务器如何编写
* 使用socket进行通信过程中,如果调用in.readLine 但是对方没有写 ---- 程序一直等待 、out.print向对方发送信息 没有阻塞
/**
* 模拟服务器
*
* @author seawind
*
*/
public class Server {
public static void main(String[] args) throws IOException {
// 步骤一 创建ServerSocket 对象
ServerSocket serverSocket = new ServerSocket(9000);
// 连接服务器需要 ip 和 端口
// 步骤二 等待客户端来连接
Socket socket = serverSocket.accept(); // socket代表一个连接
// 步骤三 需要获得流
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 收取对方信息 用 in
// 发送给对方信息 用 out
out.println("Hello !");// 输出信息 因为用字符流 ,所以flush
out.flush();
System.out.println(in.readLine());
}
}
/**
* 客户端
*
* @author seawind
*
*/
public class Client {
public static void main(String[] args) throws UnknownHostException,
IOException {
// 步骤一 连接服务器
Socket socket = new Socket("localhost", 9000);
// 步骤二 获得流
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket
.getInputStream()));
// 通过in 获得信息
System.out.println(in.readLine());
out.println("你好服务器!");
out.flush();
}
}
socket 案例 ----- 模拟tomcat服务器
/**
* 模拟tomcat server
*
* @author seawind
*
*/
public class TomcatServer {
public static void main(String[] args) throws IOException {
// 步骤一
ServerSocket serverSocket = new ServerSocket(9000);
// 创建线程池
ExecutorService executorService = Executors.newCachedThreadPool();
while (true) {
// 步骤二 获得与客户端连接
Socket socket = serverSocket.accept();
DealResponse dealResponse = new DealResponse(socket);
// 将处理任务 加入线程池
executorService.execute(dealResponse);
}
}
static class DealResponse implements Runnable {
private Socket socket;
public DealResponse(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 步骤三 流
OutputStream bout = new BufferedOutputStream(socket
.getOutputStream());
// PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// 浏览器连接服务器 发送HTTP请求
String requestline = in.readLine();// 获得请求行
// 解析资源路径
String path = parse(requestline);
System.out.println(path);
// 判断目标文件是否存在
File file = new File("webroot" + path);
// 判断服务器上面 有没有客户访问文件
if (file.exists()) {
// 回写HTTP协议格式
bout.write("HTTP/1.1 200 OK\r\n".getBytes());
// 根据文件扩展名得到文件格式
bout
.write(("Content-Type:" + getType(file.getName()) + "\r\n")
.getBytes()); // 不同文件类型是不同的
bout.write(("Content-Length:" + file.length() + "\r\n\r\n")
.getBytes());
// 存在
InputStream fis = new BufferedInputStream(
new FileInputStream(file));
int temp;
while ((temp = fis.read()) != -1) {
bout.write(temp);
}
bout.flush();
bout.close();
fis.close();
System.out.println("文件找到了");
} else {
// 不存在
bout.write("file not found".getBytes());
bout.flush();
System.out.println("文件找不到!");
bout.close();
}
// 断开socket连接
in.close();
socket.close();
} catch (FileNotFoundException e) {
// e.printStackTrace();
} catch (IOException e) {
// e.printStackTrace();
}
}
}
private static String getType(String name) {
// 获得扩展名
String ext = name.substring(name.lastIndexOf(".") + 1);
String type = ResourceBundle.getBundle("mime").getString(ext);
return type;
}
private static String parse(String requestline) {
return requestline.split(" ")[1];
}
}
---------------------------------------------------------------------------------------
注解的使用 ---- 定义注解,利用反射解析注解内容 (案例:银行转账最大金额)
Servlet3.0 注解开发Servlet、异步技术、文件上传
动态代理 (案例:德华案例、银行取款 收取手续费用)
多线程:两种线程创建方式、四种状态、同步和锁、死锁、wait和notify (案例:卖票、生产蛋糕) ---- 使用JDK5 Lock和Condition 重写
socket编程 服务器怎么写 客户端怎么写
* 实际socket案例 按照协议发送内容 模拟tomcat 服务器 遵循HTTP协议
- 浏览: 73130 次
- 性别:
文章分类
最新评论
发表评论
-
git sshkey生成
2015-10-13 10:09 564Git SSH Key 生成步骤 2012-11 ... -
hibernate04
2014-06-27 21:03 566*一)hibernate的检索方 ... -
hibernate03 一对一 多对多双向映射
2014-06-24 17:19 950*一)【双向】一对多 ... -
hibernate_02 四种状态 多对一级联操作
2014-06-11 19:55 1106*一)持久化对象的状态变化和对应的方法 (1)持久化 ... -
hibernate_01hibernate入门简单api
2014-06-10 18:20 743一)orm和hibernate概述 参见PPT< ... -
struts2_03表单校验ognl国际化
2014-06-07 10:23 983一、用户输入验证 1、编程方式: 动作类中的所有方法进行验 ... -
struts02表单验证文件上传自定义拦截器类型转换常用常量
2014-05-11 21:46 995一.package下可以配置全局页面 <!-- pa ... -
struts201 struts2环境搭建及入门
2014-05-10 21:31 582一、分析之前的项目的不足,编写属于自己的框架二、Strut ... -
ajax03 jquery jquery_ajax
2014-05-09 23:14 711非常流行JS框架 : jQue ... -
day20 文件上传与下载
2014-05-02 10:50 1127文件上传功能应用非常广泛,例如:头像上传、商品图片、新闻图片、 ... -
day19 javamail
2014-05-02 10:42 1041什么情况需要邮件发 ... -
ajax day01 JS加强
2014-05-02 10:37 713<!--[if !mso]> <styl ... -
ajaxday2 ajax json xstream
2014-05-02 10:34 1002第三部分:AJAX 异步 JavaScript和 XML ... -
day18 监听器 统计在线人数,定时销毁超时session,钝化活化session,在线列表显示和踢人功能防止用户自动登录,在线支付
2014-04-12 20:53 933Servlet 监听器和过滤器一样,是Servlet开发高 ... -
day17过滤器 禁止缓存中文乱码自动登录MD5加密url级别权限控制
2014-04-12 09:27 1217day17Servlet Filter 过滤器 day1 ... -
day16 项目1客户信息系统
2014-04-09 15:32 544客户信息增删改查系统 软件工程开发流程:1、瀑布模型 2 ... -
day15 JDBC元数据 DBUtils 开发模型
2014-04-06 17:47 772人们直接使用JDBC开发,非常麻烦 ----- 企业中开发w ... -
day14 JDBC事务管理 数据库连接池技术
2014-04-06 17:44 1009今天学习重点:JDBC事 ... -
day13 JDBC 基础 事务控制 大数据 批处理
2014-04-06 17:41 881JDBC : Java Database Connectiv ... -
day12 mysql复杂sql语句编写
2014-04-06 17:38 965SQL基本部分:1、数据 ...
相关推荐
#### 一、Servlet3.0之WebServlet注解 ##### 1. Servlet3.0简介与环境要求 - **Servlet3.0**:Servlet规范的最新版本之一,带来了诸多改进,其中最显著的变化是引入了注解支持,简化了Servlet的配置过程。 - **...
EJB3.0实体的注解规范主要涵盖了Java企业版(Java EE)中实体Bean的定义方式,这一规范也适用于Java Persistence API (JPA),并且整合了Hibernate的特有扩展。在EJB3.0中,实体Bean被设计为简单的Plain Old Java ...
Servlet在Web服务器中运行,像Tomcat、Jetty等都是支持Servlet技术的服务器。 Servlet的生命周期可以分为四个阶段: 1. 加载和实例化:服务器首先加载Servlet类,然后创建Servlet实例。 2. 初始化:Servlet的init...
"Servlet3.0.txt"文件可能涵盖了Servlet 3.0的新特性和改进,如注解配置、异步处理、过滤器和监听器的增强等。Servlet是JavaWeb中最基础的部分,用于接收和响应HTTP请求,Servlet 3.0版本引入了很多便利的功能,简化...
### EJB3.0-JPA实体的注解规范以及Hibernate特有的扩展 #### 一、概述 EJB3.0引入了一种新的编程模型,它基于Java Persistence API (JPA),使得开发人员能够更加轻松地创建企业级应用。JPA允许使用POJO(Plain Old...
反射、注解
Servlet则是Java平台上的一个标准,用于构建动态Web应用的技术。这个标签表明内容将涵盖这两者的基础知识,如安装配置Tomcat、理解Servlet生命周期、编写Servlet代码等。 【压缩包子文件的文件名称列表】 由于列表...
### JSP与Servlet技术解析 #### 一、概述 JSP (Java Server Pages) 是一种基于Java技术的服务器端脚本语言,它被用来创建动态网页。与传统的Servlet相比,JSP提供了更丰富的功能和更简便的方式来处理Web应用程序中...
【标题】"day04-Tomcat&Servlet入门-讲义.zip" 提供的是关于Tomcat服务器和Servlet编程基础的教程资料。Tomcat是Apache软件基金会 Jakarta项目中的一个核心项目,是一个开源的Java Servlet容器,它实现了Java EE的...
这两个版本中,Servlet技术都有重要更新,例如Servlet 3.0在J2EE 6.0中引入了注解配置和异步处理能力,让Servlet的使用更加灵活。 "j2EE6.0.chw"可能是同样的帮助文档的不同格式,便于在不同设备上阅读。 "day09....
2021贺岁大数据入门spark3.0入门到精通资源简介: 本课程中使用官方在2020年9月8日发布的Spark3.0系列最新稳定版:Spark3.0.1。共课程包含9个章节:Spark环境搭建,SparkCore,SparkStreaming,SparkSQL,...
SpringBoot下的Spring——DAY04——动态代理总结、AOP、自定义注解进行拦截、动态获取注解参数、通知方法 1.动态代理总结 1.1 JDK动态代理特点 1.2 CGlib动态代理 1.2.1 CGLib特点说明 1.3 动态代理的作用 2 Spring...
随着Java EE的更新,现在更推荐使用Servlet 3.0及以上版本,它引入了注解配置,可以省去`web.xml`的繁琐配置。例如,你可以直接在Servlet类上使用`@WebServlet`注解: ```java @WebServlet("/MyServlet") public ...
Servlet是Java Web开发中的核心组件,用于接收和处理客户端(如浏览器)的请求,...在深入学习的过程中,还可以探索更高级的主题,如Session管理、Filter链、MVC设计模式以及使用Servlet 3.0及以上版本的注解进行配置。
本文将深入探讨"day39-Spring 03-JDK的动态代理"这一主题,该主题主要关注Spring框架如何利用JDK的动态代理机制实现AOP(面向切面编程)。 首先,我们需要理解什么是动态代理。在Java中,动态代理是一种在运行时...
揭秘家用路由器0day漏洞挖掘技术.pdf 仅供用学习交流使用,不可用于商业用途,如有版权问题,请联系删除!
移动开发的小白树懒,现在正努力的学习Web中的http,serlet,在web层中一步一步的学习中,为强大的自己而努力
JavaWeb 技术栈 JavaWeb 是用 Java 技术来解决相关 ...JavaWeb 技术栈包括了 B/S 架构、静态资源、动态资源、数据库、HTTP 协议、Web 服务器、Servlet 等几个方面,是 Java 技术来解决相关 web 互联网领域的技术栈。
- 提升代码灵活性:通过动态传递行为,使得程序更具灵活性。 ##### 3.2 Lambda 表达式的格式 - **标准格式**:`() -> {}`,其中括号表示参数列表,箭头表示执行体。 - 示例: ```java Runnable r = () -> ...
注解:注解的另一个称呼注释,是给程序看的 反射:在运行的时候动态的去获取类的相关信息(公有的和私有的 字段 构造方法 方法 注解); 通过获取类的字节码文 件对象 再去获取相关的信息