基础篇
IO
bit byte char
1 char = 2 byte = 16 bit
字节流
操作byte类型的主要操作类时OutputStream,InputStream的子类;不用缓冲区直接操作文件本身。
字符流
操作字符类型数据,主要操作类:Reader,Writer的子类,使用缓冲区,不关闭流就不输出实际内容。
转换
OutputStreamWriter:Writer的子类,将字符流变为字节流
InputStreamReader:Reader的子类,将输入的字节流变为字符流
Linux下的5种IO模型
阻塞式IO模型
用户线程发出IO请求,内核查看数据是否准备就绪,没有就等待数据,用户线程处于阻塞态,交出CPU,数据就绪后,内核将数据拷贝到用户线程,并将结果返回到用户线程,这时用户线程变为就绪态等待分配cpu时间片。
非阻塞IO模型
非阻塞线程的用户线程会在发出IO请求后即使没有数据也不会让出cpu除非时间片到了,相当于在cpu时间内不断轮询数据。
| 12
 3
 4
 5
 6
 7
 
 | while(true){data = socket.read();
 if(data!= error){
 处理数据
 break;
 }
 }
 
 | 
当然这会导致cpu占用率高的问题。
IO复用模型
多路复用IO模型是目前用的最多的,也是Java NIO的方式。
这个模型中,有一个线程不断轮询多个socket状态,只有当socket有真正的读写事件时,才调用实际的IO读写操作,Java NIO中,通过selector.select()去查询每个通道是否有到达事件如果没有线程阻塞。一个线程可以管理多个socket,因此多路复用适合连接数比较多的情况,而且线程轮询每个socket状态实在内核态完成的,效率高。
信号驱动IO模型
用户线程发起IO请求,给对应socket发送信号函数,然后用户线程继续执行,知道内核准备的数据好了发送信号返回用户线程,用户线程接受信号调用IO读写。
异步IO模型
用户线程发起read操作后就可以处理其他事情,内核等待数据准备完成,然后将数据拷贝到用户线程,完成后发送信号给用户线程通知read完成,也就是说用户线程只做了请求发送的动作就可以去使用数据了。
和信号驱动模型对比就是不需要用户线程去调用IO函数进行实际读写。
BIO NIO AIO
Java中通过流的方式完成IO操作,所有的IO都被是为单个字节的移动,通过Stream对象一次移动一个字节,流可以和外部世界互动,也可以将对象转为字节,或者再转回来。
BIO: Java的Block IO 同步阻塞式IO,java.io包下实现。
NIO:NIO与普通的IO方式最大的区别时数据打包和传输方式,原来的IO以流的方式处理,NIO以块的方式处理。IO流一次一个字节处理,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据,所以面向流的IO方式比较慢。
一个面向块的IO以块形式处理数据,每一个操作都在一次中产生或者消费一个数据库,速度要快得多。
并且NIO的方式时支持同步阻塞和同步非阻塞模式,比如来了100个网络连接调用accept等待响应,NIO会开一个线程会管理这个链接的读写请求,让主线程继续往下响应其他链接,就这样NIO通过一个管理线程轮询所有的链接(socket)的IO状态,某个socket数据准备好了那么会通知这个线程去处理数据。
AIO:异步非阻塞IO模型,真正的异步
netty
Netty是一个非阻塞I/O客户端-服务器框架,主要用于开发Java网络应用程序,如协议服务器和客户端。异步事件驱动的网络应用程序框架和工具用于简化网络编程,例如TCP和UDP套接字服务器。Netty包括了反应器编程模式的实现。Netty最初由JBoss开发,现在由Netty项目社区开发和维护。
除了作为异步网络应用程序框架,Netty还包括了对HTTP、HTTP2、DNS及其他协议的支持,涵盖了在Servlet容器内运行的能力、对WebSockets的支持、与Google Protocol Buffers的集成、对SSL/TLS的支持以及对用于SPDY协议和消息压缩的支持。自2004年以来,Netty一直在被积极开发
从版本4.0.0开始,Netty在支持NIO和阻塞Java套接字的同时,还支持使用NIO.2作为后端。
本质:JBoss做的一个Jar包
目的:快速开发高性能、高可靠性的网络服务器和客户端程序
优点:提供异步的、事件驱动的网络应用程序框架和工具
反射
反射:程序在运行时能够获取自身的信息,在Java中,只要给定类的名字,就能通过反射机制获取属性和方法。
用处
- 运行时判断任意一个对象所属的类 
- 运行时判断任意一个类所具有的成员变量和方法 
- 运行时任意调用一个对象的方法 
- 运行时构造任意一个类的对象 
Class类
Java的Class类时Java反射机制的基础,通过Class可以获得一个类的相关信息
每个类都会有一个Class对象,运行程序时,JVM首先检查是否所有要加载的类对应的Class对象都已经被加载,如果没有,会根据类名查找.class文件,并将其Class对象载入。
反射+工厂实现IOC
首先不带反射的普通工厂模式:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | interface fruit{public abstract void eat();
 }
 class Apple implements fruit{
 public void eat(){
 System.out.println("Apple");
 }
 }
 class Orange implements fruit{
 public void eat(){
 System.out.println("Orange");
 }
 }
 
 class Factory{
 public static fruit getInstance(String fruitName){
 fruit f = null;
 if("Apple".equals(fruitName)){
 t = new Apple();
 }
 if("Orange".equals(fruitName)){
 t = new Orange();
 }
 return f;
 }
 }
 
 class Main{
 public static void main(String[] a){
 fruit f = Factory.getInstance("Orange");
 f.eat();
 }
 }
 
 | 
