Spring源码分析 之浅谈设计模式

Posted chuquan.ou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码分析 之浅谈设计模式相关的知识,希望对你有一定的参考价值。

一直想专门写个Spring源码的博客,工作了,可以全身性的投入到互联网行业中。虽然加班很严重,但是依然很开心。趁着凌晨有时间,总结总结。

首先spring,相信大家都很熟悉了。 

 1、轻量级  零配置,API使用简单

 2、面向Bean  只需要编写普通的Bean(一个Bean代表一个对象)

3、松耦合 充分利用AOP思想 )(各自可以独立开发,然后整合起来运行)

4、万能胶 与主流框架无缝集成 (Mybatis dubbo等等 )

5、设计模式 将Java中经典的设计模式运用的淋漓尽致

 

Spring解决企业级应用开发的负责设计,简化开发。

   1,基于POJO的清理爱你国际和最小侵入性(代码的嵌套,独自开发合起来运行)

  2,通过依赖注入和面向接口松耦合

  3、基于切面(典型的事务管理!!日志)和惯性进行声明式编程

  4、通过切面和模板减少版式代码

  主要通过,面向Bean、依赖注入以及面向切面三种方式达成

 

Spring提供了IOC容器,通过配置文件或者注解的方式来管理对象之间的依赖关系

  A a = new A()//实例化后用一个变量保存下来(匿名对象)    ------------------》Spring用IOC容器 存储起来~

 a.c()  //必须初始化才运行  -----------------------> Spring帮忙初始化,实例化(控制器给了spring) 

最终实现了 依赖注入:

@autowrite Interfa A a   //自动吧他的实现类注入进来

@Resource(“aa”)//IOC容器种类的id为“aa”的对象自动注入到这里

@autowrite A a  //根据类型自动注入

Spring的注入方式

1、 setter

2、 构造方法

3、强制赋值

面向切面,AOP核心思想--解耦! 把一个整体拆开,分别开发,发布时候,再组装到一起运行,切面就是规则!

比如 事务;

     开启事务 执行事务 事务回滚 关闭事务     这就是规则!!!!!!

     这种有规律的,就可以认为他是固定的,可以单独拿出来开发设计,作为一个模块(比如日志啊)。

  AOP就是个编程思想而已

关于Spring的使用,特点,网上资料很多,大家可以自己找找学习下。本博客主要对于源码进行解读。

 

在典型的面型对象开发方式中,可能要将日志记录语句放在所有方法和Java类种才能实现日志功能。而在AOP方式中,可以反过来将日志服务模块化,并以声明的方式将他们应用到需要日志的组件上。Java类不需要知道日志服务的存在,也不想需要考虑相关的代码。

AOP的功能完全集成到了Spring事务管理、日志和其他各种特性的上下文中

authentication权限认证

Logging日志

Transctions Manager事务

Lazy Loading懒加载

Contex Process 上下文处理

Error Handler 错误跟踪(异常捕获机制)

Cache缓存

1、除了AOP以外的设计模式

   a、 代理模式

   b、工厂模式

   c、单例模式

  d、委派模式

  e、策略模式

  f、策略模式

  g、原型模式

代理模式原理:

   1、拿到被代理对象的引用,然后获取它的接口

   2、JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口

   3、把代理对象的引用拿到

   4、重新动态生成一个class字节码

   5、编译

动态代理 调用哪个方法就代理哪个方法 

整个类 生成一个新 的类

 

大家认真仔细研究好代理模式,代理模式在Spring中 应用非常广泛!!!

JDK代理模式实现:

  1、定义接口

  2、定义实现接口的类

  3、 代理类  ,代理类需要实现  InvocationHandler 接口,然后实现 invoke方法

 回顾一下,满足代理模式应用场景的三个必要条件,穷取法
1、两个角色:执行者、被代理对象
2、注重过程,必须要做,被代理对象没时间做或者不想做(怕羞羞),不专业
3、执行者必须拿到被代理对象的个人资料(执行者持有被代理对象的引用)

 例:定义Persion接口

复制代码
public interface Person {

    //寻找真爱、相亲
    void findLove();
    
//    String getSex();
//
//    String getName();

}
复制代码

 

实现这个接口

复制代码
//小星星、单身
public class XiaoXingxing implements Person{

// private String sex = "女";
// private String name = "小星星";

@Override
public void findLove() {
// System.out.println("我叫" + this.name + ",性别:" + this.sex + "我找对象的要求是:");
System.out.println("高富帅");
System.out.println("有房有车的");
System.out.println("身高要求180cm以上,体重70kg");
}

// public String getSex() {
// return sex;
// }
//
// public void setSex(String sex) {
// this.sex = sex;
// }
//
// public String getName() {
// return name;
// }
//
// public void setName(String name) {
// this.name = name;
// }


}
复制代码

