简单工厂 jdk源码解析
生活随笔
收集整理的這篇文章主要介紹了
简单工厂 jdk源码解析
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
我們看一下簡(jiǎn)單工廠在JDK源碼的一些體現(xiàn),我們看一個(gè)比較熟悉的類,Calendar這么一個(gè)類,我們找一個(gè)getInstance這么一個(gè)方法,public static Calendar getInstance(){return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));}我們看一下這個(gè)方法,createCalendar后面?zhèn)鱽?lái)一些參數(shù),而這個(gè)是一個(gè)靜態(tài)方法,我們進(jìn)來(lái)private static Calendar createCalendar(TimeZone zone,Locale aLocale){CalendarProvider provider =LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider();if (provider != null) {try {return provider.getInstance(zone, aLocale);} catch (IllegalArgumentException iae) {// fall back to the default instantiation}}Calendar cal = null;if (aLocale.hasExtensions()) {String caltype = aLocale.getUnicodeLocaleType("ca");if (caltype != null) {switch (caltype) {case "buddhist":cal = new BuddhistCalendar(zone, aLocale);break;case "japanese":cal = new JapaneseImperialCalendar(zone, aLocale);break;case "gregory":cal = new GregorianCalendar(zone, aLocale);break;}}}if (cal == null) {// If no known calendar type is explicitly specified,// perform the traditional way to create a Calendar:// create a BuddhistCalendar for th_TH locale,// a JapaneseImperialCalendar for ja_JP_JP locale, or// a GregorianCalendar for any other locales.// NOTE: The language, country and variant strings are interned.if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {cal = new BuddhistCalendar(zone, aLocale);} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"&& aLocale.getCountry() == "JP") {cal = new JapaneseImperialCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}}return cal;}現(xiàn)在這個(gè)方法是private static方法,我們看一下他的具體實(shí)現(xiàn),這里面有一個(gè)if判斷,語(yǔ)言國(guó)家if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {cal = new BuddhistCalendar(zone, aLocale);} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"&& aLocale.getCountry() == "JP") {cal = new JapaneseImperialCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}else就會(huì)返回另外一種實(shí)現(xiàn),下面又返回日本的一個(gè)實(shí)現(xiàn),所以我們看一下這里面的代碼,我們?cè)诳匆幌耉ideoFactory原來(lái)的一個(gè)寫法,那我們會(huì)發(fā)現(xiàn)這兩個(gè)方法是異曲同工的,都是進(jìn)行簡(jiǎn)單的if判斷,然后把對(duì)應(yīng)的子類實(shí)現(xiàn),Calendar也是這么做的,只不過(guò)他這里是使用了static方法,他這里并不是考慮Calendar的擴(kuò)展性,因?yàn)楝F(xiàn)在應(yīng)該是滿足的,非常簡(jiǎn)單這個(gè)源碼,我們看一下這個(gè)類相關(guān)的一個(gè)類圖,我們看一下具體的實(shí)現(xiàn),現(xiàn)在Calendar可以看出來(lái),他實(shí)現(xiàn)了三個(gè)接口,序列號(hào)接口,比較還有克隆,下面就是繼承Calendar類的一個(gè)子類,Calendar是一個(gè)抽象類
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {是abstract,抽象類會(huì)是這樣的一個(gè)C,頭標(biāo)后面是一個(gè)權(quán)限符,鎖打開(kāi)就是public,點(diǎn)就是默認(rèn)的default,通過(guò)這種方式學(xué)習(xí)JDK源碼,是非常有效果的,包括我們?nèi)W(xué)習(xí)Spring的一些開(kāi)源框架,通過(guò)UML先對(duì)整體有一個(gè)認(rèn)識(shí),這樣有助于我們對(duì)源碼和框架結(jié)構(gòu)關(guān)系的全局的理解,這里面我們?cè)贁U(kuò)展一個(gè),我們?cè)趯慗DBC的時(shí)候,JDK來(lái)實(shí)現(xiàn)的時(shí)候,Class.forName("com.mysql.jdbc.Driver");通過(guò)Class.forName把mysql的驅(qū)動(dòng)加載進(jìn)來(lái),那如果寫ORACLE的驅(qū)動(dòng)呢,這里就變成對(duì)應(yīng)的ORACLE的JDBC的jar包,ORACLE的driver類,然后調(diào)用DriverManager的getConnection方法,@CallerSensitivepublic static Connection getConnection(String url)throws SQLException {java.util.Properties info = new java.util.Properties();return (getConnection(url, info, Reflection.getCallerClass()));}獲取對(duì)應(yīng)的數(shù)據(jù)庫(kù)連接,JDBC的過(guò)程也是非常簡(jiǎn)單的,// Worker method called by the public getConnection() methods.private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {/** When callerCl is null, we should check the application's* (which is invoking this class indirectly)* classloader, so that the JDBC driver class outside rt.jar* can be loaded from here.*/ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;synchronized(DriverManager.class) {// synchronize loading of the correct classloader.if (callerCL == null) {callerCL = Thread.currentThread().getContextClassLoader();}}if(url == null) {throw new SQLException("The url cannot be null", "08001");}println("DriverManager.getConnection(\"" + url + "\")");// Walk through the loaded registeredDrivers attempting to make a connection.// Remember the first exception that gets raised so we can reraise it.SQLException reason = null;for(DriverInfo aDriver : registeredDrivers) {// If the caller does not have permission to load the driver then// skip it.if(isDriverAllowed(aDriver.driver, callerCL)) {try {println(" trying " + aDriver.driver.getClass().getName());Connection con = aDriver.driver.connect(url, info);if (con != null) {// Success!println("getConnection returning " + aDriver.driver.getClass().getName());return (con);}} catch (SQLException ex) {if (reason == null) {reason = ex;}}} else {println(" skipping: " + aDriver.getClass().getName());}}// if we got here nobody could connect.if (reason != null) {println("getConnection failed: " + reason);throw reason;}println("getConnection: no suitable driver found for "+ url);throw new SQLException("No suitable driver found for "+ url, "08001");}建議大家看一下這個(gè)源碼,通過(guò)Class.forName這種方式,直接通過(guò)反射拿到對(duì)應(yīng)的Video,只不過(guò)MSYQL這里面還是需要通過(guò)注冊(cè)的,for(DriverInfo aDriver : registeredDrivers) {// If the caller does not have permission to load the driver then// skip it.if(isDriverAllowed(aDriver.driver, callerCL)) {try {println(" trying " + aDriver.driver.getClass().getName());Connection con = aDriver.driver.connect(url, info);if (con != null) {// Success!println("getConnection returning " + aDriver.driver.getClass().getName());return (con);}} catch (SQLException ex) {if (reason == null) {reason = ex;}}} else {println(" skipping: " + aDriver.getClass().getName());}}因?yàn)檫@個(gè)可以看出來(lái)它是一個(gè)for循環(huán),在遍歷注冊(cè)的一個(gè)驅(qū)動(dòng),private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();并且它是CopyOnWriteArrayList,里面是DriverInfo,初始化的時(shí)候他是一個(gè)空的,具體是什么時(shí)候完成注冊(cè)的呢,我們把mysql的驅(qū)動(dòng)增加進(jìn)來(lái),<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version>
</dependency>我們就用5.1.6這個(gè)版本,我們就看一下com.mysql.jdbc.Driver這么一個(gè)類一旦我們調(diào)用Class.forName,開(kāi)始執(zhí)行靜態(tài)的DriverManager.registeredDriverstatic { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); }
} 這個(gè)時(shí)候就會(huì)在registerDriver(new Driver())這個(gè)方法里面直接注冊(cè)這個(gè)Driver,那里面的Driver自然就是MySQL的Driver,public static synchronized void registerDriver(java.sql.Driver driver,DriverAction da)throws SQLException {/* Register the driver if it has not already been added to our list */if(driver != null) {registeredDrivers.addIfAbsent(new DriverInfo(driver, da));} else {// This is for compatibility with the original DriverManagerthrow new NullPointerException();}println("registerDriver: " + driver);
}如果不存在就往里放if(driver != null) {registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
}public boolean addIfAbsent(E e) 這個(gè)方法使用了重入鎖, final ReentrantLock lock = this.lock;這里面我們就不深入來(lái)講解了,我們主要還是來(lái)關(guān)注設(shè)計(jì)模式,講到這些呢,主要是分享JDK源碼中,一些相關(guān)的應(yīng)用,JDK源碼的分析就講到這里,剛剛MYSQL需要擴(kuò)展一下
我們看一下pom文件,我們把一些開(kāi)源的項(xiàng)目導(dǎo)入到我們的設(shè)計(jì)模式當(dāng)中,拿這些包主要是為了我們看源碼的時(shí)候方便一些,把版本聲明也拿過(guò)來(lái),這樣這些包就導(dǎo)入進(jìn)來(lái)了,關(guān)于logback一些簡(jiǎn)單的使用,public final class LoggerFactory public static ILoggerFactory getILoggerFactory() {}最里面有一個(gè)getLogger方法,public static Logger getLogger(Class clazz) {return getLogger(clazz.getName());
}public static Logger getLogger(String name) {ILoggerFactory iLoggerFactory = getILoggerFactory();return iLoggerFactory.getLogger(name);
}這個(gè)還有個(gè)重載,一個(gè)是String name,還有一個(gè)是Class clazz,clazz是干嘛的,是clazz.getName(),首先getLogger根據(jù)我們傳來(lái)的name,從iLoggerFactory里面getLogger,先看一下public interface ILoggerFactorypackage org.slf4j;
//抽象產(chǎn)品工廠
public interface ILoggerFactory {//抽象工廠方法public Logger getLogger(String name);
}很明顯ILoggerFactory它是一個(gè)接口,下面有一個(gè)方法,那這個(gè)呢是工廠方法,那在后面我們也會(huì)講,這里先過(guò)去,后面我們學(xué)習(xí)工廠方法的時(shí)候,再單獨(dú)來(lái)說(shuō),然后通過(guò)iLoggerFactory.getLogger,因?yàn)樗且粋€(gè)接口,肯定有多個(gè)實(shí)現(xiàn),LoggerContext//具體工廠實(shí)現(xiàn)類
public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle {
...//具體工廠方法@Overridepublic final Logger getLogger(final String name) {...}
...這里面我們看一下,傳入的一個(gè)name,這里面要返回Logger,這里面對(duì)name進(jìn)行了判斷,很明顯這個(gè)方法就是一個(gè)簡(jiǎn)單工廠方法,根據(jù)傳入的入?yún)⑦M(jìn)行選擇哪個(gè)Logger,那這個(gè)還是非常簡(jiǎn)單的,剛剛也說(shuō)了,在我們的LoggerFactory里面,既存在了工廠方法,又存在了簡(jiǎn)單工廠,所以設(shè)計(jì)模式在使用的時(shí)候,不一定要局限在使用一種,例如這里就是一個(gè)組合的使用,這個(gè)簡(jiǎn)單工廠比較簡(jiǎn)單,在很多源碼中也能夠找到他的影子,在前面的JDK,Logback開(kāi)源框架的,對(duì)于學(xué)習(xí)設(shè)計(jì)模式的講解呢,我們?cè)陂喿x源碼的時(shí)候呢,還可以以設(shè)計(jì)模式的角度,去聚焦源碼,這樣對(duì)我們理解源碼也是有益處的
?
總結(jié)
以上是生活随笔為你收集整理的简单工厂 jdk源码解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。