反射机制实现:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | interface fruit{public abstract void eat();
 }
 class Apple implements fruit{
 public void eat(){
 System.out.println("Apple");
 }
 }
 class Orange implements fruit{
 public void eat(){
 System.out.println("Orange");
 }
 }
 
 class Factory{
 public static fruit getInstance(String className){
 fruit f = null;
 try{
 f = (fruit)Class.forName(className).newInstance();
 }catch(Exception e){
 e.printStackTrace();
 }
 return f;
 }
 }
 
 class Main{
 public static void main(String[] a){
 fruit f=Factory.getInstance("Reflect.Apple");
 if(f!=null){
 f.eat();
 }
 }
 }
 
 | 
配置properties文件
| 12
 
 | apple=Reflect.Appleorange=Reflect.Orange
 
 | 
编写操作属性文件类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | class init{public static Properties getPro() throws FileNotFoundException, IOException{
 Properties pro=new Properties();
 File f=new File("fruit.properties");
 if(f.exists()){
 pro.load(new FileInputStream(f));
 }else{
 pro.setProperty("apple", "Reflect.Apple");
 pro.setProperty("orange", "Reflect.Orange");
 pro.store(new FileOutputStream(f), "FRUIT CLASS");
 }
 return pro;
 }
 }
 
 class Main{
 public static void main(String[] a) throws FileNotFoundException, IOException{
 Properties pro=init.getPro();
 fruit f=Factory.getInstance(pro.getProperty("apple"));
 if(f!=null){
 f.eat();
 }
 }
 }
 
 | 
运行以上代码可以看出反射动态生成对象的好处。
IOC容器
IOC最基本的就是反射,使用这个方式,用户只要在spring中配置要生成的对象文件。提高灵活性和可维护性。只有用反射才能做出框架。
IOC容器的工作模式可以看作是工厂模式的升华,工厂要生成的对象都在配置文件中给出定义,然后利用反射机制生成对象。
设计模式 代理模式
静态代理
定义一个简单接口和实现类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | public interface HelloService {public void say();
 }
 
 public class HelloServiceImpl implements HelloService{
 
 @Override
 public void say() {
 System.out.println("hello world");
 }
 }
 
 | 
定义代理对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | public class HelloServiceProxy implements HelloService{
 private HelloService target;
 public HelloServiceProxy(HelloService target){
 this.target = target;
 }
 @Override
 public void say() {
 System.out.println("记录日志");
 target.say();
 System.out.println("清理数据");
 }
 }
 
 | 
测试
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | public class Main {@Test
 public void testProxy(){
 
 HelloService target = new HelloServiceImpl();
 
 HelloServiceProxy proxy = new HelloServiceProxy(target);
 proxy.say();
 }
 }
 
 | 
这个代理模式的所有角色,代理对象,目标对象,目标对象接口都已经在编译器确定了。
动态代理
静态代理会要写很多代码,动态代理则可以省去且在运行期动态生成。
有两种实现方式:
- JDK动态代理:在java.lang.reflect包中的proxy类和InvocationHandle接口提供了生成动态代理类的能力,但是代理对象必须实现一个或多个接口。 
- Cglib动态代理:code generation library,第三方的代码生成类库,许多apo框架都在用比如spring aop,底层是通过使用一个小而快的字节码处理框架ASM来转换字节码生成新的类。且目标类不需要实现接口。 
JDK动态代理
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 
 | public class MyInvocationHandler implements InvocationHandler {
 private Object target;
 
 public MyInvocationHandler(Object target) {
 
 super();
 this.target = target;
 
 }
 
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 PerformanceMonior.begin(target.getClass().getName()+"."+method.getName());
 
 Object result = method.invoke(target, args);
 
 PerformanceMonior.end();
 return result;
 }
 
 public Object getProxy(){
 
 return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
 }
 
 }
 
 public static void main(String[] args) {
 
 UserService service = new UserServiceImpl();
 MyInvocationHandler handler = new MyInvocationHandler(service);
 UserService proxy = (UserService) handler.getProxy();
 proxy.add();
 }
 
 
 | 
Cglib 动态代理
记得在maven添加依赖
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | public class CglibProxy implements MethodInterceptor{  private Enhancer enhancer = new Enhancer();
 public Object getProxy(Class clazz){
 
 enhancer.setSuperclass(clazz);
 enhancer.setCallback(this);
 
 return enhancer.create();
 }
 
 public Object intercept(Object obj, Method method, Object[] args,
 MethodProxy proxy) throws Throwable {
 System.out.println("前置代理");
 
 Object result = proxy.invokeSuper(obj, args);
 System.out.println("后置代理");
 return result;
 }
 }
 
 public class DoCGLib {
 public static void main(String[] args) {
 CglibProxy proxy = new CglibProxy();
 
 UserServiceImpl proxyImp = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class);
 proxyImp.add();
 }
 }
 
 | 
AOP
Spring AOP 中的动态代理有两种方式,JDK动态代理和CGLIB动态代理
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。