2008-09-17 24 views
27

Tôi đang sử dụng Java 1.4 với Log4J.LoggerJ Logger có nên được khai báo là tạm thời không?

Một số mã của tôi liên quan đến việc tuần tự hóa và deserializing các đối tượng giá trị (POJOs).

Mỗi POJO tôi tuyên bố một logger với

private final Logger log = Logger.getLogger(getClass()); 

Các serializer phàn nàn của org.apache.log4j.Logger không phải là Serializable.

Tôi có nên sử dụng

private final transient Logger log = Logger.getLogger(getClass()); 

để thay thế?

+1

Một vài câu hỏi bạn có thể tự hỏi mình và thêm làm chỉnh sửa cho câu hỏi của mình. Suy nghĩ của bạn về và chống lại việc tạm thời là gì? Tạm thời nghĩa là gì? – svrist

+1

Tôi nên đề cập đến, tôi thích ý tưởng có một trình ghi nhật ký cho mỗi cá thể thay vì một cho mỗi lớp. Tôi sẽ có nhiều phiên bản của cùng một lớp được tạo và quản lý bởi một vùng chứa (nói ngữ cảnh ứng dụng Spring) và muốn chuyển mức ghi nhật ký trên cơ sở mỗi bean thay vì trên cơ sở mỗi lớp. Trong ví dụ về ngữ cảnh ứng dụng mùa xuân, trình ghi nhật ký sẽ được khai báo là một cái gì đó như tạm thời cuối cùng riêng Logger log = Logger.getLogger (getBeanName()); trong đó bean không còn là POJO và triển khai BeanNameAware – Vihung

+1

Xem thêm [Câu hỏi thường gặp về SLF4J] (http://www.slf4j.org/faq.html#declared_static): * "Các thành viên của Logger nên được khai báo là tĩnh? [...] Tóm lại, việc khai báo các thành viên logger như các biến tĩnh đòi hỏi ít thời gian CPU hơn và có dấu chân bộ nhớ hơi nhỏ hơn. [...] Tuy nhiên, các biến mẫu có thể tạo môi trường logger riêng biệt cho mỗi ứng dụng, Có lẽ quan trọng hơn những cân nhắc đã đề cập trước đây, các biến cá thể là IOC-thân thiện trong khi các biến tĩnh thì không. "* – Arjan

Trả lời

26

Làm thế nào để sử dụng trình ghi nhật ký tĩnh? Hay bạn cần một tham chiếu logger khác nhau cho mỗi thể hiện của lớp? Các trường tĩnh không được tuần tự hóa theo mặc định; bạn có thể khai báo rõ ràng các trường để tuần tự hóa với một mảng riêng, tĩnh, cuối cùng là ObjectStreamField có tên là serialPersistentFields. See Oracle documentation

Đã thêm nội dung: Khi bạn sử dụng getLogger(getClass()), bạn sẽ sử dụng cùng một trình ghi nhật ký trong từng trường hợp. Nếu bạn muốn sử dụng logger riêng biệt cho mỗi cá thể, bạn phải phân biệt tên của logger trong phương thức getLogger() -method. ví dụ. getLogger (getClass(). getName() + hashCode()). Sau đó, bạn nên sử dụng thuộc tính thoáng qua để đảm bảo rằng trình ghi nhật ký không được đăng.

+2

Trình ghi nhật ký tĩnh không tốt cho các ứng dụng web. –

+0

@ ThorbjørnRavnAndersen Bạn có thể giải thích, tại sao không tốt cho việc triển khai lại ứng dụng web? Hoặc là vấn đề này cố định với AS mới hơn như WildFly 8.2 và như vậy? – CSchulz

+5

logger tĩnh có xu hướng - trừ khi ứng dụng của bạn được mã hóa rất cẩn thận - để giữ cho trình nạp lớp để chúng không thể được thu thập rác. Điều này hiển thị trong ví dụ: tăng dần sử dụng bộ nhớ trong khi xây dựng maven mà đi xa khi javac được phân chia bởi maven. –

11

Trình ghi nhật ký phải tĩnh; điều này sẽ làm cho nó không thể tuần tự hóa được.

Không có lý do gì để làm cho trình ghi nhật ký không tĩnh, trừ khi bạn có lý do chính đáng để làm điều đó.

+4

Đôi khi có thể hữu ích khi có một trình ghi nhật ký không tĩnh nếu bạn muốn sử dụng các tên logger khác nhau cho mỗi cá thể (ví dụthêm một chuỗi ký tự duy nhất vào cuối tên của trình ghi nhật ký), hoặc nếu bạn có một trình ghi log trong một đối tượng siêu lớp và bạn muốn nó sử dụng tên của cá thể lớp con. –

+9

* "Không có lý do gì để làm cho logger không tĩnh, trừ khi bạn có một lý do mạnh mẽ để làm điều đó." * - điều này làm cho đầu tôi phát nổ! ;-) – Arjan

