2013-02-01 35 views
10

Tôi có một lớp giống như vậy:mùa xuân tiêm tĩnh (toàn cầu) singleton

public class Configurator { 
    private static Configurator INSTANCE = null; 

    private int maxRange = 1; 

    // many other properties; each property has a default value 

    private static synchronized Configurator getInstance() { 
     if(INSTANCE == null) 
      return new Configurator(); 

     return INSTANCE; 
    } 

    public static int getMaxRange() { 
     getInstance().maxRange; 
    } 

    public static void setMaxRange(int range) { 
     getInstance().maxRange = range; 
    } 

    // Getters and setters for all properties follow this pattern 
} 

Nó đóng vai trò như một đối tượng cấu hình toàn cầu có thể được thiết lập khi khởi động ứng dụng, và sau đó được sử dụng bởi hàng chục lớp học trong suốt dự án:

// Called at app startup to configure everything 
public class AppRunner { 
    Configurator.setMaxRange(30); 
} 

// Example of Configurator being used by another class 
public class WidgetFactory { 
    public void doSomething() { 
     if(Configurator.getMaxRange() < 50) 
      // do A 
     else 
      // do B 
    } 
} 

Tôi hiện đang nhập mã này vào một dự án Spring và đang cố định cấu hình XML Sprinig của tôi (đậu). tôi đoán là tôi có thể xác định một Configurator đậu duy nhất như vậy (hoặc một cái gì đó tương tự):

<bean id="configurator" class="com.me.myapp.Configurator" scope="singleton"> 
    <property name="maxRange" value="30"/> 
    <!-- etc., for all properties --> 
</bean> 

Bằng cách đó, khi WidgetFactory#doSomething thực thi, mùa xuân sẽ có đã nạp lớp Configurator và cấu hình nó trước thời hạn.

Tôi có đặt đúng số scope="singleton" hoặc điều này không quan trọng? Tôi có thiết lập các thuộc tính tĩnh một cách chính xác không? Có điều gì khác tôi cần làm hay cân nhắc ở đây không? Cảm ơn trước.

Trả lời

7

Có một số khác biệt giữa Singleton là mẫu thiết kế và cơ sở đơn lẻ của Spring. Singleton như là một mẫu thiết kế sẽ đảm bảo bạn có một đối tượng của lớp được xác định cho mỗi bộ nạp lớp. Ngược lại, cơ sở singleton của Spring (và cách tiếp cận) sẽ xác định một cá thể trên mỗi bối cảnh mùa xuân.

Trong trường hợp này bạn có thể sử dụng phương pháp getInstance() của bạn sẽ được sử dụng bởi Spring để lấy trường hợp đối tượng của bạn:

<bean id="configurator" class="com.me.myapp.Configurator" factory-method="getInstance"> 
</bean> 

Với mùa xuân phạm vi đậu singleton là mặc định do đó bạn không cần phải định nghĩa nó.

Nếu bạn muốn sử dụng configurator làm hạt mùa xuân, bạn sẽ phải tiêm nó vào các đối tượng khác, không sử dụng getInstance() để lấy. Vì vậy, trong các bean Spring khác sử dụng @Autowired hoặc xác định tham chiếu đến bean thông qua file xml. Nếu bạn không tổ chức lại việc sử dụng configurator trong các lớp khác, sẽ không có sự khác biệt, Spring sẽ khởi tạo lớp của bạn, nhưng bạn sẽ sử dụng nó như trước đây.

Ngoài ra tôi thấy rằng bạn gặp lỗi khi thiết kế singleton của mình. Phương thức getInstance() của bạn phải được công khai và các phương thức khác không được tĩnh. Trong ví dụ này bạn đã sử dụng bạn nên sử dụng Singleton như thế này:

Configurator.getInstance().someMethod() 

Trong trường hợp này bạn thực sự chỉ cần sử dụng lớp Singleton, mà không instantiating bất kỳ đối tượng! Xem wikipedia on Singleton (with Java example) để biết thêm thông tin về mẫu thiết kế Singleton và cách sử dụng.


LƯU Ý: Cần biết và cố gắng sử dụng Configurator làm Singleton và sử dụng thiết bị đơn lẻ của Spring. Nếu bạn làm điều này những lợi ích sẽ được rằng bạn có thể

  • Tháo phương pháp getInstance()
  • Hãy xây dựng công cộng của bạn
  • Hãy để mùa xuân nhanh chóng mà đối tượng duy nhất.
+0

Cảm ơn @partlov (+1) - tôi có cần phải đặt phương thức 'getInstance()' của mình thành công khai, hoặc Spring có thể xử lý thực tế là nó là riêng tư? –

+0

Bạn không cần nó (getInstance()) –

1

Đậu là đơn theo mặc định. Bạn có thể tìm thấy thông tin này/thêm thông qua trang web mùa xuân.

Bạn không nên khởi tạo Trình cấu hình mới trong getInstance vì nó sẽ không đề cập đến bean được tải vào mùa xuân và có thể gây ra một số vấn đề nghiêm trọng. Bạn có thể dây đậu này trong và sau đó để lại nó một mình, nó sẽ không được null vì bạn đã có dây nó trong (và nếu nó là chương trình của bạn sẽ có khởi tạo thất bại).

0

Có, nếu bạn muốn một cái gì đó toàn cầu, phạm vi singleton là lựa chọn đúng. một vài điều đáng nói ở đây là:

  1. Phạm vi mặc định trong mùa xuân là singleton, vì vậy bạn không cần phải thiết lập một cách rõ ràng đậu của bạn như phạm vi singleton.
  2. Sử dụng Spring bạn không cần phải viết Mẫu Singleton mã kiểu, chẳng hạn như trường hợp riêng tư và phương thức nhà máy. Đó là vì Spring sẽ đảm bảo rằng chỉ có một trường hợp duy nhất cho mỗi vùng chứa mùa xuân . Thậm chí không nói, phương pháp nhà máy của bạn là riêng tư.
0

Bằng cách này: đây không phải là chủ đề an toàn:

if(INSTANCE == null) 
     return new Configurator(); 

    return INSTANCE; 
} 

Trong khi này sẽ là:

private static Configurator INSTANCE = new Configurator(); 

(Háo hức khởi)

private static volatile Singleton _instance = null; 

(Lazy khởi với từ khóa dễ bay hơi)

Nó phải làm với cách Java cấp phát bộ nhớ và tạo ra các cá thể. Đây không phải là nguyên tử, nhưng được thực hiện theo hai bước và có thể bị can thiệp bởi bộ lập lịch trình chuỗi.

Xem thêm http://regrecall.blogspot.de/2012/05/java-singleton-pattern-thread-safe.html.

Các vấn đề liên quan