2012年7月3日
版權(quán)信息: 可以任意轉(zhuǎn)載, 轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原文出處, 即下面的聲明.
原文出處:http://blog.chenlb.com/2009/06/java-classloader-architecture.html
jvm classLoader architecture:
- Bootstrap ClassLoader/啟動(dòng)類加載器
主要負(fù)責(zé)jdk_home/lib目錄下的核心 api 或 -Xbootclasspath 選項(xiàng)指定的jar包裝入工作。 - Extension ClassLoader/擴(kuò)展類加載器
主要負(fù)責(zé)jdk_home/lib/ext目錄下的jar包或 -Djava.ext.dirs 指定目錄下的jar包裝入工作。 - System ClassLoader/系統(tǒng)類加載器
主要負(fù)責(zé)java -classpath/-Djava.class.path所指的目錄下的類與jar包裝入工作。 - User Custom ClassLoader/用戶自定義類加載器(java.lang.ClassLoader的子類)
在程序運(yùn)行期間, 通過java.lang.ClassLoader的子類動(dòng)態(tài)加載class文件, 體現(xiàn)java動(dòng)態(tài)實(shí)時(shí)類裝入特性。
類加載器的特性:
- 每個(gè)ClassLoader都維護(hù)了一份自己的名稱空間, 同一個(gè)名稱空間里不能出現(xiàn)兩個(gè)同名的類。
- 為了實(shí)現(xiàn)java安全沙箱模型頂層的類加載器安全機(jī)制, java默認(rèn)采用了 " 雙親委派的加載鏈 " 結(jié)構(gòu)。

classloader-architecture

classloader-class-diagram
類圖中, BootstrapClassLoader是一個(gè)單獨(dú)的java類, 其實(shí)在這里, 不應(yīng)該叫他是一個(gè)java類。因?yàn)椋呀?jīng)完全不用java實(shí)現(xiàn)了。它是在jvm啟動(dòng)時(shí), 就被構(gòu)造起來的, 負(fù)責(zé)java平臺(tái)核心庫。
自定義類加載器加載一個(gè)類的步驟

