2011-09-13 37 views
73

Câu hỏi có một chút lý thuyết, chi phí của việc tạo ra bối cảnh JAXB, marshaller và unmarshaller là gì?JAXB tạo bối cảnh và marshallers chi phí

Tôi nhận thấy rằng mã của tôi có thể hưởng lợi từ việc giữ cùng một bối cảnh JAXB và có thể cùng một trình soạn thảo cho tất cả các hoạt động marshaling thay vì tạo ngữ cảnh và marshaller trên mỗi marshaling.

Vậy chi phí của việc tạo ngữ cảnh JAXB và trình soạn thảo/unmarshaller là bao nhiêu? Có ổn không khi tạo bối cảnh + marshaller cho mỗi thao tác marshaling hoặc tốt hơn là tránh nó?

Trả lời

154

Lưu ý: Tôi là người lãnh đạo EclipseLink JAXB (MOXy) và là thành viên của nhóm chuyên gia JAXB 2 (JSR-222).

JAXBContext là chuỗi an toàn và chỉ nên được tạo một lần và được sử dụng lại để tránh chi phí khởi tạo siêu dữ liệu nhiều lần. MarshallerUnmarshaller không phải là chuỗi an toàn, nhưng có trọng lượng nhẹ để tạo và có thể được tạo cho mỗi hoạt động.

+5

câu trả lời hay. Bây giờ tôi có thể tự tin dựa trên kinh nghiệm của bạn với tư cách là khách hàng tiềm năng trên JAXB. – Vladimir

+6

Tôi tin tưởng bạn, nhưng điều này có được tìm thấy ở đâu đó trong tài liệu không? – Hurda

+2

Tài liệu dành cho RI: https://jaxb.java.net/guide/Performance_and_thread_safety.html (nhưng không phải Moxy AFAIK) – Caoilte

9

Thật đáng tiếc là điều này không được mô tả cụ thể trong javadoc. Những gì tôi có thể nói là Spring sử dụng một JAXBContext toàn cầu, được chia sẻ giữa các luồng, trong khi nó tạo ra một marshaller mới cho mỗi hoạt động marshalling, với mã số javadoc comment trong đó nói rằng JAXB marshallers không nhất thiết phải là thread-safe.

Điều tương tự cũng được nói trên trang này: http://jaxb.java.net/guide/Performance_and_thread_safety.html.

Tôi đoán rằng việc tạo JAXBContext là một hoạt động tốn kém, vì nó liên quan đến việc quét các lớp và gói cho các chú thích. Nhưng đo lường nó là cách tốt nhất để biết.

+0

Xin chào @ JB, câu trả lời tuyệt vời đặc biệt là các nhận xét của bạn về đo lường và tại sao JAXBContext lại tốn kém. – Vladimir

+1

Javadoc luôn yếu về các sự kiện quan trọng của _lifecycle_. Nó chắc chắn cung cấp cho chúng tôi sự lặp lại tầm thường của các getters & setters bất động sản, nhưng để biết làm thế nào/nơi để có được hoặc tạo ra một thể hiện, đột biến và thread-an toàn .. nó dường như hoàn toàn bỏ lỡ những yếu tố quan trọng nhất. Sigh :) –

29

Lý tưởng nhất, bạn nên có một singleton JAXBContext và các phiên bản địa phương là MarshallerUnmarshaller.

JAXBContext trường hợp được thread-an toàn trong khi MarshallerUnmarshaller trường hợp được không thread-safe và không bao giờ nên chia sẻ trên chủ đề.

+0

cảm ơn câu trả lời. Thật không may, tôi phải chọn chỉ một câu trả lời :-) – Vladimir

0

Tôi thường giải quyết các vấn đề như thế này với mẫu lớp học ThreadLocal. Với thực tế là bạn cần một marshaller khác nhau cho mỗi Class, bạn có thể kết hợp nó với một mẫu singleton -map.

Để giúp bạn tiết kiệm 15 phút, công việc. Sau đây tôi thực hiện một nhà máy an toàn cho Jaxb Marshallers và Unmarshallers.

Nó cho phép bạn truy cập các trường hợp như sau ...

Marshaller m = Jaxb.get(SomeClass.class).getMarshaller(); 
Unmarshaller um = Jaxb.get(SomeClass.class).getUnmarshaller(); 

Và mã bạn sẽ cần phải là một lớp JAXB nhỏ mà trông như sau:

public class Jaxb 
{ 
    // singleton pattern: one instance per class. 
    private static Map<Class,Jaxb> singletonMap = new HashMap<>(); 
    private Class clazz; 

    // thread-local pattern: one marshaller/unmarshaller instance per thread 
    private ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<>(); 
    private ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<>(); 

    // The static singleton getter needs to be thread-safe too, 
    // so this method is marked as synchronized. 
    public static synchronized Jaxb get(Class clazz) 
    { 
    Jaxb jaxb = singletonMap.get(clazz); 
    if (jaxb == null) 
    { 
     jaxb = new Jaxb(clazz); 
     singletonMap.put(clazz, jaxb); 
    } 
    return jaxb; 
    } 

    // the constructor needs to be private, 
    // because all instances need to be created with the get method. 
    private Jaxb(Class clazz) 
    { 
    this.clazz = clazz; 
    } 

