单例模式是一种常用的设计模式,用于确保在一个程序中一个类只有一个实例,并且提供一个全局访问点。这种模式在需要严格控制资源访问和分配的情况下非常有用。
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这个模式经常用于控制资源的访问,如数据库连接或文件系统。
单例模式通常涉及以下几个关键步骤:
在类加载时就创建实例。这种方式是线程安全的,但可能会增加内存负担,因为实例不管是否需要都会被创建。
在第一次需要实例时才创建。这种方式可以节省资源,但需要考虑多线程环境下的线程安全问题。
单例模式在Spring框架中的应用是其核心功能之一,特别体现在Spring的Bean容器管理中。在Spring框架中,单例模式的应用主要集中在以下几个方面:
Bean的默认作用域:
在Spring中,默认情况下,所有在Spring配置文件中定义的Bean都是以单例模式创建的。这意味着无论应用中有多少次对特定Bean的请求,Spring容器都会返回同一个Bean实例。
这种方式有助于节省资源,因为相同的Bean不会被多次创建。
BeanFactory和ApplicationContext:
Spring的BeanFactory和ApplicationContext提供了Bean的创建和管理机制。它们作为Bean的容器,负责实例化、配置和组装Bean。
这些容器自身也是以单例模式运行的,确保整个应用中有一个统一的Bean管理中心。
单例Bean的线程安全:
虽然单例Bean在Spring中只实例化一次,但Spring并不保证单例Bean是线程安全的。这意味着Bean的线程安全性依赖于其自身的实现。
在设计单例Bean时,需要考虑其在多线程环境下的行为,确保状态管理的正确性。
单例模式与依赖注入(DI):
Spring使用依赖注入(DI)机制来管理Bean之间的依赖关系。在单例模式下,依赖注入确保相同的Bean实例被注入到其他需要它的Bean中。
这种机制简化了对象之间的关系,并提高了代码的可测试性和可维护性。
配置与管理:
Spring的单例模式允许集中管理Bean的配置。由于每个Bean只有一个实例,因此其配置和属性只需要设置一次,而无需在每次使用时重新配置。
这对于管理大型应用中的配置和属性尤其有用,可以提高效率和一致性。
public class A {
private static A obj = new A(); // 类加载时即创建实例
private A() {} // 私有构造函数
public static A getA() {
return obj;
}
public void doSomething() {
// 方法实现
}
}
public class A {
private static A obj;
private A() {} // 私有构造函数
public static synchronized A getA() {
if (obj == null) {
obj = new A(); // 第一次调用时创建实例
}
return obj;
}
public void doSomething() {
// 方法实现
}
}
我们将通过创建一个JDBCSingleton类来展示单例设计模式的一个实际应用。这个类将被用于数据库操作,保证整个应用中只有一个数据库连接实例。
JDBCSingleton 类设计
JDBCSingleton类将包含:
JDBCSingleton
public class JDBCSingleton {
// 静态成员仅持有JDBCSingleton类的一个实例
private static JDBCSingleton jdbc;
// 私有构造器防止其他类实例化
private JDBCSingleton() { }
// 提供全局访问点
public static JDBCSingleton getInstance() {
if (jdbc == null) {
jdbc = new JDBCSingleton();
}
return jdbc;
}
// 获取连接以进行插入、查看等操作
private static Connection getConnection() throws ClassNotFoundException, SQLException {
Connection con = null;
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/ashwanirajput", "root", "ashwani");
return con;
}
// 向数据库中插入记录
public int insert(String name, String pass) throws SQLException {
Connection c = null;
PreparedStatement ps = null;
int recordCounter = 0;
try {
c = getConnection();
ps = c.prepareStatement("insert into userdata(uname, upassword) values(?, ?)");
ps.setString(1, name);
ps.setString(2, pass);
recordCounter = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
if (c != null) {
c.close();
}
}
return recordCounter;
}
// 从数据库中查看数据
public void view(String name) throws SQLException {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = this.getConnection();
ps = con.prepareStatement("select * from userdata where uname = ?");
ps.setString(1, name);
rs = ps.executeQuery();
while (rs.next()) {
System.out.println("姓名: " + rs.getString(2) + "\t" + "密码: " + rs.getString(3));
}
} catch (Exception e) {
System.out.println(e);
} finally {
if (rs != null) {
rs.close();
}
if (ps != null) {
ps.close();
}
if (con != null) {
con.close();
}
}
}
// 更新给定用户名的密码
public int update(String name, String password) throws SQLException {
Connection c = null;
PreparedStatement ps = null;
int recordCounter = 0;
try {
c = this.getConnection();
ps = c.prepareStatement("update userdata set upassword = ? where uname = '" + name + "'");
ps.setString(1, password);
recordCounter = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
if (c != null) {
c.close();
}
}
return recordCounter;
}
// 从数据库删除数据
public int delete(int userid) throws SQLException {
Connection c = null;
PreparedStatement ps = null;
int recordCounter = 0;
try {
c = getConnection();
ps = c.prepareStatement("delete from userdata where uid = '" + userid + "'");
recordCounter = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
ps.close();
}
if (c != null) {
c.close();
}
}
return recordCounter;
}
}
JDBCSingletonDemo
public class JDBCSingletonDemo {
static int count = 1;
static int choice;
public static void main(String[] args) throws IOException {
JDBCSingleton jdbc = JDBCSingleton.getInstance();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
do {
System.out.println("数据库操作");
System.out.println("---------------------");
System.out.println("1. 插入");
System.out.println("2. 查看");
System.out.println("3. 删除");
System.out.println("4. 更新");
System.out.println("5. 退出");
System.out.print("\n请输入你想在数据库中执行的操作: ");
choice = Integer.parseInt(br.readLine());
switch (choice) {
case 1: {
System.out.print("输入要插入数据库的用户名: ");
String username = br.readLine();
System.out.print("输入要插入数据库的密码: ");
String password = br.readLine();
try {
int i = jdbc.insert(username, password);
if (i > 0) {
System.out.println("第 " + (count++) + " 条数据已成功插入");
} else {
System.out.println("数据未插入");
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按回车键继续...");
System.in.read();
break;
}
case 2: {
System.out.print("输入要查看的用户名: ");
String username = br.readLine();
try {
jdbc.view(username);
} catch (SQLException e) {
System.out.println(e);
}
System.out.println("按回车键继续...");
System.in.read();
break;
}
case 3: {
System.out.print("输入要删除的用户ID: ");
int userid = Integer.parseInt(br.readLine());
try {
int i = jdbc.delete(userid);
if (i > 0) {
System.out.println("第 " + (count++) + " 条数据已成功删除");
} else {
System.out.println("数据未删除");
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按回车键继续...");
System.in.read();
break;
}
case 4: {
System.out.print("输入要更新的用户名: ");
String username = br.readLine();
System.out.print("输入新密码: ");
String password = br.readLine();
try {
int i = jdbc.update(username, password);
if (i > 0) {
System.out.println("第 " + (count++) + " 条数据已成功更新");
}
} catch (Exception e) {
System.out.println(e);
}
System.out.println("按回车键继续...");
System.in.read();
break;
}
default:
return;
}
} while (choice != 5);
}
}
这个示例展示了如何在实际应用中使用单例模式来创建和管理数据库连接。通过这种方式,可以确保应用程序中的所有组件都使用相同的数据库连接实例,从而提高了效率和一致性。同时,这也减少了数据库连接的开销,因为连接实例只被创建一次并在整个应用中复用。
23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern