针对在Singleton类中加载属性文件和对象加载的过程,属性先加载还是方法先加载这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展4.平凡之路-封装帮助类和加载属性文件、c–陷阱:静态堆栈变
针对在Singleton类中加载属性文件和对象加载的过程,属性先加载还是方法先加载这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展4.平凡之路-封装帮助类和加载属性文件、c – 陷阱:静态堆栈变量Singleton类、C++中的Singleton类的实现、Flex中的Singleton类等相关知识,希望可以帮助到你。
本文目录一览:- 在Singleton类中加载属性文件(对象加载的过程,属性先加载还是方法先加载)
- 4.平凡之路-封装帮助类和加载属性文件
- c – 陷阱:静态堆栈变量Singleton类
- C++中的Singleton类的实现
- Flex中的Singleton类
在Singleton类中加载属性文件(对象加载的过程,属性先加载还是方法先加载)
我已经看过几次,并尝试了一些建议,但都没有成功(到目前为止)。我在以下路径上有一个maven项目和属性文件:
[project]/src/main/reources/META_INF/testing.properties
我正在尝试将其加载到Singleton类中以通过键访问属性
public class TestDataProperties { private static TestDataProperties instance = null; private Properties properties; protected TestDataProperties() throws IOException{ properties = new Properties(); properties.load(getClass().getResourceAsStream("testing.properties")); } public static TestDataProperties getInstance() { if(instance == null) { try { instance = new TestDataProperties(); } catch (IOException ioe) { ioe.printStackTrace(); } } return instance; } public String getValue(String key) { return properties.getProperty(key); }}
但是我在运行时遇到了NullPointerError的问题。我已经完成了所有可以想到的操作,但是无法找到/加载文件。
有任何想法吗?
堆栈跟踪:
Exception in thread "main" java.lang.NullPointerException at java.util.Properties$LineReader.readLine(Properties.java:434) at java.util.Properties.load0(Properties.java:353) at java.util.Properties.load(Properties.java:341)
答案1
小编典典您应该实例化您的Properties
对象。另外,您还应该使用以下路径加载资源文件/META-INF
:
properties = new Properties();properties.load(getClass().getResourceAsStream("/META-INF/testing.properties"));
4.平凡之路-封装帮助类和加载属性文件
MyBatisUtils.java 文件
/**
* 知识点:
* final 修饰类 : 不能被基础
* 修饰方法 : 不能被重写
* 修改变量 : 常量
*/
public final class MyBatisUtils {
private MyBatisUtils(){}//不允许进行实例化
private static final String PATH = "mybatis-config.xml";
private static InputStream is ;
private static SqlSessionFactory sqlSessionFactory;
static{//1.静态代码块 只是加载一次
try {
is = Resources.getResourceAsStream(PATH);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException ex) {
ex.printStackTrace();
throw new RuntimeException("加载核心配置文件失败");
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
public static void closeSqlSession(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.close();
}
}
}
图解说明
加载属性文件
新建src的根目录下jdbc.properties
jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://127.0.0.1:3306/cy42_mss
jdbc.mysql.username=root
jdbc.mysql.password=shxt
修改核心配置文件
<configuration>
<!-- 加载属性文件 -->
<properties resource="jdbc.properties"/>
<!-- 配置数据库的环境 -->
<environments default="development">
<environment id="development">
<!-- 事务管理器:保证数据的完整性和一致性 -->
<!-- 框架:默认情况下CUD操作需要手动提交事务 -->
<transactionManager type="JDBC" />
<!-- 使用的是连接池:百度Java如何实行连接池的原理? -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.mysql.driver}" />
<property name="url" value="${jdbc.mysql.url}" />
<property name="username" value="${jdbc.mysql.username}" />
<property name="password" value="${jdbc.mysql.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="com/shxt/model/SkillMapper.xml"/>
</mappers>
</configuration>
通过
${KEY}
获取对应的值
c – 陷阱:静态堆栈变量Singleton类
class Logger { public: static Logger* Instance() { if (!m_pInstance) m_pInstance = new Logger; return m_pInstance; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); static Logger* m_pInstance; };
但是,有一种更简单的方法,使用引用:
class Logger { public: static Logger& Instance() { static Logger theLogger; return theLogger; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); ~Logger(); };
阅读文章C++ Singleton design pattern,它警告第二种方式:
[Potential Pitfall]: This form of the singleton can present a problem
because of the life expectancy of the object. If one singleton is
instantiated within another,one must be keenly aware of the
destructor call sequence.
但我无法理解,有人能告诉我一个不好的用法,我应该避免它吗?
解决方法
典型的单身人士
class Logger { public: static Logger* Instance() { if (!m_pInstance) m_pInstance = new Logger; return m_pInstance; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); static Logger* m_pInstance; };
此代码不是线程安全的,因此对新Logger的调用可能会多次发生(在不同的线程中).它还会泄漏Logger实例(因为它永远不会被删除),如果应该执行析构函数,这可能是一个问题.
梅耶的辛格尔顿
class Logger { public: static Logger& Instance() { static Logger theLogger; return theLogger; } private: Logger(); Logger(Logger const&); Logger& operator=(Logger const&); ~Logger(); };
Meyer’s Singleton的问题确实是由于对象的破坏.从main返回后,所有全局变量的析构函数将按照构造这些全局变量的相反顺序运行1.这就好像这些全局变量是在堆栈上构造的.
如果在Logger之前构造了一个对象,并试图在它自己的析构函数中使用它;然后它将使用已经被破坏的对象,导致未定义的行为.
1更准确地说,它们的构造函数以相反的顺序完成.
最简单的选择是重新审视典型单身人士:
class Logger { public: static Logger& Instance() { static Logger* L = new Logger; return *L; } private: ... };
这现在是线程安全的,但仍然泄漏.但实际上这里需要泄漏,因为它可以保证这个对象比任何其他析构函数都被调用的时间更长.警告:如果你曾经在析构函数中做过一些事情,它将永远不会运行.
还有其他的变化,例如Alexandrescu的凤凰Singleton从它的灰烬中回来,如果它在它死后需要它;但是,在破坏期间获得线程安全性和安全性很难实现.
C++中的Singleton类的实现
《设计模式》中把 singleton 写成返回指针:
class Singleton{ public: static Singleton* Instance(); protected: Singleton(); private: static Singleton* _instance; };
相应的实现 cpp 文件是:
Singleton* Singleton::_instance; Singleton* Singleton::Instance(){ if( _instance == 0){ _instance = new Singleton; }; return _instance; }
将构造函数设计成 protected 的目的是防止在 class 外面 new ,有人可能会设计成 private ,如果考虑到有可能会继承这个类的话,还是将构造函数设计成 protected 比较好,还需要加一个 virtual 析构函数。为了防止别人复制 Singleton 对象:
Singleton* pSingleton = Singleton::Instance(); Singleton s1 = *pSingleton; Singleton s2 = *pSingleton; 需要将拷贝构造(copy constructor)函数变成 private。
但是这里存在的问题是,什么时候删除 Singleton 对象?按照 C++ 的一个基本原则,对象在哪里创建就在哪里销毁,这里还应该放一个 destroy 方法来删除 Singleton 对象。如果忘了删除就比较麻烦。Instance 函数还存在多线程同时访问的加锁问题。如果把 Instance 函数开始和结尾放上加锁和解锁,整个函数性能会下降很多。这不是一个好的设计。
有一个小小的改动,可以避免忘了删除 Singleton 对象带来内存泄露的问题。那就是用 std:auto_ptr 来包含 Singleton 对象,定义一个class static member auto_ptr 对象,在析构的静态 auto_ptr 变量的时候时候自动删除 Singleton 对象。为了不让用户 delete Singleton 对象,需要将析构函数由 public 变成 protected。以下是头文件 SingletonAutoPtr.h :
#include <memory> using namespace std; class CSingletonAutoPtr { private: static auto_ptr<CSingletonAutoPtr> m_auto_ptr; static CSingletonAutoPtr* m_instance; protected: CSingletonAutoPtr(); CSingletonAutoPtr(const CSingletonAutoPtr&); virtual ~CSingletonAutoPtr(); //allow auto_ptr to delete, using protected ~CSingletonAutoPtr() friend class auto_ptr<CSingletonAutoPtr>; public: static CSingletonAutoPtr* GetInstance(); void Test(); };
#p#对应的 SingletonAutoPtr.cpp 如下:
立即学习“C++免费学习笔记(深入)”;
#include "SingletonAutoPtr.h" #include <iostream> //initial static member vars here CSingletonAutoPtr* CSingletonAutoPtr::m_instance = NULL; auto_ptr<CSingletonAutoPtr> CSingletonAutoPtr::m_auto_ptr; ///////////////////////////////////////// // Construction/Destruction ///////////////////////////////////////// CSingletonAutoPtr::CSingletonAutoPtr() { cout << "CSingletonAutoPtr::CSingletonAutoPtr()" << endl; //put single object into auto_ptr object m_auto_ptr = auto_ptr<CSingletonAutoPtr>(this); } CSingletonAutoPtr::~CSingletonAutoPtr() { cout << "CSingletonAutoPtr::~CSingletonAutoPtr()" << endl; } CSingletonAutoPtr* CSingletonAutoPtr::GetInstance() { //begin lock //.... if(m_instance == NULL) m_instance = new CSingletonAutoPtr(); //end lock //... return m_instance; } void CSingletonAutoPtr::Test() { cout << "CSingletonAutoPtr::Test()" << endl; }
调用方法:
CSingletonAutoPtr* pSingleton = CSingletonAutoPtr::GetInstance(); pSingleton->Test();
写一个 C++ 中的 Singleton 需要这么费劲,大大出乎我们的意料。有很多人从未用过 auto_ptr,而且 std:auto_ptr 本身就并不完美,它是基于对象所有权机制的,相比之下,Apache Log4cxx 中有一个 auto_ptr, 是基于对象计数的,更为好用。只是为了用一个好的 auto_ptr 而不得不用 log4cxx , 对于很多项目来说,也不太好。当然了,ANSI C++ 的 STL 中 std:auto_ptr 对于写上面的例子已经足够用了。
#p#另外一个思路是,把 GetInstance 函数设计成 static member 可能更好,因为一般来说,Singleton 对象都不大,static member 虽然必须一直占用内存,问题不大。这里的析构函数必须设成 public 了。以下是头文件 SingleStaticObj.h
class CSingletonStaticObj { private: static CSingletonStaticObj m_instance; protected: CSingletonStaticObj(); CSingletonStaticObj(const CSingletonStaticObj&); public: virtual ~CSingletonStaticObj(); //must public static CSingletonStaticObj& GetInstance(); void Test(); }; 对应的 SingleStaticObj.cpp 文件为: #include "SingletonStaticObj.h" #include <string> #include <iostream> using namespace std; CSingletonStaticObj CSingletonStaticObj::m_instance; CSingletonStaticObj::CSingletonStaticObj() { cout << "CSingletonStaticObj::CSingletonStaticObj()" << endl; } CSingletonStaticObj::~CSingletonStaticObj() { cout << "CSingletonStaticObj::~CSingletonStaticObj()" << endl; } CSingletonStaticObj& CSingletonStaticObj::GetInstance() { return m_instance; } void CSingletonStaticObj::Test() { cout << "CSingletonStaticObj::Test()" << endl; }
调用方法:
CSingletonStaticObj& singleton = CSingletonAutoPtr::GetInstance();singleton.Test();
从代码量来说,似乎使用 static member ref 更为简单。我更偏向于用这种方法。
但是,并不是所有情况下面都适合用 static member singleton。比如说,GetInstance 需要动态决定返回不同的 instance 的时候,就不能用。举例来说,FileSystem::GetInstance, 在 windows 下面运行可能需要返回 new WinFileSystem, Linux/Unix 下面运行可能需要返回 new LinuxFileSystem,这个时候还是需要用上面的 auto_ptr 包含 singleton 指针的方法。
Flex中的Singleton类
是否有任何类似于类名的约定应该是eb Singleton,或者它应该扩展任何其他类.
一个项目有多少Singleton类?
有谁可以说Singleton类的实时使用?
我打算将我的组件标签文本保存在Singleton类中……这是一个好方法.
解决方法
关于创建单例的方法有几种,主要是因为AS3没有私有构造函数.这是我们使用的模式.
package com.foo.bar { public class Blah { private static var instance : Blah; public function Blah( enforcer : SingletonEnforcer ) {} public static function getInstance() : Blah { if (!instance) { instance = new Blah( new SingletonEnforcer() ); } return instance; } ... } } class SingletonEnforcer{}
请注意,SingletonEnforcer类是内部的,因此只能由Blah类使用(有效).没有人可以直接实例化类,他们必须通过getInstance()函数.
关于在Singleton类中加载属性文件和对象加载的过程,属性先加载还是方法先加载的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于4.平凡之路-封装帮助类和加载属性文件、c – 陷阱:静态堆栈变量Singleton类、C++中的Singleton类的实现、Flex中的Singleton类的相关信息,请在本站寻找。
本文标签: