1. 程式人生 > >Spring源碼分析 之淺談設計模式

Spring源碼分析 之淺談設計模式

throw rup change getheight 配置 owa 委派 bean 松耦合

一直想專門寫個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度可以起鍋了");
    }
    
}
技術分享圖片

實現為沖咖啡的

技術分享圖片
public class Coffee  extends Bevegrage{

    //原材料放到杯中
    public void pourInCup() {
        System.out.println("將咖啡倒入杯中");
    }

    //房輔料
    public void addCoundiments() {
        System.out.println("添加牛奶和糖");
    }

}
技術分享圖片

實現為泡茶的

技術分享圖片
public class Tea extends Bevegrage{

    //原材料放到杯中
    public void pourInCup() {
        System.out.println("將茶葉放入杯中");
    }

    //房輔料
    public void addCoundiments() {
        System.out.println("添加蜂蜜");
    }

}
技術分享圖片

測試類

技術分享圖片
public class TestTemplate {
    
    public static void main(String[] args) {
        
//        Coffee coffee = new Coffee();
//        coffee.create();
        
        Tea tea = new Tea();
        tea.create();
        
    }
    
    
    //SpringJDBC
    //是java規範,各個數據庫廠商自己去實現
    //1、加載驅動類DriverManager
    //2、建立連接
    //3、創建語句集(標準語句集、預處理語句集)(語句集?  MySQL、Oracle、SQLServer、Access)
    //4、執行語句集
    //5、結果集ResultSet 遊標
    //ORM(?)
    
}
技術分享圖片

Spring JDBC就是個模板模式

是 Java的規範 各個數據庫廠商去實現

1、加載驅動類 DriverManager

2、建立連接

3、創建語句集(標準語句集、預處理語句集)(語句集合? Mysql oracle sqlserver access 語句不太一樣哦)

4、執行語句集

5、結果集ResultSet 遊標

ORM (連接的是哪個對象 映射哪個結果 List or 自定義的類 還是??運行時候才知道)

https://www.cnblogs.com/toov5/p/9472082.html

Spring源碼分析 之淺談設計模式