java 單例模式防治反攻擊

參考:http://m.blog.csdn.net/article/details?id=50525335

1: single bean 餓漢模式

package com.xxx.cn;

/**

 * 

 * @author petter

 *

 */

public class TestSingleBean {

private static boolean flag = false;

public static final TestSingleBean bean = new TestSingleBean();

private TestSingleBean(){

if(flag == false){

flag = !flag;

}else{

throw new RuntimeException("構件單列異常");

}

}

// public static TestReflectionBean getInstance(){

// if(bean == null){

// bean = new TestReflectionBean();

// }

// return bean;

// }

public void test(){

System.out.println("test reflection");

}


}


2:測試代碼:

public class HelloWorld {

public static void main(String args[]){

System.out.println("JAVA project");

testReflactionBeanMethod();

testReflactionMethond();

}

private static void testReflactionBeanMethod(){

try {

  //正常情況

TestSingleBean testbean = TestSingleBean.bean;

System.out.println(testbean.hashCode());

TestSingleBean testbean2 = TestSingleBean.bean;

System.out.println(testbean2.hashCode());

//設置setAccessible屬性

Class<?> classType = TestSingleBean.class;

        Constructor<?> c1 = classType.getDeclaredConstructor(null);

        c1.setAccessible(true);//添加此方法設置屬性,可以跳用private構造函數;accessible 可以進入的意思

        TestSingleBean e1 = (TestSingleBean)c1.newInstance();

        System.out.println(e1.hashCode());

//反射構建對象

Class c = Class.forName("com.xxx.cn.TestSingleBean");

Constructor c0=c.getDeclaredConstructor();   

            c0.setAccessible(true);   

            TestSingleBean po=(TestSingleBean)c0.newInstance();   

            po.test();


} catch (Exception e) {

e.printStackTrace();

}

private static void testReflactionMethond(){

String str = "123";

TestReflectionMethod.change(str);

System.out.println(str);

}

}


3:打印結果

JAVA project

104181190

104181190

java.lang.reflect.InvocationTargetException

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:526)

at petter.HelloWorld.testReflactionBeanMethod(HelloWorld.java:25)

at petter.HelloWorld.main(HelloWorld.java:11)

Caused by: java.lang.RuntimeException: 構件單列異常

at com.xxx.cn.TestSingleBean.<init>(TestSingleBean.java:15)

... 6 more

123



說明:(瞭解)

在1,2,3,公有靜態成員是個final域;

如果構造方法改造爲:公有的成員是個靜態工廠方法:

public class xxx{

private static final xxx INSTANCE = new xxx();

private xxx(){};

public static xxx getInstance(){

return INSTANCE;

}

//防止序列化生成新的實例

private object redResolve(){

return INSTANCE;

}

}




4:單例的線程安全,經常會在開源的源碼中看到:雙重檢查  懶漢模式
private xxx bean;
public static xxx getInstance(){
  if(bean == null){
synchronized(xxx.class){
if(bean == null){
   bean = new XXX();
                }
}
   
  }
  return bean;
}
這種寫法儘量避免了同步帶來的性能損耗;

5:反射中的getDeclaredConstructor();
java.lang.Class.getDeclaredConstructor() 方法返回一個Constructor對象,它反映此Class對象所表示的類或接口指定的構造函數。parameterTypesparameter是確定構造函數的形參類型,在Class對象聲明順序的數組。


6:拓展,餓漢模式我們做了反射驗證,那麼懶漢模式是否同樣有用?

package com.xxx.cn;

/**

 * 

 * @author petter

 *

 */

public class TestSingleBean {

private static boolean flag = false;

private static TestSingleBean bean;

// public static final TestSingleBean bean = new TestSingleBean();

private TestSingleBean(){

if(flag == false){

flag = !flag;

}else{

throw new RuntimeException("構件單列異常");

}

}

public static TestSingleBean getInstance(){

if(bean == null){

bean = new TestSingleBean();

}

return bean;

}

}


JAVA project

1367113803

1367113803

java.lang.reflect.InvocationTargetException

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:526)

at petter.HelloWorld.testReflactionBeanMethod(HelloWorld.java:27)

at petter.HelloWorld.main(HelloWorld.java:11)

Caused by: java.lang.RuntimeException: 構件單列異常

at com.xxx.cn.TestSingleBean.<init>(TestSingleBean.java:16)

... 6 more

123



測試的結果就是,還是需要加上防止反射的代碼;不然反射的時候還是會嘗試構建新的對象;

好吧,先紀錄着麼多;






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章