Tại sao chúng ta tuyên bố Loggers tĩnh cuối cùng?


131

Trong Java, tại sao cách khai báo logger tốt nhất static final?

private static final Logger S_LOGGER

Câu trả lời:


209
  • private- để không có lớp nào khác có thể chiếm quyền điều khiển logger của bạn
  • static - vì vậy chỉ có một phiên bản logger cho mỗi lớp, cũng tránh các nỗ lực để tuần tự hóa logger
  • final - không cần thay đổi logger trong suốt vòng đời của lớp

Ngoài ra, tôi thích tên logcàng đơn giản càng tốt, nhưng mô tả.

EDIT: Tuy nhiên, có một ngoại lệ thú vị đối với các quy tắc này:

protected final Logger log = LoggerFactory.getLogger(getClass());

như trái ngược với:

private static final Logger log = LoggerFactory.getLogger(Foo.class);

Cách trước đây cho phép bạn sử dụng cùng tên logger (tên của lớp thực tế) trong tất cả các lớp trong toàn bộ phân cấp thừa kế. Vì vậy, nếu Barkéo dài Foo, cả hai sẽ đăng nhập vào Barlogger. Một số tìm thấy nó trực quan hơn.


35
nếu tĩnh và cuối cùng thì thay vào đó là LOG (chữ hoa)
zacheusz

39
@zacheusz , tôi biết, đó là điểm chính. Một số theo quy ước đặt tên Java một cách tôn giáo (không có gì sai với điều đó), nhưng tôi thích viết dễ hơn và dễ đọc loghơn tên hơn là phân tán mã LOG. Chỉ là vấn đề của dev. thỏa thuận đội.
Tomasz Nurkiewicz

27
Xin lưu ý rằng không còn luôn luôn khuyến nghị khai báo loggers là tĩnh và cuối cùng, xem slf4j.org/faq.html#declared_staticwiki.apache.org/commons/Logging/FrequentlyAskedQuestions Tôi có nên khai báo các tham chiếu Nhật ký tĩnh hay không?
Matthew Farwell

6
@zacheusz Tên trường được viết hoa được sử dụng cho các hằng số. Logger không đổi. http://stackoverflow.com/questions/1417190/should-a-static-final-logger-be-declared-in-upper-case
michal.kreuzman 17/12/12

2
@zacheusz không phải tất cả các thuộc tính tĩnh cuối cùng phải là UPPERCASE: stackoverflow.com/questions/1417190/
Kẻ

15

Kiểm tra bài đăng trên blog này: Thoát khỏi Trình ghi nhật ký tĩnh Java . Đây là cách bạn sử dụng slf4j với jcabi-log :

import com.jcabi.log.Logger;
class Foo {
  void save(File f) {
    Logger.info(this, "file %s saved successfully", f);
  }
}

Và không bao giờ sử dụng tiếng ồn tĩnh đó nữa.


Một thay thế thú vị và chắc chắn sạch hơn. Tôi tự hỏi làm thế nào quy mô này so với logger lớp cá nhân.
Ross

12
Viết Logger dài hơn .. (này, ...) mỗi lần. Không
Mikhail Boyarsky

Nhận xét đầu tiên trong bài đăng trên blog có liên quan chỉ ra mặt xấu của các phương thức tĩnh :) Vì vậy, sử dụng Logger cuối cùng là cách thực hành tốt nhất tôi đoán.
Bahadir Tasdemir

5

staticcó nghĩa là bạn chỉ tạo một Logger cho mỗi lớp chứ không phải một logger cho mỗi thể hiện của lớp bạn. Nói chung, đây là những gì bạn muốn - vì các logger có xu hướng thay đổi chỉ dựa trên lớp.

finalcó nghĩa là bạn sẽ không thay đổi giá trị của loggerbiến. Điều này đúng, vì hầu như bạn luôn ném tất cả các thông điệp tường trình (từ một lớp) vào cùng một logger. Ngay cả trong những trường hợp hiếm hoi mà một lớp có thể muốn gửi một số thông điệp đến một logger khác, việc tạo một biến logger khác (ví dụ widgetDetailLogger) sẽ rõ ràng hơn thay vì thay đổi giá trị của biến tĩnh khi đang di chuyển.


4

Khi nào bạn muốn thay đổi giá trị của trường?

Nếu bạn sẽ không bao giờ thay đổi giá trị, việc đưa ra trường cuối cùng sẽ cho thấy rõ rằng bạn sẽ không bao giờ thay đổi giá trị.


1
Trong nhiều trường hợp, rõ ràng là không có từ cuối cùng, trường hợp này trở thành một loại rác.
Dima

2
@Dima: Vâng tôi vẫn biết ơn rằng trình biên dịch vẫn sẽ ném ra một lỗi nếu tôi làm vô tình cố gắng để thay đổi giá trị trong những trường hợp ...
Jon Skeet

3

Thông thường, bạn khởi tạo logger để ghi nhật ký bằng tên lớp - điều đó có nghĩa là nếu chúng không tĩnh, bạn sẽ kết thúc với mỗi thể hiện của lớp có một thể hiện của nó (dấu chân bộ nhớ cao), nhưng tất cả các logger này sẽ chia sẻ cùng một cấu hình và hành xử giống hệt nhau. Đó là lý do đằng sau staticbit. Ngoài ra vì mỗi cái Loggerđược khởi tạo với tên lớp, để ngăn xung đột với các lớp con, bạn khai báo nó privateđể nó không thể được kế thừa. Xuất finalphát từ điểm mà bạn thường không thay đổi Loggertrong quá trình thực thi - vì vậy, một khi đã khởi tạo, bạn không bao giờ "cấu hình lại" nó - trong trường hợp đó là hợp lý để đảm bảo cuối cùng để đảm bảo không ai có thể thay đổi nó (bởi sai lầm hoặc cách khác). Tất nhiên nếu bạn sẽ sử dụng mộtLoggertheo một cách khác bạn có thể KHÔNG cần sử dụng static final- nhưng tôi sẽ mạo hiểm đoán 80% ứng dụng sẽ sử dụng đăng nhập như đã giải thích ở trên.