classloader-load-class
ClassLoader 類加載邏輯分析, 以下邏輯是除 BootstrapClassLoader 外的類加載器加載流程:
- // 檢查類是否已被裝載過
- Class c = findLoadedClass(name);
- if (c == null ) {
- // 指定類未被裝載過
- try {
- if (parent != null ) {
- // 如果父類加載器不為空, 則委派給父類加載
- c = parent.loadClass(name, false );
- } else {
- // 如果父類加載器為空, 則委派給啟動(dòng)類加載加載
- c = findBootstrapClass0(name);
- }
- } catch (ClassNotFoundException e) {
- // 啟動(dòng)類加載器或父類加載器拋出異常后, 當(dāng)前類加載器將其
- // 捕獲, 并通過findClass方法, 由自身加載
- c = findClass(name);
- }
- }
線程上下文類加載器
java默認(rèn)的線程上下文類加載器是 系統(tǒng)類加載器(AppClassLoader)。
- // Now create the class loader to use to launch the application
- try {
- loader = AppClassLoader.getAppClassLoader(extcl);
- } catch (IOException e) {
- throw new InternalError(
- "Could not create application class loader" );
- }
-
- // Also set the context class loader for the primordial thread.
- Thread.currentThread().setContextClassLoader(loader);
以上代碼摘自sun.misc.Launch的無參構(gòu)造函數(shù)Launch()。
使用線程上下文類加載器, 可以在執(zhí)行線程中, 拋棄雙親委派加載鏈模式, 使用線程上下文里的類加載器加載類.
典型的例子有, 通過線程上下文來加載第三方庫jndi實(shí)現(xiàn), 而不依賴于雙親委派.
大部分java app服務(wù)器(jboss, tomcat..)也是采用contextClassLoader來處理web服務(wù)。
還有一些采用 hotswap 特性的框架, 也使用了線程上下文類加載器, 比如 seasar (full stack framework in japenese).
線程上下文從根本解決了一般應(yīng)用不能違背雙親委派模式的問題.
使java類加載體系顯得更靈活.
隨著多核時(shí)代的來臨, 相信多線程開發(fā)將會(huì)越來越多地進(jìn)入程序員的實(shí)際編碼過程中. 因此,
在編寫基礎(chǔ)設(shè)施時(shí), 通過使用線程上下文來加載類, 應(yīng)該是一個(gè)很好的選擇。
當(dāng)然, 好東西都有利弊. 使用線程上下文加載類, 也要注意, 保證多根需要通信的線程間的類加載器應(yīng)該是同一個(gè),
防止因?yàn)椴煌念惣虞d器, 導(dǎo)致類型轉(zhuǎn)換異常(ClassCastException)。
為什么要使用這種雙親委托模式呢?
- 因?yàn)檫@樣可以避免重復(fù)加載,當(dāng)父親已經(jīng)加載了該類的時(shí)候,就沒有必要子ClassLoader再加載一次。
- 考慮到安全因素,我們試想一下,如果不使用這種委托模式,那我們就可以隨時(shí)使用自定義的String來動(dòng)態(tài)替代java核心api中定義類型,這樣會(huì)存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因?yàn)镾tring已經(jīng)在啟動(dòng)時(shí)被加載,所以用戶自定義類是無法加載一個(gè)自定義的ClassLoader。
java動(dòng)態(tài)載入class的兩種方式:
- implicit隱式,即利用實(shí)例化才載入的特性來動(dòng)態(tài)載入class
- explicit顯式方式,又分兩種方式:
- java.lang.Class的forName()方法
- java.lang.ClassLoader的loadClass()方法
用Class.forName加載類
Class.forName使用的是被調(diào)用者的類加載器來加載類的。
這種特性, 證明了java類加載器中的名稱空間是唯一的, 不會(huì)相互干擾。
即在一般情況下, 保證同一個(gè)類中所關(guān)聯(lián)的其他類都是由當(dāng)前類的類加載器所加載的。
- public static Class forName(String className)
- throws ClassNotFoundException {
- return forName0(className, true , ClassLoader.getCallerClassLoader());
- }
-
- /** Called after security checks have been made. */
- private static native Class forName0(String name, boolean initialize,
- ClassLoader loader)
- throws ClassNotFoundException;
上面中 ClassLoader.getCallerClassLoader 就是得到調(diào)用當(dāng)前forName方法的類的類加載器
static塊在什么時(shí)候執(zhí)行?
- 當(dāng)調(diào)用forName(String)載入class時(shí)執(zhí)行,如果調(diào)用ClassLoader.loadClass并不會(huì)執(zhí)行.forName(String,false,ClassLoader)時(shí)也不會(huì)執(zhí)行.
- 如果載入Class時(shí)沒有執(zhí)行static塊則在第一次實(shí)例化時(shí)執(zhí)行.比如new ,Class.newInstance()操作
- static塊僅執(zhí)行一次
各個(gè)java類由哪些classLoader加載?
- java類可以通過實(shí)例.getClass.getClassLoader()得知
- 接口由AppClassLoader(System ClassLoader,可以由ClassLoader.getSystemClassLoader()獲得實(shí)例)載入
- ClassLoader類由bootstrap loader載入
NoClassDefFoundError和ClassNotFoundException
- NoClassDefFoundError:當(dāng)java源文件已編譯成.class文件,但是ClassLoader在運(yùn)行期間在其搜尋路徑load某個(gè)類時(shí),沒有找到.class文件則報(bào)這個(gè)錯(cuò)
- ClassNotFoundException:試圖通過一個(gè)String變量來創(chuàng)建一個(gè)Class類時(shí)不成功則拋出這個(gè)異常
一:使用場景
1)使用的地方:樹形結(jié)構(gòu),分支結(jié)構(gòu)等
2)使用的好處:降低客戶端的使用,為了達(dá)到元件與組合件使用的一致性,增加了元件的編碼
3)使用后的壞處:代碼不容易理解,需要你認(rèn)真去研究,發(fā)現(xiàn)元件與組合件是怎么組合的
二:一個(gè)實(shí)際的例子
畫圖形,這個(gè)模式,稍微要難理解一點(diǎn),有了例子就說明了一切,我畫的圖是用接口做的,代碼實(shí)現(xiàn)是抽象類為基類,你自己選擇了,接口也可以。

