设计模式-单例模式
常见设计模式分三大类:
- 创建模式:
工厂方法, 抽象工厂, 建造模式, 原型模式, 单例模式5种. - 结构模式:
适配器模式, 桥梁模式, 代理模式, 装饰模式, 门面模式5种. - 行为模式:
模板模式, 迭代器模式, 观察者模式, 状态模式, 策略模式5种.
单例模式
应用场景: 实际应用场景读取配置属性,单例模式保持虚拟机中只有一个实例.不是什么场景都适合使用单例模式的,保存配置文件信息算是典型的一个了.
特点:
- 只有一个实例;
- 自己创建实例;
- 必须给其他对象提供这一实例.
懒汉式(用的时候才实例化)
示例一:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class Singleton {
/**
* 构造函数私有,避免外部实例化
*/
private Singleton(){}
/**
* 声明实例
*/
private static Singleton singleton = null;
/**
* 实例化, 线程不安全
* @return
*/
public static Singleton getInstance(){
if (null == singleton)
singleton = new Singleton();
return singleton;
}
}
改进一:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class Singleton {
/**
* 构造函数私有,避免外部实例化
*/
private Singleton(){}
/**
* 声明实例
*/
private static Singleton singleton = null;
/**
* 实例化, 改进一. 效率低
* @return
*/
public static synchronized Singleton getInstance(){
if (null == singleton)
singleton = new Singleton();
return singleton;
}
}
改进二:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class Singleton {
/**
* 构造函数私有,避免外部实例化
*/
private Singleton() {
}
/**
* 声明实例
*/
private static Singleton singleton = null;
/**
* 实例化, 改进二. 双重检查锁定
*
* @return
*/
public static synchronized Singleton getInstance() {
if (null == singleton) {
synchronized (Singleton.class) {
if (null == singleton)
singleton = new Singleton();
}
}
return singleton;
}
}
该进三:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class Singleton {
/**
* 构造函数私有,避免外部实例化
*/
private Singleton() {
}
/**
* 私有静态内部类构建实例,在使用的时候才会加载次类
*/
private static class LazyLoad {
private static final Singleton singleton = new Singleton();
}
/**
* 实例化, 改进三. 静态内部类
*
* @return
*/
public static final Singleton getInstance() {
return LazyLoad.singleton;
}
}
懒汉式(用不用都会实例化)
示例一:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package comdata.synch.model;
/**
* Created by xiehui1956(@)gmail.com on 16-12-8.
*/
public class Singleton {
/**
* 构造函数私有,避免外部实例化
*/
private Singleton() {
}
/**
* 实例化
*/
private static final Singleton singleton = new Singleton();
/**
* 对外入口
*
* @return
*/
public static Singleton getInstance() {
return singleton;
}
}
测试:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44package comdata.synch;
import comdata.synch.model.Singleton;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by xiehui1956(@)gmail.com on 16-12-7.
*/
public class AppTest {
private Logger LOGGER = LoggerFactory.getLogger(AppTest.class);
@Test
public void testSingleton() {
for (int i = 0; i < 20; i++) {
new Thread(new Runnable() {
@Override
public void run() {
LOGGER.info(Singleton.getInstance().toString());
}
}).start();
}
}
}
------------------------------------
16:17:02.219 [Thread-0] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.220 [Thread-6] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.220 [Thread-5] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.220 [Thread-2] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.219 [Thread-1] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.220 [Thread-3] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.219 [Thread-4] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.220 [Thread-8] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.224 [Thread-16] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.220 [Thread-7] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.221 [Thread-9] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.225 [Thread-17] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.221 [Thread-11] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
16:17:02.221 [Thread-10] INFO comdata.synch.AppTest - comdata.synch.model.Singleton@51bf2a83
应用实例-读取properties配置
PropertiesUtils.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41package comdata.synch.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
* Created by xiehui1956(@)gmail.com on 16-11-8.
*/
public class PropertiesUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesUtils.class);
public static Properties loadProperties(String path) {
Properties properties = new Properties();
InputStream inputStream = null;
try {
inputStream = new FileInputStream(path);
} catch (FileNotFoundException e) {
LOGGER.error("读取配置时出错了,请注意配置路径config. 报错信息L{}", e.getStackTrace());
}
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (null != inputStream)
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return properties;
}
}PropertiesConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package comdata.synch.util;
/**
* Created by xiehui1956(@)gmail.com on 16-11-1.
*/
public class PropertiesConfig {
/**
* cassandra
*/
public static final String JDBC_CASSANDRA = "jdbc.cassandra.properties";
/**
* 应用信息配置
*/
public static final String APP = "app.properties";
/**
* 数据库配置信息
*/
public static final String JDBC = "jdbc.properties";
/**
* 获取配置文件路径
*
* @param fileName
* @return
*/
public static final String getConfigPath(String fileName) {
return System.getProperty("config") + fileName;
}
}WebAppConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71package comdata.synch;
import comdata.synch.util.PropertiesConfig;
import comdata.synch.util.PropertiesUtils;
import java.util.Properties;
/**
* Created by xiehui1956(@)gmail.com on 16-11-8.
* properties属性映射类
*/
public final class WebAppConfig {
private WebAppConfig() {
System.setProperty("config", "/home/bls/workspace/work/project/data-sync/config/");
Properties properties = PropertiesUtils.loadProperties(PropertiesConfig.getConfigPath(PropertiesConfig.APP));
canalListenerIp = properties.getProperty("canal.listener.ip");
canalListenerPort = Integer.parseInt(properties.getProperty("canal.listener.port"));
canalListenerName = properties.getProperty("canal.listener.name");
}
private static class LazyLoad {
private static final WebAppConfig appConfig = new WebAppConfig();
}
public static WebAppConfig getInstance() {
return LazyLoad.appConfig;
}
/**
* canal监听ipl
*/
private String canalListenerIp;
/**
* canal监听port
*/
private int canalListenerPort;
/**
* canal监听服务名
*/
private String canalListenerName;
public String getCanalListenerIp() {
return canalListenerIp;
}
public void setCanalListenerIp(String canalListenerIp) {
this.canalListenerIp = canalListenerIp;
}
public int getCanalListenerPort() {
return canalListenerPort;
}
public void setCanalListenerPort(int canalListenerPort) {
this.canalListenerPort = canalListenerPort;
}
public String getCanalListenerName() {
return canalListenerName;
}
public void setCanalListenerName(String canalListenerName) {
this.canalListenerName = canalListenerName;
}
}
-----------------------------------
输出结果: 16:37:17.194 [main] INFO com.data.synch.AppTest - 127.0.0.1
后来properties配置文件变多了,更新调整了以下类
WebAppConfig.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174package comdata.synch;
import comdata.synch.util.PropertiesConfig;
import comdata.synch.util.PropertiesUtils;
import java.util.Properties;
/**
* Created by xiehui1956(@)gmail.com on 16-11-8.
* properties属性映射类
*/
public final class WebAppConfig {
private WebAppConfig() {
setApp(new App());
setSetup(new Setup());
}
private static class LazyLoad {
private static final WebAppConfig appConfig = new WebAppConfig();
}
public static WebAppConfig getInstance() {
return LazyLoad.appConfig;
}
private App app;
private Setup setup;
public App getApp() {
return app;
}
public void setApp(App app) {
this.app = app;
}
public Setup getSetup() {
return setup;
}
public void setSetup(Setup setup) {
this.setup = setup;
}
/**
* 应用配置信息
*/
public final class App {
private App() {
System.setProperty("config", "/home/bls/workspace/work/redstar/project/data-sync/config/");
Properties properties = PropertiesUtils.loadProperties(PropertiesConfig.getConfigPath(PropertiesConfig.APP));
canalListenerIp = properties.getProperty("canal.listener.ip");
canalListenerPort = Integer.parseInt(properties.getProperty("canal.listener.port"));
canalListenerName = properties.getProperty("canal.listener.name");
}
/**
* canal监听ipl
*/
private String canalListenerIp;
/**
* canal监听port
*/
private int canalListenerPort;
/**
* canal监听服务名
*/
private String canalListenerName;
public String getCanalListenerIp() {
return canalListenerIp;
}
public void setCanalListenerIp(String canalListenerIp) {
this.canalListenerIp = canalListenerIp;
}
public int getCanalListenerPort() {
return canalListenerPort;
}
public void setCanalListenerPort(int canalListenerPort) {
this.canalListenerPort = canalListenerPort;
}
public String getCanalListenerName() {
return canalListenerName;
}
public void setCanalListenerName(String canalListenerName) {
this.canalListenerName = canalListenerName;
}
}
/**
* 启动信息
*/
public final class Setup {
private Setup() {
System.setProperty("config", "/home/bls/workspace/work/redstar/project/data-sync/config/");
Properties properties = PropertiesUtils.loadProperties(PropertiesConfig.getConfigPath(PropertiesConfig.APP));
servicePort = Integer.parseInt(properties.getProperty("service.port"));
redisMaxWaitMillis = Integer.parseInt(properties.getProperty("redis.MaxWaitMillis"));
redisTimeout = Integer.parseInt(properties.getProperty("redis.timeout"));
redisConfigServerUrl = properties.getProperty("redis.config.server.url");
redisConfigServerPort = Integer.parseInt(properties.getProperty("redis.config.server.port"));
redisClusterInfo = properties.getProperty("redis.cluster.info");
}
private int servicePort;
private long redisMaxWaitMillis;
private int redisTimeout;
private String redisConfigServerUrl;
private int redisConfigServerPort;
//info realtime info
private String redisClusterInfo;
public int getServicePort() {
return servicePort;
}
public void setServicePort(int servicePort) {
this.servicePort = servicePort;
}
public long getRedisMaxWaitMillis() {
return redisMaxWaitMillis;
}
public void setRedisMaxWaitMillis(long redisMaxWaitMillis) {
this.redisMaxWaitMillis = redisMaxWaitMillis;
}
public int getRedisTimeout() {
return redisTimeout;
}
public void setRedisTimeout(int redisTimeout) {
this.redisTimeout = redisTimeout;
}
public String getRedisConfigServerUrl() {
return redisConfigServerUrl;
}
public void setRedisConfigServerUrl(String redisConfigServerUrl) {
this.redisConfigServerUrl = redisConfigServerUrl;
}
public int getRedisConfigServerPort() {
return redisConfigServerPort;
}
public void setRedisConfigServerPort(int redisConfigServerPort) {
this.redisConfigServerPort = redisConfigServerPort;
}
public String getRedisClusterInfo() {
return redisClusterInfo;
}
public void setRedisClusterInfo(String redisClusterInfo) {
this.redisClusterInfo = redisClusterInfo;
}
}
}AppTest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package comdata.synch;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created by xiehui1956(@)gmail.com on 16-12-7.
*/
public class AppTest {
private Logger LOGGER = LoggerFactory.getLogger(AppTest.class);
@Test
public void testSingleton() {
WebAppConfig appConfig = WebAppConfig.getInstance();
LOGGER.info(appConfig.getApp().getCanalListenerIp());
}
}
说明:
- System.setProperty这里设置的系统启动参数,其实是没必要都在这里设置.我在这里设置时为了方便看.正真用的时候是设置在jvm启动参数中设置一个就行了.这个自定义参数的设置是在PropertiesConfig.getConfigPath方法中使用的.
- 见过其他人封装的PropertiesUtils工具类,建议这里类中读取配置的方法如果抛异常直接在这个类中处理就行了.没必要再向上抛了,因为属性的操作类就是这里出异常了应该在这里做统一处理.
- WebAppConfig中封装的内部类建议这么用,因为这样既可以统一管理配置信息又方便做细节区分.即使再多的配置也不会手忙脚乱,其实我要读取的配置更多,这里就列出来两个.
以上.