2018/1/8
一些常用的底层操作,比如数据库连接,获取数据库配置文件的操作等等,我们可以将这些操作提取到一个工具类(ConfigManager.java),并把它设计为单利模式。(23种设计模式之一,最常用的设计模式)在系统运行期间,有且只有一个实例,满足三个关键点:
【1】一个类只有一个实例。因此,只能提供私有的构造器,即保证不能随便创建该类实例。
package com.single;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigManager {
private static Properties properties;
//private constructor
private ConfigManager(){
String configFile = "database.properties";
properties = new Properties();
InputStream is = ConfigManager.class.getClassLoader().getSystemResourceAsStream(configFile);
try {
properties.load(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
【2】它必须自行创建这个实例。如下红色字体,定义了静态私有对象ConfigManager:
package com.single;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigManager {
private static ConfigManager configManager;
private static Properties properties;
//private constructor
private ConfigManager(){
String configFile = "database.properties";
properties = new Properties();
InputStream is = ConfigManager.class.getClassLoader().getSystemResourceAsStream(configFile);
try {
properties.load(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
外界需要获取并使用这个单例类的实例,但由于这个类的构造器是私有,外界不能new一个,那么必须提供一个静态的共有方法,该方法创建或获取它本身的静态私有对象并返回。
package com.single;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigManager {
private static ConfigManager configManager;
private static Properties properties;
//private constructor
private ConfigManager(){
String configFile = "database.properties";
properties = new Properties();
InputStream is = ConfigManager.class.getClassLoader().getSystemResourceAsStream(configFile);
try {
properties.load(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
}
//全局访问点
public static ConfigManager getInstance(){
if(configManager == null){
configManager = new ConfigManager();
}
return configManager;
}
}
目标:1. 读取 database.properties;2. 获取数据源的配置值(url、driver、password、username);3. CRUD等等JDBC相关的操作。
【1】修改ConfigManager.java 文件:
package com.single;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigManager {
private static ConfigManager configManager;
private static Properties properties;
//private constructor
private ConfigManager(){
String configFile = "database.properties";
properties = new Properties();
InputStream is = ConfigManager.class.getClassLoader().getSystemResourceAsStream(configFile);
try {
properties.load(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
}
//全局访问点
public static ConfigManager getInstance(){
if(configManager == null){
configManager = new ConfigManager();
}
return configManager;
}
public String getValue(String key){
//API
return properties.getProperty(key);
}
}
【2】新建一个BaseDao类:
package com.single;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
public class BaseDao {
public static Connection getConnection(){
Connection connection = null;
String driver = ConfigManager.getInstance().getValue("driver");
String url = ConfigManager.getInstance().getValue("url");
String username = ConfigManager.getInstance().getValue("username");
String password = ConfigManager.getInstance().getValue("password");
try{
Class.forName(driver);
connection = DriverManager.getConnection(url,username,password);
}catch(Exception e){
e.getMessage();
}
return connection;
}
//CRUD 不作补充了
}
解释:(1)上面是最简单的单例模式了;
(2)BaseDao 设计为静态而非单例,因为每个线程都需要单独的Connection。
(3)弊端严重:线程不安全,会出现多个ConfigManager实例。
解决问题需要先了解单例模式的两种实现方法:懒汉和饿汉模式。
而上例就是采用了懒汉模式--在类加载时没有初始化,需要时调用了getInstance()方法,获取ConfigManager实例。虽保持了延迟加载,但无法在多线程下正常工作。现作以下修改:最简单的就是考虑同步,采用同步synchronize关键字实现。
【1】修改ConfigManager.java 文件的全局访问点:
//全局访问点
public static synchronized ConfigManager getInstance(){
if(configManager == null){
configManager = new ConfigManager();
}
return configManager;
}
(2)遗憾,该方式效率不高,99%的情况下是不需要同步的。
(3)so,推荐饿汉模式。
饿汉模式即是:在类加载的时候,就完成了初始化操作,故类加载较慢,但是获取对象的速度很快。并且由于饿汉模式在类初始化时就已经自行实例化,因此肯定不存在线程安全问题。
【1】修改ConfigManager.java 文件:
package com.hungry;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigManager {
private static ConfigManager configManager = new ConfigManager();
private static Properties properties;
//private constructor
private ConfigManager(){
String configFile = "database.properties";
properties = new Properties();
InputStream is = ConfigManager.class.getClassLoader().getSystemResourceAsStream(configFile);
try {
properties.load(is);
is.close();
}catch(IOException e){
e.printStackTrace();
}
}
//饿汉模式的全局访问点
public static ConfigManager getInstance(){
return configManager;
}
public String getValue(String key){
//API
return properties.getProperty(key);
}
}
综上,我们希望是饿汉模式+延迟加载特性(lazy loading);
package com.InnerClass;
public class Singleton {
private static Singleton singleton;
private Singleton(){
//可以添加业务代码--整个系统运行只会执行一次的业务代码操作
}
//Inner class
public static class SingletonHelper{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
singleton = SingletonHelper.INSTANCE;
return singleton;
}
public static Singleton test(){
return singleton;
}
}
package com.InnerClass;
import org.apache.log4j.Logger;
import org.junit.Test;
public class SingletonTest {
private Logger log = Logger.getLogger(SingletonTest.class.getName());
@Test
public void test() {
log.info("Singleton.test()--->"+Singleton.test());
log.info("Singleton.getInstance()--->"+Singleton.getInstance());
}
}
2018-01-08 19:10:45,667 [com.InnerClass.SingletonTest]-[INFO] Singleton.test()--->null
2018-01-08 19:10:45,729 [com.InnerClass.SingletonTest]-[INFO] Singleton.getInstance()--->com.InnerClass.Singleton@6f75e721
调用了该方法才能获取得了实例;延迟效果达到!!
(2)同时也满足了饿汉模式,在类加载时就已经完成了初始化!!内部类,静态!!
public static class SingletonHelper{
private static final Singleton INSTANCE = new Singleton();
}
以上是该博文全部内容。