3

Để trả lời câu hỏi đó, bạn nên tự hỏi "tĩnh" và "cuối cùng" là để làm gì.

Đối với một Logger, (tôi giả sử bạn nói về lớp Log4J Logger) bạn muốn một danh mục cho mỗi lớp. Điều này sẽ dẫn đến thực tế là bạn chỉ gán nó một lần và không cần nhiều hơn một thể hiện cho mỗi lớp. Và có lẽ không có lý do gì để phơi bày đối tượng Logger của lớp này sang lớp khác, vậy tại sao không làm cho nó riêng tư và tuân theo một số Nguyên tắc OO.

Ngoài ra, bạn cần lưu ý rằng trình biên dịch có thể nhận được lợi ích của điều đó. Vì vậy, mã của bạn thực hiện tốt hơn một chút :)


2

Bởi vì đó thường là loại chức năng có thể được chia sẻ trên tất cả các phiên bản của các đối tượng của bạn. Sẽ không có ý nghĩa gì (90% thời gian) để có một trình ghi nhật ký khác nhau cho hai trường hợp của cùng một lớp.

Tuy nhiên, bạn cũng có thể thấy đôi khi các lớp logger được khai báo là singletons hoặc thậm chí chỉ đơn giản là cung cấp các hàm tĩnh để ghi nhật ký công cụ của bạn.


2

Mã này dễ bị tổn thương ,, nhưng sau Java7, chúng ta có thể sử dụng Logger lgr = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); thay cho logger tĩnh.


This is code is vulnerableBạn có thể làm rõ bạn trả lời một chút?
Dmitry Zagorulkin

1

Trong hầu hết các trường hợp, bạn sẽ không thay đổi tham chiếu và finalsửa đổi đánh dấu nó. Bạn không cần các thể hiện riêng cho từng thể hiện của lớp - vì vậy static. Và trước hết, đây là hiệu năng - nó có thể được tối ưu hóa độc đáo (cuối cùng) và tiết kiệm bộ nhớ (tĩnh).


1

Logger lý tưởng nên như sau cho đến Java 7, vì không đưa ra Sonar và đưa ra Mã tuân thủ: riêng tư: không bao giờ có thể truy cập được bên ngoài lớp cha của nó. Nếu một lớp khác cần phải ghi nhật ký một cái gì đó, nó sẽ khởi tạo logger của chính nó. static: không bị phụ thuộc vào một thể hiện của một lớp (một đối tượng). Khi ghi nhật ký một cái gì đó, thông tin theo ngữ cảnh tất nhiên có thể được cung cấp trong các tin nhắn nhưng logger nên được tạo ở cấp lớp để ngăn việc tạo một logger cùng với từng đối tượng và do đó ngăn chặn dấu chân bộ nhớ cao. cuối cùng: được tạo một lần và chỉ một lần mỗi lớp.


0

Ngoài những lý do được đưa ra trong các câu trả lời khác, một điều tôi gặp phải là nếu logger của tôi không tĩnh cũng không phải là cuối cùng:

...
public Logger logger = LoggerFactory.getLogger(DataSummary.class);

public String toJson() {
  GsonBuilder gsonBuilder = new GsonBuilder();   
  return gsonBuilder.create().toJsonTree(this).toString();
}
...

trong một số trường hợp nhất định (khi tôi đang sử dụng thư viện Gson) tôi sẽ nhận được ngoại lệ stackoverflow. Tình huống cụ thể của tôi là khởi tạo lớp chứa logger không tĩnh. Sau đó gọi phương thức toJson đã gọi GsonBuilder:

...
DataSummary ds = new DataSummary(data);    
System.out.println(ds.toJson());
...

0

Trên thực tế logger tĩnh có thể "có hại" vì chúng được cho là hoạt động trong bối cảnh tĩnh. Khi có một môi trường năng động, vd. OSGi có thể giúp sử dụng các logger không tĩnh. Vì một số triển khai ghi nhật ký thực hiện lưu trữ bộ đệm của bộ ghi nhật ký nội bộ (AFAIK ít nhất là log4j), tác động hiệu suất có thể không đáng kể.

Một nhược điểm của loggers tĩnh là ví dụ. thu gom rác (khi một lớp chỉ được sử dụng một lần, ví dụ như trong quá trình khởi tạo, bộ ghi sẽ vẫn được giữ xung quanh).

Để biết thêm chi tiết kiểm tra:

Xem thêm:


0

Theo thông tin tôi đọc được từ internet về việc làm cho logger tĩnh hay không, cách tốt nhất là sử dụng nó theo các trường hợp sử dụng.

Có hai đối số chính:

1) Khi bạn làm cho nó tĩnh, nó không phải là rác được thu thập (sử dụng & hiệu suất bộ nhớ).

2) Khi bạn không làm cho nó tĩnh, nó được tạo cho mỗi thể hiện của lớp (sử dụng bộ nhớ)

Do đó, khi bạn đang tạo một logger cho một singleton, bạn không cần phải làm cho nó tĩnh. Bởi vì sẽ chỉ có một ví dụ như vậy một logger.

Mặt khác, nếu bạn đang tạo một logger cho một mô hình hoặc lớp thực thể, bạn nên làm cho nó tĩnh để không tạo các logger trùng lặp.


-1

Bạn vẫn cần logger tĩnh cho các lớp tĩnh bên trong

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.