GVKun编程网logo

在Singleton类中加载属性文件(对象加载的过程,属性先加载还是方法先加载)

16

针对在Singleton类中加载属性文件和对象加载的过程,属性先加载还是方法先加载这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展4.平凡之路-封装帮助类和加载属性文件、c–陷阱:静态堆栈变

针对在Singleton类中加载属性文件对象加载的过程,属性先加载还是方法先加载这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展4.平凡之路-封装帮助类和加载属性文件、c – 陷阱:静态堆栈变量Singleton类、C++中的Singleton类的实现、Flex中的Singleton类等相关知识,希望可以帮助到你。

本文目录一览:

在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.平凡之路-封装帮助类和加载属性文件

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类

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类的实现

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类

Flex中的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类的相关信息,请在本站寻找。

本文标签: