2012-05-19 25 views
94

Trong trường hợp của Proxy Design Pattern, sự khác nhau giữa JDK's Dynamic Proxy và API tạo mã động bên thứ ba chẳng hạn như CGLib là gì?Sự khác biệt giữa JDK proxy động và CGLib là gì?

Sự khác biệt giữa việc sử dụng cả hai phương pháp tiếp cận và khi nào nên thích cái nào hơn phương pháp tiếp cận khác?

+3

Lấy mã tại đây: . Trong cglib bạn có thể tạo cả proxy lớp và proxy giao diện. Spring sử dụng CGlib theo mặc định trong khi AspectJ sử dụng Java proxy. Đọc phần này: http://jnb.ociweb.com/jnb/jnbNov2005.html;) –

Trả lời

127

JDK proxy động chỉ có thể proxy theo giao diện (vì vậy lớp đích của bạn cần triển khai giao diện, sau đó lớp này cũng được triển khai bởi lớp proxy).

CGLIB (và javassist) có thể tạo proxy theo phân lớp con. Trong trường hợp này, proxy trở thành một lớp con của lớp đích. Không cần giao diện.

proxy

Vì vậy, Java động có thể proxy: public class Foo implements iFoo nơi cglib thể proxy: public class Foo

EDIT:

tôi nên đề cập đến điều đó vì Javassist và cglib sử dụng proxy bằng cách subclassing, rằng đây là lý do bạn không thể tuyên bố chính thức phương pháp hoặc làm cho lớp cuối cùng khi sử dụng các khung dựa trên điều này. Điều đó sẽ ngăn các thư viện này cho phép phân lớp lớp của bạn và ghi đè lên các phương thức của bạn.

+0

tHANKS .. !! nhưng nó sẽ rất hữu ích nếu bạn có thể cho tôi một mã ví dụ (hoặc Link) để minh họa cách sử dụng của một người khác trong một số trường hợp .. !!! – KDjava

+3

Danh sách mã trên http://www.edc4it.com/2011/11/03/jpa-transactional-proxy-for-javase/ tạo một proxy bằng cách sử dụng javassist. Ở đây: http://www.edc4it.com/2011/03/01/using-run-time-bytecode-instrumentation-bci/ là một ví dụ sử dụng CGLib. Một ví dụ sử dụng Java Dynamic proxy có thể được tìm thấy http://docs.oracle.com/javase/1.3/docs/guide/reflection/proxy.html –

+0

mã CGLIB- http://www.edc4it.com/2011/03/01/sử dụng-chạy-thời gian-bytecode-instrumentation-bci/đã thực sự thú vị một và hữu ích quá .. Cảm ơn rất nhiều !! – KDjava

35

Sự khác biệt về chức năng

  • Các proxy JDK cho phép để thực hiện bất kỳ tập hợp các giao diện trong khi subclassing java.lang.reflect.Proxy. Bất kỳ phương thức giao diện nào, cùng với Object::hashCode, Object::equalsObject::toString sau đó được chuyển tiếp đến một số InvocationHandler.

  • cglib cho phép bạn triển khai bất kỳ bộ giao diện nào trong khi phân lớp bất kỳ lớp không phải cuối cùng nào. Ngoài ra, các phương pháp có thể được ghi đè tùy chọn, nghĩa là không phải tất cả các phương pháp không trừu tượng đều cần được chặn. Hơn nữa, có nhiều cách khác nhau để thực hiện một phương thức. Nó cũng cung cấp một lớp InvocationHandler (trong một gói khác), nhưng nó cũng cho phép gọi các phương thức siêu bằng cách sử dụng các trình chặn đánh chặn nâng cao hơn, ví dụ: MethodInterceptor. Hơn nữa, cglib có thể cải thiện hiệu năng bằng các trường hợp chặn đặc biệt như FixedValue. Tôi đã từng viết a summary of different interceptors for cglib.

khác biệt Performance

JDK proxy được thực hiện khá ngây thơ chỉ với một đánh chặn điều phối, các InvocationHandler. Điều này đòi hỏi một phương thức ảo gửi đến một thực thi mà không phải lúc nào cũng được inlined. Cglib cho phép tạo mã byte đặc biệt đôi khi có thể cải thiện hiệu suất. Dưới đây là một số so sánh để triển khai giao diện với 18 phương pháp sơ khai:

  cglib     JDK proxy 
creation 804.000  (1.899)  973.650  (1.624) 
invocation 0.002  (0.000)  0.005  (0.000) 

Thời gian được ghi chú bằng nano giây với độ lệch chuẩn trong niềng răng. Bạn có thể tìm thêm chi tiết về điểm chuẩn trong Byte Buddy's tutorial, trong đó Byte Buddy là một giải pháp thay thế hiện đại hơn cho cglib. Ngoài ra, lưu ý rằng cglib không còn được phát triển tích cực nữa.

+1

Tại sao tài liệu hướng dẫn mùa xuân ủng hộ JDK proxy trên cglib cho lợi ích hiệu suất của sau này? http://docs.spring.io/spring/docs/2.5.x/reference/aop.html#aop-proxying – P4ndaman

+1

Cglib là một phụ thuộc bên ngoài và hiện không được hỗ trợ. Dựa vào phần mềm của bên thứ ba luôn luôn là một canh bạc để tốt nhất của nó khi càng ít người càng tốt dựa vào nó. –

+0

* Điều này * phải là câu trả lời được chấp nhận! –

12

Proxy động: Triển khai động các giao diện khi chạy bằng cách sử dụng JDK Reflection API.

Ví dụ: Spring sử dụng proxy động cho các giao dịch như sau:

enter image description here

Proxy tạo ra trên đầu trang của đậu. Nó thêm hành vi xuyên quốc gia vào bean. Ở đây proxy tạo ra động tại thời gian chạy bằng cách sử dụng JDK Reflection API.

Khi ứng dụng bị dừng, proxy sẽ bị hủy và chúng tôi sẽ chỉ có giao diện và đậu trên hệ thống tệp.


Trong ví dụ trên, chúng tôi có giao diện. Nhưng trong hầu hết việc thực hiện giao diện thì không tốt nhất. Vì vậy, đậu không thực hiện một giao diện, trong trường hợp đó chúng ta sử dụng thừa kế:

enter image description here

Để tạo proxy như vậy, Spring sử dụng một thư viện của bên thứ ba được gọi là cglib.

cglib (C thơ ca ngợi G eneration Lib rary) được xây dựng trên đầu trang của ASM, điều này được sử dụng chủ yếu các tạo Proxy mở rộng đậu và thêm hành vi đậu trong các phương pháp proxy.

Examples for JDK Dynamic proxy and CGLib

Spring ref

0

From Spring documentation:

Spring AOP sử dụng hoặc JDK proxy động hoặc cglib để tạo ra các proxy cho một đối tượng mục tiêu nhất định. (JDK proxy động được ưa thích bất cứ khi nào bạn có một sự lựa chọn).

Nếu đối tượng đích được triển khai thực hiện ít nhất một giao diện thì proxy động JDK sẽ được sử dụng. Tất cả các giao diện được thực hiện bởi loại mục tiêu sẽ được ủy nhiệm. Nếu đối tượng đích không thực hiện bất kỳ giao diện nào thì proxy CGLIB sẽ được tạo.

Nếu bạn muốn buộc sử dụng proxy CGLIB (ví dụ, để proxy mọi phương thức được xác định cho đối tượng đích, không chỉ các phương thức được thực hiện bởi giao diện của nó), bạn có thể làm như vậy. Tuy nhiên, có một số vấn đề cần xem xét:

phương pháp cuối cùng không thể được thông báo, vì chúng không thể bị quá tải.

Bạn sẽ cần các tệp nhị phân CGLIB 2 trên đường dẫn lớp của mình, trong khi proxy động có sẵn với JDK. Spring sẽ tự động cảnh báo bạn khi cần CGLIB và các lớp thư viện CGLIB không được tìm thấy trên classpath.

Hàm tạo của đối tượng proxy của bạn sẽ được gọi hai lần. Đây là một hệ quả tự nhiên của mô hình proxy CGLIB, theo đó một lớp con được tạo ra cho mỗi đối tượng được ủy quyền. Đối với mỗi cá thể được ủy quyền, hai đối tượng được tạo: đối tượng được ủy quyền thực tế và một cá thể của lớp con thực hiện lời khuyên. Hành vi này không được trưng bày khi sử dụng các proxy JDK. Thông thường, gọi hàm khởi tạo của kiểu proxy hai lần, không phải là một vấn đề, vì thường chỉ có các phép gán diễn ra và không có logic thực được thực hiện trong hàm tạo.

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