一直想專門寫個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