1)先建立圖形元件
package com.mike.pattern.structure.composite;
/**
* 圖形元件
*
* @author taoyu
*
* @since 2010-6-23
*/
public abstract class Graph {
/**圖形名稱*/
protected String name;
public Graph(String name){
this.name=name;
}
/**畫圖*/
public abstract void draw()throws GraphException;
/**添加圖形*/
public abstract void add(Graph graph)throws GraphException;
/**移掉圖形*/
public abstract void remove(Graph graph)throws GraphException;
}
2)建立基礎(chǔ)圖形圓
package com.mike.pattern.structure.composite;
import static com.mike.util.Print.print;
/**
* 圓圖形
*
* @author taoyu
*
* @since 2010-6-23
*/
public class Circle extends Graph {
public Circle(String name){
super(name);
}
/**
* 圓添加圖形
* @throws GraphException
*/
@Override
public void add(Graph graph) throws GraphException {
throw new GraphException("圓是基礎(chǔ)圖形,不能添加");
}
/**
* 圓畫圖
*/
@Override
public void draw()throws GraphException {
print(name+"畫好了");
}
/**
* 圓移掉圖形
*/
@Override
public void remove(Graph graph)throws GraphException {
throw new GraphException("圓是基礎(chǔ)圖形,不能移掉");
}
}
3)建立基礎(chǔ)圖形長方形
package com.mike.pattern.structure.composite;
import static com.mike.util.Print.print;
/**
* 長方形
*
* @author taoyu
*
* @since 2010-6-23
*/
public class Rectangle extends Graph {
public Rectangle(String name){
super(name);
}
/**
* 長方形添加
*/
@Override
public void add(Graph graph) throws GraphException {
throw new GraphException("長方形是基礎(chǔ)圖形,不能添加");
}
/**
* 畫長方形
*/
@Override
public void draw() throws GraphException {
print(name+"畫好了");
}
@Override
public void remove(Graph graph) throws GraphException {
throw new GraphException("長方形是基礎(chǔ)圖形,不能移掉");
}
}
4)最后簡歷組合圖形
package com.mike.pattern.structure.composite;
import java.util.ArrayList;
import java.util.List;
import static com.mike.util.Print.print;
/**
* 圖形組合體
*
* @author taoyu
*
* @since 2010-6-23
*/
public class Picture extends Graph {
private List<Graph> graphs;
public Picture(String name){
super(name);
/**默認(rèn)是10個(gè)長度*/
graphs=new ArrayList<Graph>();
}
/**
* 添加圖形元件
*/
@Override
public void add(Graph graph) throws GraphException {
graphs.add(graph);
}
/**
* 圖形元件畫圖
*/
@Override
public void draw() throws GraphException {
print("圖形容器:"+name+" 開始創(chuàng)建");
for(Graph g : graphs){
g.draw();
}
}
/**
* 圖形元件移掉圖形元件
*/
@Override
public void remove(Graph graph) throws GraphException {
graphs.remove(graph);
}
}
5)最后測試
public static void main(String[] args)throws GraphException {
/**畫一個(gè)圓,圓里包含一個(gè)圓和長方形*/
Picture picture=new Picture("立方體圓");
picture.add(new Circle("圓"));
picture.add(new Rectangle("長方形"));
Picture root=new Picture("怪物圖形");
root.add(new Circle("圓"));
root.add(picture);
root.draw();
}
6)使用心得:的確降低了客戶端的使用情況,讓整個(gè)圖形可控了,當(dāng)是你要深入去理解,才真名明白采用該模式的含義,不太容易理解。
一:使用場景
1)使用的地方:我想使用兩個(gè)不同類的方法,這個(gè)時(shí)候你需要把它們組合起來使用
2)目前使用的情況:我會(huì)把兩個(gè)類用戶組合的方式放到一起,編程思想think in java里已經(jīng)提到個(gè),能盡量用組合就用組合,繼承一般考慮再后。
3)使用后的好處:你不需要改動(dòng)以前的代碼,只是新封裝了一新類,由這個(gè)類來提供兩個(gè)類的方法,這個(gè)時(shí)候:一定會(huì)想到facade外觀模式,本來是多個(gè)類使用的情況,我新封裝成一個(gè)類來使用,而這個(gè)類我采用組合的方式來包裝新的方法。我的理解是,設(shè)計(jì)模式本身就是為了幫助解決特定的業(yè)務(wù)場景而故意把模式劃分對(duì)應(yīng)的模式類別,其實(shí)大多數(shù)情況,都解決了同樣的問題,這個(gè)時(shí)候其實(shí)沒有必要過多的糾纏到模式的名字上了,你有好的注意,你甚至取一個(gè)新的名字來概括這樣的使用場景。
4)使用的壞處:適配器模式,有兩種方式來實(shí)現(xiàn)。一個(gè)是組合一個(gè)是繼承,我覺得,首先應(yīng)該考慮組合,能用組合就不要用繼承,這是第一個(gè)。第二個(gè),你采用繼承來實(shí)現(xiàn),那肯定會(huì)加大繼承樹結(jié)構(gòu),如果你的繼承關(guān)系本身就很復(fù)雜了,這肯定會(huì)加大繼承關(guān)系的維護(hù),不有利于代碼的理解,或則更加繁瑣。繼承是為了解決重用的為題而出現(xiàn)的,所以我覺得不應(yīng)該濫用繼承,有機(jī)會(huì)可以考慮同樣別的方案。
二:一個(gè)實(shí)際的例子
關(guān)聯(lián)營銷的例子,用戶購買完商品后,我又推薦他相關(guān)別的商品
由于減少代碼,方法我都不采用接口,直接由類來提供,代碼只是一個(gè)范例而已,都精簡了。
1)創(chuàng)建訂單信息
public class Order {
private Long orderId;
private String nickName;
public Order(Long orderId,String nickName){
this.orderId=orderId;
this.nickName=nickName;
}
/**
* 用戶下訂單
*/
public void insertOrder(){
}
}
2)商品信息
public class Auction {
/**商品名稱*/
private String name;
/**制造商*/
private String company;
/**制造日期*/
private Date date;
public Auction(String name,String company, Date date){
this.name=name;
this.company=company;
this.date=date;
}
/**
* 推廣的商品列表
*/
public void commendAuction(){
}
}
3)購物
public class Trade {
/**用戶訂單*/
private Order order;
/**商品信息*/
private Auction auction;
public Trade(Order order ,Auction auction){
this.order=order;
this.auction=auction;
}
/**
* 用戶產(chǎn)生訂單以及后續(xù)的事情
*/
public void trade(){
/**下訂單*/
order.insertOrder();
/**關(guān)聯(lián)推薦相關(guān)的商品*/
auction.commendAuction();
}
}
4)使用心得:其實(shí)外面采用了很多繼承的方式,order繼承auction之后,利用super .inserOrder()再加一個(gè)auction.recommendAuction(),實(shí)際上大同小異,我到覺得采用組合更容易理解以及代碼更加優(yōu)美點(diǎn)。
一:使用場景
1)使用到的地方:如果你想創(chuàng)建類似汽車這樣的對(duì)象,首先要?jiǎng)?chuàng)建輪子,玻璃,桌椅,發(fā)動(dòng)機(jī),外廓等,這些部件都創(chuàng)建好后,最后創(chuàng)建汽車成品,部件的創(chuàng)建和汽車的組裝過程本身都很復(fù)雜的情況,希望把部件的創(chuàng)建和成品的組裝分開來做,這樣把要做的事情分割開來,降低對(duì)象實(shí)現(xiàn)的復(fù)雜度,也降低以后成本的維護(hù),把汽車的部件創(chuàng)建和組裝過程獨(dú)立出兩個(gè)對(duì)應(yīng)的工廠來做,有點(diǎn)類似建立兩個(gè)對(duì)應(yīng)的部件創(chuàng)建工廠和汽車組裝工廠兩個(gè)工廠,而工廠只是創(chuàng)建一個(gè)成品,并沒有把里面的步驟也獨(dú)立出來,應(yīng)該說Builder模式比工廠模式又進(jìn)了一步。
2)采用Builder模式后的好處:把一個(gè)負(fù)責(zé)的對(duì)象的創(chuàng)建過程分解,把一個(gè)對(duì)象的創(chuàng)建分成兩個(gè)對(duì)象來負(fù)責(zé)創(chuàng)建,代碼更有利于維護(hù),可擴(kuò)性比較好。
3)采用Builder模式后的壞處:實(shí)現(xiàn)起來,對(duì)應(yīng)的接口以及部件的對(duì)象的創(chuàng)建比較多,代碼相對(duì)來講,比較多了,估計(jì)剛開始你會(huì)有點(diǎn)暈,這個(gè)可以考慮代碼精簡的問題,增加代碼的可讀性。
二:一個(gè)實(shí)際的例子
汽車的組裝
1)首先創(chuàng)建汽車這個(gè)成品對(duì)象,包含什么的成員
public class Car implements Serializable{
/**
* 汽車序列號(hào)
*/
private static final long serialVersionUID = 1L;
/**汽車輪子*/
private Wheel wheel;
/**汽車發(fā)動(dòng)機(jī)*/
private Engine engine;
/**汽車玻璃*/
private Glass glass;
/**汽車座椅*/
private Chair chair;
public Wheel getWheel() {
return wheel;
}
public void setWheel(Wheel wheel) {
this.wheel = wheel;
}
public Engine getEngine() {
return engine;
}
public void setEngine(Engine engine) {
this.engine = engine;
}
public Glass getGlass() {
return glass;
}
public void setGlass(Glass glass) {
this.glass = glass;
}
public Chair getChair() {
return chair;
}
public void setChair(Chair chair) {
this.chair = chair;
}
}
2)創(chuàng)建對(duì)應(yīng)汽車零部件
public class Wheel {
public Wheel(){
print("--汽車輪子構(gòu)建完畢--");
}
}
public class Engine {
public Engine(){
print("--汽車發(fā)動(dòng)機(jī)構(gòu)建完畢--");
}
}
public class Glass {
public Glass(){
print("--汽車玻璃構(gòu)建完畢--");
}
}
public class Chair {
public Chair(){
print("--汽車座椅構(gòu)建完畢--");
}
}
3)開始重點(diǎn)了,汽車成品的組裝過程
public interface Builder {
/**組裝汽車輪子*/
public void buildWheel();
/**組裝汽車發(fā)動(dòng)機(jī)*/
public void buildEngine();
/**組裝汽車玻璃*/
public void buildGlass();
/**組裝汽車座椅*/
public void buildChair();
/**返回組裝好的汽車*/
public Car getCar();
}
以及實(shí)現(xiàn)類
public class CarBuilder implements Builder {
/**汽車成品*/
private Car car;
public CarBuilder(){
car=new Car();
}
/**組裝汽車輪子*/
@Override
public void buildChair() {
car.setChair(new Chair());
}
/**組裝汽車發(fā)動(dòng)機(jī)*/
@Override
public void buildEngine() {
car.setEngine(new Engine());
}
/**組裝汽車玻璃*/
@Override
public void buildGlass() {
car.setGlass(new Glass());
}
/**組裝汽車座椅*/
@Override
public void buildWheel() {
car.setWheel(new Wheel());
}
/**返回組裝好的汽車*/
@Override
public Car getCar() {
buildChair();
buildEngine();
buildGlass();
buildWheel();
print("--整個(gè)汽車構(gòu)建完畢--");
return car;
}
}
4)最后汽車創(chuàng)建測試
public static void main(String[] args) {
/**創(chuàng)建汽車組裝*/
Builder carBuilder=new CarBuilder();
Car car=carBuilder.getCar();
}
最后輸出:
--汽車座椅構(gòu)建完畢--
--汽車發(fā)動(dòng)機(jī)構(gòu)建完畢--
--汽車玻璃構(gòu)建完畢--
--汽車輪子構(gòu)建完畢--
--整個(gè)汽車構(gòu)建完畢--
5)體會(huì)心得:Builder模式實(shí)際的重點(diǎn)就把汽車的組裝過程和零部件的生產(chǎn)分開來實(shí)現(xiàn),零部件的生成主要靠自己的對(duì)象來實(shí)現(xiàn),我上面只是在構(gòu)造函數(shù)里創(chuàng)建了,比較簡單,而重點(diǎn)汽車的組裝則交給CarBuilder來實(shí)現(xiàn),最終由builder來先負(fù)責(zé)零部件的創(chuàng)建,最后返回出成品的汽車。
一:使用場景
1)經(jīng)常使用的地方:一個(gè)類只有一個(gè)實(shí)例,eg:頁面訪問統(tǒng)計(jì)pv,統(tǒng)計(jì)的個(gè)數(shù)就只能保證一個(gè)實(shí)例的統(tǒng)計(jì)。
2)我們目前使用的情況:比如我想創(chuàng)建一個(gè)對(duì)象,這個(gè)對(duì)象希望只有一份實(shí)例的維護(hù),在內(nèi)存的保存也只有一份,也就是在同一個(gè)jvm的java堆里只保存一份實(shí)例對(duì)象,所以你會(huì)想一辦法,在創(chuàng)建這個(gè)對(duì)象的時(shí)候,就已經(jīng)能保證只有一份。
3)怎么改進(jìn):定義該對(duì)象的時(shí)候,就保證是同一份實(shí)例,比如:定義為私有構(gòu)造函數(shù),防止通過new的方式可以創(chuàng)建對(duì)象,然后在對(duì)象里定義一個(gè)靜態(tài)的私有成員(本身對(duì)象的一個(gè)實(shí)例),然后再創(chuàng)建一個(gè)外面訪問該對(duì)象的方法就好了。
4)改進(jìn)的好處:代碼在編譯代碼這個(gè)級(jí)別就被控制了,不至于在jvm里運(yùn)行的時(shí)候才來保證,把唯一實(shí)例的創(chuàng)建保證在編譯階段;jvm里內(nèi)存只有一份,從而內(nèi)存占有率更低,以及更方便java垃圾回收
5)改進(jìn)后的壞處:只能是代碼稍微需要更多點(diǎn),其實(shí)大家最后發(fā)現(xiàn)改進(jìn)后的壞處,都是代碼定義比之間要多一點(diǎn),但以后的維護(hù)代碼就降下來了,也短暫的代碼量偏大來換取以后代碼的精簡。
二:一個(gè)實(shí)際的例子
總體的例子
package com.mike.pattern.singleton;
/**
* 總統(tǒng)
*
* @author taoyu
*
* @since 2010-6-22
*/
public class President {
private President(){
System.out.println("總統(tǒng)已經(jīng)選舉出來了");
}
/**總統(tǒng)只有一個(gè)*/
private static President president=new President();
/**
* 返回總統(tǒng)
*/
public static President getPresident(){
return president;
}
/**
* 總統(tǒng)宣布選舉成功
*/
public void announce(){
System.out.println("偉大的中國人民,我將成你們新的總統(tǒng)");
}
}
/**
* @param args
*/
public static void main(String[] args) {
President president=President.getPresident();
president.announce();
}
1.使用場景
1)子類過多,不容易管理;構(gòu)造對(duì)象過程過長;精簡代碼創(chuàng)建;
2)目前我們代碼情況: 編寫代碼的時(shí)候,我們經(jīng)常都在new對(duì)象,創(chuàng)建一個(gè)個(gè)的對(duì)象,而且還有很多麻煩的創(chuàng)建方式,eg:HashMap<String,Float> grade=new HashMap<String,Float>(),這樣的代碼創(chuàng)建方式太冗長了,難道你沒有想過把這個(gè)創(chuàng)建變的短一點(diǎn)么,比如:HashMap<String,Float>grade=HashMapFactory.new(),可以把你創(chuàng)建精簡一點(diǎn);你也可以還有別的需求,在創(chuàng)建對(duì)象的時(shí)候,你需要不同的情況,創(chuàng)建統(tǒng)一種類別的對(duì)象,eg:我想生成不同的汽車,創(chuàng)建小轎車,創(chuàng)建卡車,創(chuàng)建公交汽車等等,都屬于同種類別:汽車,你難道沒有想過,我把這些創(chuàng)建的對(duì)象在一個(gè)工廠里來負(fù)責(zé)創(chuàng)建,我把創(chuàng)建分開化,交給一人來負(fù)責(zé),這樣可以讓代碼更加容易管理,創(chuàng)建方式也可以簡單點(diǎn)。
比如:Car BMW=CarFactory.create(bmw); 把創(chuàng)建new由一個(gè)統(tǒng)一負(fù)責(zé),這樣管理起來相當(dāng)方便
3)怎么改進(jìn):這個(gè)時(shí)候,你會(huì)想到,創(chuàng)建這樣同類別的東西,我把這個(gè)權(quán)利分出去,讓一個(gè)人來單獨(dú)管理,它只負(fù)責(zé)創(chuàng)建我的對(duì)象這個(gè)事情,所以你單獨(dú)簡歷一個(gè)對(duì)象來創(chuàng)建同類的對(duì)象,這個(gè)時(shí)候,你想這個(gè)東西有點(diǎn)像工廠一樣,生成同樣的產(chǎn)品,所以取了個(gè)名字:工廠模式,顧名思義,只負(fù)責(zé)對(duì)象的創(chuàng)建
4)改進(jìn)后的好處:代碼更加容易管理了,代碼的創(chuàng)建要簡潔很多。
5)改進(jìn)后的壞處:那就是你需要單獨(dú)加一個(gè)工廠對(duì)象來負(fù)責(zé)創(chuàng)建,多需要寫點(diǎn)代碼。
2.一個(gè)實(shí)際的例子
創(chuàng)建寶馬汽車與奔馳汽車的例子
1)先提取出一個(gè)汽車的公用接口Car
public interface Car{
/**行駛*/
public void drive();
}
2)寶馬和奔馳汽車對(duì)象
public class BMWCar implements Car {
/**
* 汽車發(fā)動(dòng)
*/
public void drive(){
System.out.println("BMW Car drive");
}
}
public class BengCar implements Car {
/**
* 汽車發(fā)動(dòng)
*/
public void drive(){
System.out.println("BengChi Care drive");
}
}
3)單獨(dú)一個(gè)汽車工廠來負(fù)責(zé)創(chuàng)建
public class FactoryCar {
/**
* 制造汽車
*
* @param company 汽車公司
* @return 汽車
* @throws CreateCarException 制造汽車失敗異常
*/
public static Car createCar(Company company)throws CreateCarException{
if(company==Company.BMW){
return new BMWCar();
}else if(company==Company.Beng){
return new BengCar();
}
return null;
}
}
4)最后的代碼實(shí)現(xiàn):
Car BMWCar=FactoryCar.createCar(Company.BMW);
BMWCar.drive();
1. 我說下我對(duì)設(shè)計(jì)模式的理解:任何一樣事物都是因?yàn)橛行枨蟮尿?qū)動(dòng)才誕生的,所以設(shè)計(jì)模式也不例外,我們平時(shí)在編寫代碼的時(shí)候,隨著時(shí)間的深入,發(fā)現(xiàn)很多代碼很難維護(hù),可擴(kuò)展性級(jí)差,以及代碼的效率也比較低,這個(gè)時(shí)候你肯定會(huì)想辦法讓代碼變的優(yōu)美又能解決你項(xiàng)目中的問題,所以在面向?qū)ο笳Z言里,你肯定會(huì)去發(fā)現(xiàn)很多可以重用的公用的方法,比如:接口的存在,你自然就想到了,讓你定義的方法與你的實(shí)現(xiàn)分開,也可以很方便把不同的類與接口匹配起來,形成了一個(gè)公用的接口,你會(huì)發(fā)現(xiàn)這樣做,好處會(huì)是非常多的,解決了你平時(shí)想把代碼的申明與邏輯實(shí)現(xiàn)的分開。
2. 這個(gè)時(shí)候,你發(fā)現(xiàn)了,本身面向?qū)ο蟮恼Z言里,已經(jīng)暗藏了很多好處,你肯定會(huì)仔細(xì)去分析面向?qū)ο筮@個(gè)語言,認(rèn)真去挖掘里面更多的奧秘,最后,你發(fā)現(xiàn)了,原來你可以把面向?qū)ο蟮奶匦蕴崛〕梢粋€(gè)公用的實(shí)現(xiàn)案例,這些案例里能幫助你解決你平時(shí)編寫代碼的困擾,而這樣一群人,就是所謂gof的成員,他們從平時(shí)設(shè)計(jì)建筑方面找到了靈感,建筑的設(shè)計(jì)也可以公用化以及重用化,所以他們也提取了相關(guān)的軟件設(shè)計(jì)方面的公用案例,也就有了下面的相關(guān)的所謂23種設(shè)計(jì)模式,而里面這么多模式,你也可以把他們歸類起來,最后發(fā)現(xiàn)就幾類模式:創(chuàng)建,結(jié)構(gòu),行為等模式類別,而這些現(xiàn)成的方案,也可以在實(shí)際應(yīng)用中充分發(fā)揮作用,隨著大家的使用以及理解,發(fā)現(xiàn)其實(shí)這些所謂的模式里,你的確可以讓你的代碼變的更加優(yōu)美與簡練。
3. 我比較喜歡把代碼變的更加優(yōu)美與簡練,優(yōu)美的代碼就是一看就懂,結(jié)構(gòu)很清晰,而簡歷就是一目了然,又可以解決你的問題,就是代碼又少效率又高,所以平時(shí)要養(yǎng)成寫java doc的習(xí)慣,這樣的代碼才為清晰,所以才會(huì)更加優(yōu)美。
4. 這些就是我對(duì)設(shè)計(jì)模式的理解,所以這么好的寶貝,我們不去深入的了解,的確可惜了,這就叫站到巨人的肩膀上.....
一:網(wǎng)絡(luò)配置
1.關(guān)掉防火墻
1) 重啟后生效
開啟: chkconfig iptables on
關(guān)閉: chkconfig iptables off
2) 即時(shí)生效,重啟后失效
開啟: service iptables start
關(guān)閉: service iptables stop
2.下載軟件
wget curl
3.安裝和解壓
安裝 rpm -ivh
升級(jí) rpm -Uvh
卸載 rpm -e
tar -zxvf
二:網(wǎng)卡設(shè)置
1、 設(shè)置ip地址(即時(shí)生效,重啟失效)
#ifconfig eth0 ip地址 netmask 子網(wǎng)掩碼
2、 設(shè)置ip地址(重啟生效,永久生效)
#setup
3、 通過配置文件設(shè)置ip地址(重啟生效,永久生效)
#vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0 #設(shè)備名,與文件同名。
ONBOOT=yes #在系統(tǒng)啟動(dòng)時(shí),啟動(dòng)本設(shè)備。
BOOTPROTO=static
IPADDR=202.118.75.91 #此網(wǎng)卡的IP地址
NETMASK=255.255.255.0 #子網(wǎng)掩碼
GATEWAY=202.118.75.1 #網(wǎng)關(guān)IP
MACADDR=00:02:2D:2E:8C:A8 #mac地址
4、 重啟網(wǎng)絡(luò)服務(wù)
#service network restart //重啟所有網(wǎng)卡
5、 禁用網(wǎng)卡,啟動(dòng)網(wǎng)卡
#ifdown eth0
#ifup eth0
6、 屏蔽網(wǎng)卡,顯示網(wǎng)卡
#ifconfig eth0 down
#ifconfig eth0 up
7、 配置DNS客戶端(最多三個(gè))
#vi /etc/resolv.conf
nameserver 202.99.96.68
8、更改主機(jī)名(即時(shí)生效)
#hostname 主機(jī)名
9、更改主機(jī)名(重啟計(jì)算機(jī)生效,永久生效)
#vi /etc/sysconfig/network
HOSTNAME=主機(jī)名
三:兩臺(tái)linux拷貝命令:scp
1.安裝scp:yum install openssh-clients
2.scp -r 本地用戶名@IP地址:文件名1 遠(yuǎn)程用戶名@IP地址:文件名2
摘要: 作者:NetSeek http://www.linuxtone.org (IT運(yùn)維專家網(wǎng)|集群架構(gòu)|性能調(diào)優(yōu))歡迎轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必以超鏈接形式標(biāo)明文章原始出處和作者信息及本聲明.首發(fā)時(shí)間: 2008-11-25 更新時(shí)間:2009-1-14目 錄一、 Nginx 基礎(chǔ)知識(shí)二、 Nginx 安裝及調(diào)試三、 Nginx Rewrite四、 Nginx Redirect五、 Nginx 目錄自動(dòng)加斜線...
閱讀全文
一:quartz簡介 OpenSymphony 的Quartz提供了一個(gè)比較完美的任務(wù)調(diào)度解決方案。 Quartz 是個(gè)開源的作業(yè)調(diào)度框架,定時(shí)調(diào)度器,為在 Java 應(yīng)用程序中進(jìn)行作業(yè)調(diào)度提供了簡單卻強(qiáng)大的機(jī)制。
Quartz中有兩個(gè)基本概念:作業(yè)和觸發(fā)器。作業(yè)是能夠調(diào)度的可執(zhí)行任務(wù),觸發(fā)器提供了對(duì)作業(yè)的調(diào)度
二:quartz spring配置詳解- 為什么不適用java.util.Timer結(jié)合java.util.TimerTask
1.主要的原因,適用不方便,特別是制定具體的年月日時(shí)分的時(shí)間,而quartz使用類似linux上的cron配置,很方便的配置每隔時(shí)間執(zhí)行觸發(fā)。
2.其次性能的原因,使用jdk自帶的Timer不具備多線程,而quartz采用線程池,性能上比timer高出很多。
在spring里主要分為兩種使用方式:第一種,也是目前使用最多的方式,spring提供的MethodInvokingJobDetailFactoryBean代理類,通過雷利類直接調(diào)用任務(wù)類的某個(gè)函數(shù);第二種,程序里實(shí)現(xiàn)quartz接口,quartz通過該接口進(jìn)行調(diào)度。
主要講解通過spring提供的代理類MethodInvokingJobDetailFactoryBean 1.業(yè)務(wù)邏輯類:業(yè)務(wù)邏輯是獨(dú)立的,本身就與quartz解耦的,并沒有深入進(jìn)去,這對(duì)業(yè)務(wù)來講是很好的一個(gè)方式。
public class TestJobTask{ /**
*業(yè)務(wù)邏輯處理
*/ public void service(){
/**業(yè)務(wù)邏輯*/ 


..
}
}
2.增加一個(gè)線程池 <!-- 線程執(zhí)行器配置,用于任務(wù)注冊 --><bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="500" />
</bean>
3.定義業(yè)務(wù)邏輯類
<!-- 業(yè)務(wù)對(duì)象 --><bean id="testJobTask" class="com.mike.scheduling.TestJobTask" />
4.增加quartz調(diào)用業(yè)務(wù)邏輯
<!-- 調(diào)度業(yè)務(wù) --><bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="testJobTask" />
<property name="targetMethod" value="service" />
</bean>
5.增加調(diào)用的觸發(fā)器,觸發(fā)的時(shí)間,有兩種方式:
第一種觸發(fā)時(shí)間,采用類似linux的cron,配置時(shí)間的表示發(fā)出豐富 <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="jobDetail" />
<property name="cronExpression" value="10 0/1 * * * ?" />
</bean>
Cron表達(dá)式“10 */1 * * * ?”意為:從10秒開始,每1分鐘執(zhí)行一次 第二種,采用比較簡話的方式,申明延遲時(shí)間和間隔時(shí)間
<bean id="taskTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="jobDetail" />
<property name="startDelay" value="10000" />
<property name="repeatInterval" value="60000" />
</bean>
延遲10秒啟動(dòng),然后每隔1分鐘執(zhí)行一次 6.開始調(diào)用
<!-- 設(shè)置調(diào)度 --><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
<property name="taskExecutor" ref="executor" />
</bean>
7.結(jié)束:啟動(dòng)容器即可,已經(jīng)將spring和quartz結(jié)合完畢。 Cron常用的表達(dá)式 "0 0 12 * * ?" 每天中午12點(diǎn)觸發(fā)"0 15 10 ? * *" 每天上午10:15觸發(fā)
"0 15 10 * * ?" 每天上午10:15觸發(fā)
"0 15 10 * * ? *" 每天上午10:15觸發(fā)
"0 15 10 * * ? 2005" 2005年的每天上午10:15觸發(fā)
"0 * 14 * * ?" 在每天下午2點(diǎn)到下午2:59期間的每1分鐘觸發(fā)
"0 0/5 14 * * ?" 在每天下午2點(diǎn)到下午2:55期間的每5分鐘觸發(fā)
"0 0/5 14,18 * * ?" 在每天下午2點(diǎn)到2:55期間和下午6點(diǎn)到6:55期間的每5分鐘觸發(fā)
"0 0-5 14 * * ?" 在每天下午2點(diǎn)到下午2:05期間的每1分鐘觸發(fā)
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44觸發(fā)
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15觸發(fā)
"0 15 10 15 * ?" 每月15日上午10:15觸發(fā)
"0 15 10 L * ?" 每月最后一日的上午10:15觸發(fā)
"0 15 10 ? * 6L" 每月的最后一個(gè)星期五上午10:15觸發(fā)
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一個(gè)星期五上午10:15觸發(fā)
"0 15 10 ? * 6#3" 每月的第三個(gè)星期五上午10:15觸發(fā)
三:quartz原理
根據(jù)上面spring的配置,我們就比較清楚quartz的內(nèi)部情況,下面我們主要詳解配置涉及到的每個(gè)點(diǎn) 1.我們先從最后一個(gè)步驟看起,
SchedulerFactoryBean ,scheduler的工廠實(shí)現(xiàn),里面可以生產(chǎn)出對(duì)應(yīng)的多個(gè)jobDetail和trigger,每個(gè)jobDetail對(duì)應(yīng)trigger代表一個(gè)任務(wù)
Quartz的SchedulerFactory是標(biāo)準(zhǔn)的工廠類,不太適合在Spring環(huán)境下使用。此外,為了保證Scheduler能夠感知 Spring容器的生命周期,完成自動(dòng)啟動(dòng)和關(guān)閉的操作,必須讓Scheduler和Spring容器的生命周期相關(guān)聯(lián)。以便在Spring容器啟動(dòng)后, Scheduler自動(dòng)開始工作,而在Spring容器關(guān)閉前,自動(dòng)關(guān)閉Scheduler。為此,Spring提供 SchedulerFactoryBean,這個(gè)FactoryBean大致?lián)碛幸韵碌墓δ埽?nbsp; 1)以更具Bean風(fēng)格的方式為Scheduler提供配置信息;
2)讓Scheduler和Spring容器的生命周期建立關(guān)聯(lián),相生相息;
3)通過屬性配置部分或全部代替Quartz自身的配置文件。
2.jobDetail,表示一個(gè)可執(zhí)行的業(yè)務(wù)調(diào)用
3.trigger:調(diào)度的時(shí)間計(jì)劃,什么時(shí)候,每隔多少時(shí)間可執(zhí)行等時(shí)間計(jì)劃
4.ThreadPoolTaskExecutor,線程池,用來并行執(zhí)行每個(gè)對(duì)應(yīng)的job,提高效率,這也是上面提到不推薦使用jdk自身timer的一個(gè)很重要的原因