代理类

复制代码
//媒婆
public class Meipo implements InvocationHandler {

    private Person target; //被代理对象的引用作为一个成员变量保存下来了   在下面调用时候的 的   ///////////////////////// 下面的嗲用
 
    //获取被代理人的个人资料为,为了能让他代理任何对象
    public Object getInstance(Person target) throws Exception {
        this.target = target;
        Class clazz = target.getClass();  //利用反射机制(最终获得接口)
        System.out.println("被代理对象的class是:" + clazz);
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);  //this这个参数 指的是 代理人 this.h   就是调用了媒婆的 invoke方法    this指的是invoke这个回调方法
    }
        //代理对象 会自动调用下面invoke方法
        @Override
        public Object invoke (Object proxy, Method  method, Object[] args) throws Throwable{

            System.out.println("我是媒婆:" + "得给你找个异性才行");
            System.out.println("开始进行海选...");
            System.out.println("------------");
  ///////////////////////////////////////////////////////////
            //调用的时候   (利用反射机制调用)   对象名.方法名 
            method.invoke(this.target, args);  这个invoke不是方法名字的invoke  是的话 会陷入死循环  
            System.out.println("------------");
            System.out.println("如果合适的话,就准备办事");

            return null;
        }

    }
复制代码

测试:

复制代码
public class TestFindLove {
    public static void main(String[] args) {
        
        try {
            
//            
//            Person obj = (Person)new Meipo().getInstance(new XiaoXingxing());
//            System.out.println(obj.getClass());
//            obj.findLove();
            
            //原理:
            //1.拿到被代理对象的引用,然后获取它的接口
            //2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
            //3.把被代理对象的引用也拿到了
            //4.重新动态生成一个class字节码
            //5.然后编译
            
            //获取字节码内容 
//            byte[] data = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Person.class});  //生成字节码文件
//            FileOutputStream os = new FileOutputStream("E:/GP_WORKSPACE/$Proxy0.class");  //将字节码输入到磁盘上
//            os.write(data);
//            os.close();
            
            //是什么?
            //为什么?
            //怎么做?
         //解释: 字节码 反编译后 可以查看
Person obj = (Person)new GPMeipo().getInstance(new XiaoXingxing()); //返回一个代理对象 代理出来的这个对象可以强转这个接口类 System.out.println(obj.getClass()); //这个Object对象 并不是 lcy的引用了 完全是一个新的对象 obj.findLove(); //动态代理 需要调用哪个方法 就调用哪个方法 整个类都是新的类了 新的字节码 } catch (Exception e) { e.printStackTrace(); } } }
复制代码

也可以不用 JDK的任何东西 自己实现动态代理!!

不用jdk的任何东西!

首先规定有个InvocationHandler  有个 invoke方法

import java.lang.reflect.Method;

public interface GPInvocationHandler {
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

实现个Proxy  里面有 InvocationHandler引用  有 newInstance的方法 classloader方法

复制代码
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;


//生成代理对象的代码
public class GPPorxy {
    
    private static String ln = "\\r\\n";
    
    public static Object newProxyInstance(GPClassLoader classLoader,Class<?>[] interfaces,GPInvocationHandler h){
        
        
        try{
            //1、生成源代码
            String proxySrc = generateSrc(interfaces[0]);
            
            
            //2、将生成的源代码输出到磁盘,保存为.java文件
            String filePath = GPPorxy.class.getResource("").getPath();
            File f = new File(filePath + "$Proxy0.java");
            FileWriter fw = new FileWriter(f);
            fw.write(proxySrc);
            fw.flush();
            fw.close();
        
            //3、编译源代码,并且生成.class文件   
            JavaCompiler  compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager manager = compiler.getStandardFileManager(null, null, null);
            Iterable iterable = manager.getJavaFileObjects(f);
            
            CompilationTask task = compiler.getTask(null, manager, null, null, null, iterable);
            task.call();
            manager.close();
        
            //4.将class文件中的内容,动态加载到JVM中来
            
            //5.返回被代理后的代理对象
            Class proxyClass = classLoader.findClass("$Proxy0");
            Constructor c = proxyClass.getConstructor(GPInvocationHandler.class);  //拿到构造方法
            f.delete();
            
            return c.newInstance(h);
            
        }catch (Exception e) {
            e.printStackTrace();
        }
        
        
        return null;
    }
    
    
    private static String generateSrc(Class<?> interfaces){
        StringBuffer src = new StringBuffer();
        src.append("package com.gupaoedu.vip.custom;" + ln);
        src.append("import java.lang.reflect.Method;" + ln);
        src.append("public class $Proxy0 implements " + interfaces.getName() + "{" + ln);
        
        src.append("GPInvocationHandler h;" + ln);
        
        src.append("public $Proxy0(GPInvocationHandler h) {" + ln);
        src.append("this.h = h;" + ln);
        src.append("}" + ln);
        
        for (Method m : interfaces.getMethods()) {    //那么多方法 需要拿出来 
            src.append("public " + m.getReturnType().getName() + " " + m.getName() + "(){" + ln);
            
            src.append("try{" + ln);
            src.append("Method m = " + interfaces.getName() + ".class.getMethod(\\"" +m.getName()+"\\",new Class[]{});" + ln);  //方法名 参数等等
            src.append("this.h.invoke(this,m,null);" + ln);  
            src.append("}catch(Throwable e){e.printStackTrace();}" + ln);
            src.append("}" + ln);    
        }  
        
        src.append("}");
        
        return src.toString();
    }
}
复制代码

classloader类

复制代码
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

//代码生成、编译、重新动态load到JVM
public class GPClassLoader extends ClassLoader{

    private File baseDir;
    
    public GPClassLoader(){
        String basePath = GPClassLoader.class.getResource("").getPath();
        this.baseDir = new java.io.File(basePath);   //保存路径
    }
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String className = GPClassLoader.class.getPackage().getName() + "." + name;   //找到这个class文件
        if(baseDir != null){
            File classFile = new File(baseDir,name.replaceAll("\\\\.", "/") + ".class");
            if(classFile.exists()){
                FileInputStream in = null;
                ByteArrayOutputStream out = null; 
                try{
                    in = new FileInputStream(classFile);
                    out = new ByteArrayOutputStream();
                    byte [] buff = new byte[1024];   //缓冲区
                    int len;
                    while ((len = in.read(buff)) != -1) {
                        out.write(buff, 0, len);
                    }  //全部读完
                    return defineClass(className, out.toByteArray(), 0,out.size());  //搞到jvm中去
                    
                }catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    if(null != in){
                        try {
                            in.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if(null != out){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    classFile.delete();
                }
                
            }
        }
        
        return null;
    }
    
}
复制代码

代理类媒婆  必须实现这个类

复制代码
import java.lang.reflect.Method;

import com.gupaoedu.vip.proxy.jdk.Person;

public class GPMeipo implements GPInvocationHandler{
    
    private Person target;
    
    //获取被代理人的个人资料
    public Object getInstance(Person target) throws Exception{
        this.target = target;
        Class clazz = target.getClass();
        System.out.println("被代理对象的class是:"+clazz);
        return GPPorxy.newProxyInstance(new GPClassLoader(), clazz.getInterfaces(), this);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是媒婆:得给你找个异性才行");
        System.out.println("开始进行海选...");
        System.out.println("------------");
        method.invoke(this.target, args);
        System.out.println("------------");
        System.out.println("如果合适的话,就准备办事");
        return null;
    }

}
复制代码

注意 Java中 $符号的 约定俗成 被代理的类

 JDK 必须 实现接口!!!!

满足代理模式应用场景的三个必要条件,

    1、需要有两个角色  执行者 和 被代理对象

    2、注重过程,必须要做,被代理对象不做

   3、执行者必须拿到被代理对象的资料(执行者持有被代理对象的引用)

代理模式总结到底层就是:字节码重组! (字节码重组时候 对象要强制转换,必须要实现一个接口)

 Java源代码--->编译---->字节码(在原始的加了东西)-->加载到jvm中 

 

 

 

然后 cglib不需要,Spring主要用的cglib做动态代理 定义一个类   自动生成一个类 自动继承这个类 子类引用指向父类   看下面:

(同样做了字节码重组 事情)

 是继承关系 

复制代码
public class YunZhongYu {
    
    
    public void findLove(){
        System.out.println("肤白貌美大长腿");
    }
    
}
复制代码

定义代理类:

复制代码
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class GPMeipo implements MethodInterceptor{      // MethodInterceptor这是cglib里面的

    //疑问?
    //好像并没有持有被代理对象的引用
    public Object getInstance(Class clazz) throws Exception{
          //通过反射机制进行实例化

        Enhancer enhancer = new Enhancer();   //用来动态生成class
        //把父类设置为谁?
        //这一步就是告诉cglib,生成的子类需要继承哪个类
        enhancer.setSuperclass(clazz);
        //设置回调
        enhancer.setCallback(this);   //业务逻辑 指的是下面的 intercept 回调方法
        
        //第一步、生成源代码
        //第二步、编译成class文件
        //第三步、加载到JVM中,并返回被代理对象
        return enhancer.create();
    }
    
    //同样是做了字节码重组这样一件事情
    //对于使用API的用户来说,是无感知
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {    //要干的哪些事情   obj是生成以后的子类的引用   调用子类的引用就会调用这个子 intercept方法 调用super方法
        System.out.println("我是GP媒婆:" + "得给你找个异性才行");
        System.out.println("开始进行海选...");
        System.out.println("------------");
        //这个obj的引用是由CGLib给我们new出来的
        //cglib new出来以后的对象,是被代理对象的子类(继承了我们自己写的那个类)
        //OOP, 在new子类之前,实际上默认先调用了我们super()方法的,
        //new了子类的同时,必须先new出来父类,这就相当于是间接的持有了我们父类的引用
        //子类重写了父类的所有的方法
        //我们改变子类对象的某些属性,是可以间接的操作父类的属性的
        proxy.invokeSuper(obj, args);  //可以直接调用 调用的是父类哦
        System.out.println("------------");
        System.out.println("如果合适的话,就准备办事");
        return null;
    }

}
复制代码

测试类

复制代码
public class TestGglibProxy {
    
    public static void main(String[] args) {
        
        //JDK的动态代理是通过接口来进行强制转换的
        //生成以后的代理对象,可以强制转换为接口
        
        
        //CGLib的动态代理是通过生成一个被代理对象的子类,然后重写父类的方法
        //生成以后的对象,可以强制转换为被代理对象(也就是用自己写的类)
        //子类引用赋值给父类
        
        
        try {
            YunZhongYu obj = (YunZhongYu)new GPMeipo().getInstance(YunZhongYu.class);  //面向接口 对外开放 制定规范  接口就是规范  一般是是字符串 包名 类名 方法名之类的
            obj.findLove();
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}
复制代码

 

代理可以实现 在每一个方法调用之前加一些代码,方法嗲用之后加一些代码

AOP: 事务代理、 日志监听

Service方法  开启一个事务   事务的执行是由我们自己的代码完成的 

   1、监听到是否有异常,可能需要根据异常的类型来决定这个事务是否好回滚or继续提交?(commit or rollback?)

   2、事务要关闭掉 

通过动态代理给加了代码   

 

-------------------------------------工厂模式

首先要区分 生产者 消费者     消费者不关心工厂、过程  只关心结果  从工厂取东西哈哈

简单工厂:

定义接口:

复制代码
//产品接口
//汽车需要满足一定的标准
public interface Car {
    
    //规定汽车的品牌
    String getName();
    
}
复制代码

实现之:

复制代码
public class Bmw implements Car{

    @Override
    public String getName() {
        return "BMW";
    }

}
复制代码
复制代码
public class Benz implements Car{

    @Override
    public String getName() {
        return "Benz";
    }

}
复制代码
复制代码
public class Audi implements Car{

    @Override
    public String getName() {
        return "Audi";
    }

}
复制代码

定义工厂类

复制代码
import com.gupaoedu.vip.factory.Audi;
import com.gupaoedu.vip.factory.Benz;
import com.gupaoedu.vip.factory.Bmw;
import com.gupaoedu.vip.factory.Car;

//对于这个工厂来说(太强大了)
//为什么?
//这个工厂啥都能干(不符合现实)
//编码也是一种艺术(融汇贯通),艺术来源于生活,回归到生活的
public class SimpleFactory {
    
    //实现统一管理、专业化管理
    //如果没有工厂模式,小作坊,没有执行标准的
    //如果买到三无产品(没有标准)
    //卫生监督局工作难度会大大减轻
    
    //中国制造(按人家的标准执行)
    //中国制造向中国创造改变(技术不是问题了,问题是什么?思维能力)
    //码农就是执行标准的人
    //系统架构师,就是制定标准的人
    
    //不只做一个技术者,更要做一个思考者
    
    
    public Car getCar(String name){
        if("BMW".equalsIgnoreCase(name)){
            //Spring中的工厂模式
            //Bean
            //BeanFactory(生成Bean)
            //单例的Bean
            //被代理过的Bean
            //最原始的Bean(原型)
            //List类型的Bean
            //作用域不同的Bean
            
            //getBean
            //非常的紊乱,维护困难
            //解耦(松耦合开发)
            return new Bmw();
        }else if("Benz".equalsIgnoreCase(name)){
            return new Benz();
        }else if("Audi".equalsIgnoreCase(name)){
            return new Audi();
        }else{
            System.out.println("这个产品产不出来");
            return null;
        }
    }
    
}
复制代码

测试类(消费者)

复制代码
public class SimpleFactoryTest {

    
    
    public static void main(String[] args) {
    
        //这边就是我们的消费者
        Car car = new SimpleFactory().getCar("Audi");
        System.out.println(car.getName());
        
    }
    
}
复制代码

接下来是 工厂方法模式

  定义工厂接口

  实现不同工厂

   消费者使用

1、定义工厂接口

 

复制代码
import com.gupaoedu.vip.factory.Car;

//工厂接口,就定义了所有工厂的执行标准
public interface Factory {

    //符合汽车上路标准
    //尾气排放标准
    //电子设备安全系数
    //必须配备安全带、安全气囊
    //轮胎的耐磨程度
    Car getCar();
    
}
复制代码

2、实现这个工厂接口

复制代码
import com.gupaoedu.vip.factory.Bmw;
import com.gupaoedu.vip.factory.Car;

public class BmwFactory implements Factory {

    @Override
    public Car getCar() {
        return new Bmw();
    }

}
复制代码
复制代码
import com.gupaoedu.vip.factory.Benz;
import com.gupaoedu.vip.factory.Car;

public class BenzFactory implements Factory {

    @Override
    public Car getCar() {
        return new Benz();
    }

}
复制代码

3、测试类

复制代码
public class FactoryTest {

    public static void main(String[] args) {
        
        //工厂方法模式
        //各个产品的生产商,都拥有各自的工厂
        //生产工艺,生成的高科技程度都是不一样的
        Factory factory = new AudiFactory();
        System.out.println(factory.getCar());
        
        //需要用户关心,这个产品的生产商
        factory = new BmwFactory();
        System.out.println(factory.getCar());
        
        //增加的代码的使用复杂度
        
        
        //抽象工厂模式
        
    }
    
}
复制代码

改进版的工厂方法模式,抽象工厂模式:

这个不再是 接口了 而是 抽象类

 抽象类可以引用自己的方法! 

默认的方法

复制代码
import com.gupaoedu.vip.factory.Car;

public class DefaultFactory extends AbstractFactory {

    private AudiFactory defaultFactory = new AudiFactory();
    
    public Car getCar() {
        return defaultFactory.getCar();
    }

}
复制代码

工厂方法

复制代码
import com.gupaoedu.vip.factory.Car;

public abstract class AbstractFactory {

     protected abstract Car getCar();
     
     
     //这段代码就是动态配置的功能
     //固定模式的委派
     public Car getCar(String name){
        if("BMW".equalsIgnoreCase(name)){
            return new BmwFactory().getCar();
        }else if("Benz".equalsIgnoreCase(name)){
            return new BenzFactory().getCar();
        }else if("Audi".equalsIgnoreCase(name)){
            return new AudiFactory().getCar();
        }else{
            System.out.println("这个产品产不出来");
            return null;
        }
    }

}
复制代码
复制代码
import com.gupaoedu.vip.factory.Audi;
import com.gupaoedu.vip.factory.Car;


//具体的业务逻辑封装
public class AudiFactory extends AbstractFactory {

    @Override
    public Car getCar() {
        return new Audi();
    }

}
复制代码
复制代码
public class BenzFactory extends AbstractFactory {

    @Override
    public Car getCar() {
        return new Benz();
    }

}
复制代码
复制代码
public class BmwFactory extends AbstractFactory {

    @Override
    public Car getCar() {
        return new Bmw();
    }

}
复制代码

 

单例模式:

整个系统从启动到终止,自会有一个实例

在应用中遇到功能性冲突的时候,需要用到单例模式

单例模式有7种写 法!!!

1.

复制代码
1 public class Singleton implements java.io.Serializable {   
2     public static Singleton INSTANCE = new Singleton();   
3     protected Singleton() {  }   
4     private Object readResolve() {   
5         return INSTANCE;   
6     }
7 }
复制代码

2、

复制代码
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton1 {
    //1、第一步先将构造方法私有化
    private Singleton1() {}
    //2、然后声明一个静态变量保存单例的引用
    private static Singleton1 single = null;
    //3、通过提供一个静态方法来获得单例的引用
    //不安全的
    public static Singleton1 getInstance() {
        if (single == null) {
            single = new Singleton1();
        }
        return single;
    }
}
复制代码

 

3、

复制代码
//懒汉式单例.保证线程安全
public class Singleton2 {
    //1、第一步先将构造方法私有化
    private Singleton2() {}
    //2、然后声明一个静态变量保存单例的引用
    private static Singleton2 single=null;
    //3、通过提供一个静态方法来获得单例的引用
    //为了保证多线程环境下正确访问,给方法加上同步锁synchronized
    //慎用  synchronized 关键字,阻塞,性能非常低下的
    //加上synchronized关键字以后,对于getInstance()方法来说,它始终单线程来访问
    //没有充分利用上我们的计算机资源,造成资源的浪费
    public static synchronized Singleton2 getInstance() {
        if (single == null) {
            single = new Singleton2();
        }
        return single;  
    }
}
复制代码

4、

复制代码
//懒汉式单例.双重锁检查
public class Singleton3 {
    //1、第一步先将构造方法私有化
    private Singleton3() {}
    //2、然后声明一个静态变量保存单例的引用
    private static Singleton3 single=null;
    //3、通过提供一个静态方法来获得单例的引用
    //为了保证多线程环境下的另一种实现方式,双重锁检查
    //性能,第一次的时候
    public static Singleton3 getInstance() {  
      if (single == null) {
          synchronized (Singleton3.class) {
              if (single == null) {    
                  single = new Singleton3();
              }    
          }    
      }    
       return single;   
    }
}
复制代码

5、

复制代码
//懒汉式(静态内部类)
//这种写法,即解决安全问题,又解决了性能问题
//这个代码,没有浪费一个字
public class Singleton4 {
    //1、先声明一个静态内部类
    //private 私有的保证别人不能修改
    //static 保证全局唯一
    private static class LazyHolder {
        //final 为了防止内部误操作,代理模式,GgLib的代理模式
        private static final Singleton4 INSTANCE = new Singleton4();
    }
    //2、将默认构造方法私有化
    private Singleton4 (){}
    //相当于有一个默认的public的无参的构造方法,就意味着在代码中随时都可以new出来
        
    //3、同样提供静态方法获取实例
    //final 确保别人不能覆盖
    public static final Singleton4 getInstance() {  
        
        //方法中的逻辑,是要在用户调用的时候才开始执行的
        //方法中实现逻辑需要分配内存,也是调用时才分配的
        return LazyHolder.INSTANCE;
    }
    
//    static int a = 1;
//    //不管该class有没有实例化,static静态块总会在classLoader执行完以后,就加载完毕
//    static{
//        //静态块中的内容,只能访问静态属性和静态方法
//        //只要是静态方法或者属性,直接可以用Class的名字就能点出来
//        Singleton4.a = 2;
//        //JVM 内存中的静态区,这一块的内容是公共的 
//    }
}

//我们所写的所有的代码,在java的反射机制面前,都是裸奔的
//反射机制是可以拿到private修饰的内容的
//我们可以理解成即使加上private也不靠谱(按正常套路出牌,貌似可以)


//类装载到JVM中过程
//1、从上往下(必须声明在前,使用在后)
//先属性、后方法
//先静态、后动态
复制代码

6、

复制代码
  //类似Spring里面的方法,将类名注册,下次从里面直接获取。  
public class Singleton6 {  
    private static Map<String,Singleton6> map = new HashMap<String,Singleton6>();  
    static {
        Singleton6 single = new Singleton6();
        map.put(single.getClass().getName(), single);
    }
    //保护的默认构造子  
    protected Singleton6(){}  
    //静态工厂方法,返还此类惟一的实例  
    public static Singleton6 getInstance(String name) {  
        if(name == null) {  
             name = Singleton6.class.getName();  
        }  
        if(map.get(name) == null) {  
       try {  
           map.put(name, (Singleton6) Class.forName(name).newInstance());  
       } catch (InstantiationException e) {  
           e.printStackTrace();  
       } catch (IllegalAccessException e) {  
           e.printStackTrace();  
       } catch (ClassNotFoundException e) {  
           e.printStackTrace();  
       }  
}  
return map.get(name);  
}  
}
复制代码

测试类

复制代码
public class TestMain {
    public static void main(String[] args){  
        TestSingleton ts1 = TestSingleton.getInstance();  
        ts1.setName("james");  
        TestSingleton ts2 = TestSingleton.getInstance();  
        ts2.setName("tom");  
          
        ts1.printInfo();  
        ts2.printInfo();  
          
        if(ts1 == ts2){  
            System.out.println("创建的是同一个实例" + ts1.getName());  
        }else{  
            System.out.println("创建的不是同一个实例" + ts1.getName());  
        }  
    }
}
复制代码
复制代码
public class TestSingleton {  
    String name = null;  
    private TestSingleton() {}  
  
    //注意这里用到了volatile关键字
    private static volatile TestSingleton instance = null;  
  
    public static TestSingleton getInstance() {  
       if (instance == null) {    
         synchronized (TestSingleton.class) {    
            if (instance == null) {    
               instance = new TestSingleton();   
            }    
         }    
       }   
       return instance;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public void printInfo() {  
        System.out.println("the name is " + name);  
    }  
  
}
复制代码
复制代码
public class TestThread {
    
    public static void main(String[] args) {
        //启动100线程同时去抢CPU
        int count = 100;
        
        //发令枪,测试并发经常用到
        CountDownLatch latch = new CountDownLatch(count);
        //Set默认去去重的,set是本身线程不安全的
        //
        final Set<Singleton1> syncSet = Collections.synchronizedSet(new HashSet<Singleton1>());
        
        for (int i = 0; i < count; i++) {
            new Thread(){

                @Override
                public void run() {
                    syncSet.add(Singleton1.getInstance());
                }
            }.start();
            
            latch.countDown();
        }
          
        try {
            latch.await();//等待所有线程全部完成,最终输出结果
            System.out.println(syncSet.size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
}
复制代码

 

委派模式:

 1类似中介的功能(委托机制)

 2只有被委托人的引用 

两个角色 受托人 委托人

 定义一个接口

复制代码
public class Dispatcher implements IExector{
    IExector exector;
    
    Dispatcher(IExector exector){
        this.exector = exector;
    }
    
    
    //项目经理,虽然也有执行方法
    //但是他的工作职责是不一样的
    public void doing() {
        this.exector.doing();
    }

}
复制代码

两个员工类实现这个接口

复制代码
public class ExectorA implements IExector {

    @Override
    public void doing() {
        System.out.println("xxoo");
    }

}
复制代码
复制代码
public class ExectorB implements IExector{

    @Override
    public void doing() {
        System.out.println("员工B开始执行任务");
    }

}
复制代码

项目经理类

复制代码
public class Dispatcher implements IExector{
    IExector exector;
    
    Dispatcher(IExector exector){
        this.exector = exector;
    }
    
    
    //项目经理,虽然也有执行方法
    //但是他的工作职责是不一样的
    public void doing() {
        this.exector.doing();
    }

}
复制代码

测试

复制代码
public class DispatcherTest {

    
    public static void main(String[] args) {
        Dispatcher dispatcher = new Dispatcher(new ExectorA());
        //看上去好像是我们的项目经理在干活
        //但实际干活的人是普通员工
        //这就是典型,干活是我的,功劳是你的
        dispatcher.doing();
    }
    
}
复制代码

IOC容器中,有一个Register的东西(为了告诉我们的容器,在这个类被初始化的过程中,需要做很多不同的逻辑处理,需要实现多个任务执行者,分别实现各自的功能 )

关于策略模式,参考系 Comparator方法就可以啦 返回  -1 0 1这种的

  a、比较器接口

  b、调用时候有自己的实现

复制代码
//比较器
public interface Comparator {
    
    int compareTo(Object obj1,Object obj2);
    
}
复制代码
复制代码
public class ObjectComparator implements Comparator{

    @Override
    public int compareTo(Object obj1, Object obj2) {
        return 0;
    }

}
复制代码
复制代码
public class NumberComparator implements Comparator{

    @Override
    public int compareTo(Object obj1, Object obj2) {
        return 0;
    }

}
复制代码
复制代码
public class MyList {
    
    public void sort(Comparator com){
//        com.compareTo(obj1, obj2);
        System.out.println("执行逻辑");
    }
    
}
复制代码
复制代码
public class MyListTest {
    
    public static void main(String[] args) {
        //new MyList().sort(new NumberComparator());
        
        
        //策略模式
//        List<Long> numbers = new ArrayList<Long>();
//        
//        Collections.sort(numbers, new Comparator<Long>() {
//
//            @Override
//            //返回值是固定的
//            //0 、-1 、1
//            //0 、 >0 、<0
//            public int compare(Long o1, Long o2) {
//                
//                //中间逻辑是不一样的
//                
//                return 0;
//            }
//            
//            
//        });
    }
}
复制代码

 原型模式:  

  首先要设计个原型

    实现 Cloneable接口

 

复制代码
public class ConcretePrototype implements Cloneable{

    private int age;

    private String name;
    
    public ArrayList<String> list = new ArrayList<String>();
    
    protected Object clone() throws CloneNotSupportedException {
        ConcretePrototype prototype = null;
        try{
            prototype = (ConcretePrototype)super.clone();
            prototype.list = (ArrayList)list.clone();
            
            //克隆基于字节码的
            //用反射,或者循环
        }catch(Exception e){
            
        }
        
        return prototype;
    }

    
    //定义上100个属性
    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    
    
    
    
}
复制代码
复制代码
public class CloneTest {

    
    
    public static void main(String[] args) {
        
        ConcretePrototype cp = new ConcretePrototype();
        cp.setAge(18);
        cp.setName("Tom");
        
        //cp.list.add("Tom");
        
        try {
            ConcretePrototype copy = (ConcretePrototype)cp.clone();
            
            System.out.println(copy.list  == cp.list);
            System.out.println(copy.getAge() + "," + copy.getName() + copy.list.size());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        
        //就是一个现成的对象,这个对象里面有已经设置好的值
        //当我要新建一个对象,并且要给新建的对象赋值,而且赋值内容要跟之前的一模一样
        
        
        //ConcretePrototype cp = new ConcretePrototype();
        //cp.setAge(18);
        
        //ConcretePrototype copy = new ConcretePrototype();
        //copy.setAge(cp.getAge());
        //copy.setName(cp.getName());
        //用循环,用反射,确实可以的(反射性能并不高)
        //字节码复制newInstance()
        
        //ConcretePrototype copy = cp;
        //ORM的时候经常用到的
        
        
        //能够直接拷贝其实际内容的数据类型/只支持9种,八大基本数据类型+String 浅拷贝
        //深拷贝
    }
    
}
复制代码

原型模式:

复制代码
//猴子
public class Monkey {
    //身高
    protected int height;//基本
    //体重
    protected int weight;
    //生日
    protected Date birthday;//不是基本类型
    
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }


    
    
}
复制代码
复制代码
public class TestPrototype {
    public static void main(String[] args) {
        TheGreatestSage sage = new TheGreatestSage();
        sage.change();
        
        //跟《西游记》中描述的一致,怎么办?
    }
}
复制代码
复制代码
public class GoldRingedStaff implements Serializable{
    
    private float height = 100; //长度
    private float diameter = 10;//直径
    
    
    
    /**
     * 金箍棒长大
     */
    public void grow(){
        this.diameter *= 2;
        this.height *= 2;
    }
    
    /**
     * 金箍棒缩小
     */
    public void shrink(){
        this.diameter /= 2;
        this.height /= 2;
    }
    
}
复制代码
复制代码
/**
 * 齐天大圣
 *
 */
public class   TheGreatestSage  extends Monkey implements Cloneable,Serializable{
    
    //金箍棒
    private GoldRingedStaff staff;
    
    //从石头缝里蹦出来
    public TheGreatestSage(){
        this.staff = new GoldRingedStaff();
        this.birthday = new Date();
        this.height = 150;
        this.weight = 30;
        System.out.println("------------------------");
    }
    
    //分身技能
    public Object clone(){
        //深度克隆
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //return super.clone();//默认浅克隆,只克隆八大基本数据类型和String
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            TheGreatestSage copy = (TheGreatestSage)ois.readObject();
            copy.birthday = new Date();
            
            return copy;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }finally{
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //变化
    public void change(){
        TheGreatestSage copySage = (TheGreatestSage)clone();
        System.out.println("大圣本尊生日是:" + this.getBirthday().getTime());
        System.out.println("克隆大圣的生日是:" + copySage.getBirthday().getTime());
        System.out.println("大圣本尊和克隆大圣是否为同一个对象:" + (this == copySage));
        System.out.println("大圣本尊持有的金箍棒跟克隆大圣持有金箍棒是否为同一个对象:" + (this.getStaff() == copySage.getStaff()));
    }
    
    public GoldRingedStaff getStaff() {
        return staff;
    }

    public void setStaff(GoldRingedStaff staff) {
        this.staff = staff;
    }
    
    
    
    
}
复制代码

模板模式:

模板(固定的执行流程)

定义冲饮料的机器:

复制代码
//冲饮料(拿出去卖钱了)
public abstract class Bevegrage {
    
    //不能被重写
    public final void create(){
        //1、把水烧开
        boilWater();
        //2、把杯子准备好、原材料放到杯中
        pourInCup();
        //3、用水冲泡
        brew();
        //4、添加辅料
        addCoundiments();
    }
    
    public abstract void pourInCup();
    
    public abstract void addCoundiments();
    
    
    public void brew(){
        System.out.println("将开水放入杯中进行冲泡");
    };
    
    public void boilWater(){
        System.out.println("烧开水,烧到100度可以起锅了");
    }
    
}