Trong Java, tại sao cách khai báo logger tốt nhất static final
?
private static final Logger S_LOGGER
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:
private
- để không có lớp nào khác có thể chiếm quyền điều khiển logger của bạnstatic
- 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 loggerfinal
- không cần thay đổi logger trong suốt vòng đời của lớpNgoài ra, tôi thích tên log
cà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 Bar
kéo dài Foo
, cả hai sẽ đăng nhập vào Bar
logger. Một số tìm thấy nó trực quan hơn.
log
hơn tên hơn là phân tán mã LOG
. Chỉ là vấn đề của dev. thỏa thuận đội.
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.
static
có 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.
final
có nghĩa là bạn sẽ không thay đổi giá trị của logger
biế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.
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ị.
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 static
bit. 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 final
phát từ điểm mà bạn thường không thay đổi Logger
trong 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ộtLogger
theo 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.
Để 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 :)
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.
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 vulnerable
Bạn có thể làm rõ bạn trả lời một chút?
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.
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());
...
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:
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.