2

Hãy thử làm cho trình ghi nhật ký tĩnh thay thế. Hơn bạn không phải quan tâm đến việc tuần tự hóa bởi vì nó được xử lý bởi trình nạp lớp.

0

Nếu bạn muốn Trình ghi nhật ký là từng trường hợp thì có, bạn sẽ muốn làm cho nó thoáng qua nếu bạn định sắp xếp các đối tượng của mình. Logger Log4J không serializable, không phải trong phiên bản của Log4J mà tôi đang sử dụng anyway, vì vậy nếu bạn không làm cho các lĩnh vực Logger của bạn thoáng qua bạn sẽ nhận được ngoại lệ về serialization.

0

Trình ghi nhật ký không được tuần tự hóa, do đó bạn phải sử dụng tạm thời khi lưu trữ chúng trong các trường mẫu. Nếu bạn muốn khôi phục logger sau khi deserialization bạn có thể lưu trữ Level (String) indide đối tượng của bạn mà không nhận được serialized.

2

Các loại trường hợp này, đặc biệt là trong EJB, thường được xử lý tốt nhất thông qua trạng thái địa phương của luồng. Thông thường, trường hợp sử dụng giống như bạn có một giao dịch cụ thể đang gặp sự cố và bạn cần nâng cao nhật ký để gỡ lỗi cho hoạt động đó để bạn có thể tạo nhật ký chi tiết về hoạt động sự cố. Thực hiện một số trạng thái địa phương luồng trên giao dịch và sử dụng để chọn trình ghi nhật ký chính xác. Thành thật mà nói, tôi không biết nó sẽ có lợi khi thiết lập mức trên một INSTANCE trong môi trường này bởi vì việc ánh xạ các cá thể vào giao dịch phải là một hàm mức container, bạn sẽ không thực sự kiểm soát được cá thể nào được sử dụng trong một giao dịch đã cho. Ngay cả trong trường hợp bạn đang đối phó với DTO, thường không phải là một ý tưởng tốt để thiết kế hệ thống của bạn theo cách mà một cá thể cụ thể được yêu cầu vì thiết kế có thể dễ dàng phát triển theo những cách làm xấu lựa chọn. Bạn có thể đi cùng một tháng từ bây giờ và quyết định rằng những cân nhắc về hiệu quả (bộ nhớ đệm hoặc một số vòng đời tối ưu hóa thay đổi khác) sẽ phá vỡ giả định của bạn về việc ánh xạ các cá thể thành các đơn vị công việc.

5

Hoặc khai báo trường trình ghi của bạn là tĩnh hoặc tạm thời.

Cả hai cách đều đảm bảo phương thức writeObject() sẽ không cố gắng ghi trường vào luồng đầu ra trong quá trình tuần tự hóa.

Thông thường các trường logger được khai báo là tĩnh, nhưng nếu bạn cần nó là một trường thể hiện, hãy khai báo nó thoáng qua, vì nó thường được thực hiện cho bất kỳ trường không tuần tự hóa nào. Khi deserialization trường logger sẽ là null, tuy nhiên, vì vậy bạn phải thực hiện một phương thức readObject() để khởi tạo nó đúng cách.

9

Nếu bạn thực sự muốn sử dụng phương pháp tạm thời, bạn sẽ cần đặt lại nhật ký khi đối tượng của bạn được deserialized. Các cách để làm điều đó là để thực hiện phương pháp này:

private void readObject(java.io.ObjectInputStream in) 
    throws IOException, ClassNotFoundException; 

các javadocs cho Serializable có thông tin về phương pháp này.

triển khai của bạn của nó sẽ giống như thế:

private void readObject(java.io.ObjectInputStream in) 
    throws IOException, ClassNotFoundException { 
    log = Logger.getLogger(...); 
    in.defaultReadObject(); 
} 

Nếu bạn không làm điều này sau đó đăng nhập sẽ được null sau deserializing đối tượng của bạn.

0

Có nhiều lý do chính đáng để sử dụng trình ghi nhật ký. Một trường hợp sử dụng rất tốt là bạn có thể khai báo logger trong một siêu lớp và sử dụng nó trong tất cả các lớp con (nhược điểm duy nhất là các log từ lớp siêu được gán cho lớp con nhưng thường dễ dàng thấy điều đó).

(Giống như những người khác đã đề cập sử dụng tĩnh hoặc tạm thời).

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