    /** 
    * Gets/Creates a marshaller (thread-safe) 
    * @throws JAXBException 
    */ 
    public Marshaller getMarshaller() throws JAXBException 
    { 
    Marshaller m = marshallerThreadLocal.get(); 
    if (m == null) 
    { 
     JAXBContext jc = JAXBContext.newInstance(clazz); 
     m = jc.createMarshaller(); 
     marshallerThreadLocal.set(m); 
    } 
    return m; 
    } 

    /** 
    * Gets/Creates an unmarshaller (thread-safe) 
    * @throws JAXBException 
    */ 
    public Unmarshaller getUnmarshaller() throws JAXBException 
    { 
    Unmarshaller um = unmarshallerThreadLocal.get(); 
    if (um == null) 
    { 
     JAXBContext jc = JAXBContext.newInstance(clazz); 
     um = jc.createUnmarshaller(); 
     unmarshallerThreadLocal.set(um); 
    } 
    return um; 
    } 
} 
+8

ThreadLocal sẽ giới thiệu các vấn đề phụ khác, không có lợi ích. Chỉ cần giữ một JAXBContext duy nhất (đó là phần tốn kém) và tạo một Unmarshaller mới bất cứ khi nào cần thiết. – ymajoros

4

tôi giải quyết vấn đề này bằng chủ đề chia sẻ an toàn JAXBContext và sợi địa phương un/marschallers (do đó về mặt lý thuyết, sẽ có nhiều trường hợp un/marshaller vì có các chủ đề truy cập chúng) wi đồng bộ hóa thứ chỉ trên un/marshaller khởi tạo.

private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<Unmarshaller>() { 
    protected synchronized Unmarshaller initialValue() { 
     try { 
      return jaxbContext.createUnmarshaller(); 
     } catch (JAXBException e) { 
      throw new IllegalStateException("Unable to create unmarshaller"); 
     } 
    } 
}; 
private final ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<Marshaller>() { 
    protected synchronized Marshaller initialValue() { 
     try { 
      return jaxbContext.createMarshaller(); 
     } catch (JAXBException e) { 
      throw new IllegalStateException("Unable to create marshaller"); 
     } 
    } 
}; 

private final JAXBContext jaxbContext; 

private MyClassConstructor(){ 
    try { 
     jaxbContext = JAXBContext.newInstance(Entity.class); 
    } catch (JAXBException e) { 
     throw new IllegalStateException("Unable to initialize"); 
    } 
} 
+6

ThreadLocal sẽ giới thiệu các vấn đề khác, không có lợi. Chỉ cần giữ một JAXBContext duy nhất (đó là phần tốn kém) và tạo một Unmarshaller mới bất cứ khi nào cần thiết. – ymajoros

1

Thậm chí tốt hơn !! Dựa trên giải pháp tốt từ bài đăng ở trên, hãy tạo ngữ cảnh chỉ một lần trong hàm tạo và lưu nó thay vì lớp.

Thay thế dòng:

private Class clazz; 

với một này:

private JAXBContext jc; 

Và các nhà xây dựng chính với một này:

private Jaxb(Class clazz) 
    { 
    this.jc = JAXBContext.newInstance(clazz); 
    } 

như vậy trong getMarshaller/getUnmarshaller bạn có thể xóa dòng này:

JAXBContext jc = JAXBContext.newInstance(clazz); 

cải thiện này làm cho, trong trường hợp của tôi, đó là thời gian xử lý giảm từ 60 ~ 70ms xuống chỉ còn 5 ~ 10ms

+0

Tệp xml bạn phân tích cú pháp là bao nhiêu. Bạn có thấy cải thiện đáng kể với các tệp xml rất lớn không? – John

+0

nó không thực sự là một vấn đề của tập tin xml lớn (mỏ đi từ 2-3kb lên đến 6mb), nhưng thay vì một số lượng rất lớn của các tập tin xml (chúng tôi đang nói ở đây khoảng 10.000 xml yêu cầu mỗi phút) ; trong trường hợp đó tạo ra bối cảnh chỉ một lần đạt được những ms nhỏ này tạo nên sự khác biệt lớn – tbarderas

2

JAXB 2.2 (JSR-222) đã này để nói, trong phần "4.2 JAXBContext":

Để tránh chi phí liên quan đến việc tạo ra một cá thể JAXBContext, một ứng dụng JAXB là được khuyến khích sử dụng lại một trường hợp JAXBContext. An triển khai lớp trừu tượng JAXBContext được yêu cầu là an toàn chủ đề, do đó, nhiều luồng trong một ứng dụng có thể chia sẻ cá thể tương tự JAXBContext.

[..]

Lớp JAXBContext được thiết kế không thay đổi và do đó an toàn. Với số lượng xử lý động có khả năng có thể mất địa điểm khi tạo một phiên bản mới của JAXBContxt, đề nghị rằng một cá thể JAXBContext được chia sẻ qua các chủ đề và sử dụng lại như nhiều nhất có thể để cải thiện hiệu suất ứng dụng.

Thật không may, đặc điểm kỹ thuật không đưa ra bất kỳ khiếu nại nào về an toàn luồng của UnmarshallerMarshaller. Vì vậy, tốt nhất là giả sử họ không.

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