zoukankan      html  css  js  c++  java
  • 反射破坏单例的私有构造函数保护

          Java的反射破坏单例的私有构造函数保护,最典型的就是Spring的Bean注入,我们可以通过改造私有构造函数来防止。
      在Singleton中,我们只对外提供工厂方法(获取单例),而私有化构造函数,来防止外面多余的创建。
      对于一般的外部调用来说,私有构造函数已经很安全了。
             

    public class Singleton {
      private Singleton(){}
      private static volatile Singleton instance = null;
      public static SingletongetInstance() throws Exception {
      if (instance ==null) { //为了简洁度,暂不考虑线程安全
      instance =new Singleton();
      }
      returninstance;
      }
      }
    

      

      

    Class singletonClass = Class.forName("com.jscai.spring.demo.Singleton");
    Constructor[] cts =singletonClass.getConstructors();
    System.out.println(cts.length)


      一般的外部调用,编译器会校验,直接提示编译错误。而正常的反射也是找不到私有构造函数的,所以上面的输出为0.
      但是一些特权用户可以通过反射来访问私有构造函数,并且实例化:
      

    Constructor[] cts = singletonClass.getDeclaredConstructors();
    System.out.println(cts.length);
    cts[0].setAccessible(true);
    Singletonsingleton = (Singleton) cts[0].newInstance();
    

      


      上述代码首先通过反射的getDeclaredConstructors()来获取所有构造函数(public,protected,default * (package) access, andprivate constructors),当然这个函数会校验调用者的权限。
      此时默认还是不能调用私有构造函数的,还需要把访问权限打开setAccessible(true),就可以访问私有构造函数了,这样破坏了单例的私有构造函数保护。
      如果要防御这样的反射侵入,可以修改构造函数,加上第二次实例化的检查。(上面的getInstance()经过多线程(DoubleCheck)处理后,就不会出现线程冲突来触发这个异常)

    private static int cntInstance = 0;
    private Singleton()throws Exception {
    if (++cntInstance > 1 ) {
    throw new Exception("Can'tcreate another instance.");
            }
     }
    

      


      另外,在Spring的Bean注入中,即使你私有化构造函数,默认他还是会去调用你的私有构造函数去实例化。 【通过BeanFactory来装配Bean,和上面的逻辑如出一辙】
      所以,如果我们想保证实例的单一性,就要在定义<bean>时加上factory-method=""的属性,并且在私有构造函数中添加防御机制。单例的getInstance()可能会添加一些逻辑,而Spring的默认调用构造函数去创建,就不能保证这份逻辑的准确性,所以会带来隐患。
      我们可以通过scope="prototype"来测试单例是否被多次创建:

      <beanid="test"class="com.jscai.spring.demo.Singleton"scope="prototype"></bean>
      BeanFactory bf = new ClassPathXmlApplicationContext("demoAppTestContext.xml");
      Singleton test1 = (Singleton) bf.getBean("singleton");
      Singleton test2 = (Singleton) bf.getBean("singleton");
    

      


      发现防御机制生效,抛出"Can't create another instance."的异常,证明Spring能正常调用私有的构造函数来创建Bean,并且创建了多次。
      这时候我们要使用factory-method来指定工厂方法,才能达到我们想要的效果
      

    <beanid="test"class="com.jscai.spring.demo.Singleton"scope="prototype"factory-method="getInstance"></bean>
    

      

  • 相关阅读:
    VS2008编写MFC程序--使用opencv2.4()
    November 02nd, 2017 Week 44th Thursday
    November 01st, 2017 Week 44th Wednesday
    October 31st, 2017 Week 44th Tuesday
    October 30th, 2017 Week 44th Monday
    October 29th, 2017 Week 44th Sunday
    October 28th, 2017 Week 43rd Saturday
    October 27th, 2017 Week 43rd Friday
    October 26th, 2017 Week 43rd Thursday
    October 25th, 2017 Week 43rd Wednesday
  • 原文地址:https://www.cnblogs.com/xiohao/p/5473966.html
Copyright © 2011-2022 走看看