एकाधिक @ControllerAdvice @ExceptionHandlers की सेटिंग की स्थापना


83

मेरे पास गुणक कक्षाएं हैं @ControllerAdvice, जिनमें से प्रत्येक में एक @ExceptionHandlerविधि है।

एक Exceptionइस इरादे के साथ संभालता है कि यदि कोई अधिक विशिष्ट हैंडलर नहीं मिला है, तो इसका उपयोग किया जाना चाहिए।

अफसोस की बात है कि स्प्रिंग एमवीसी हमेशा Exceptionअधिक विशिष्ट लोगों ( IOExceptionउदाहरण के लिए ) के बजाय सबसे सामान्य मामले ( ) का उपयोग करता प्रतीत होता है ।

क्या यह उम्मीद है कि कोई स्प्रिंग एमवीसी के व्यवहार की उम्मीद करेगा? मैं जर्सी से एक पैटर्न का अनुकरण करने की कोशिश कर रहा हूं, जो प्रत्येक ExceptionMapper(समतुल्य घटक) का आकलन करता है कि यह निर्धारित करने के लिए कि वह जिस प्रकार को संभालता है वह उस अपवाद से है जो फेंक दिया गया है, और हमेशा निकटतम पूर्वज का उपयोग करता है।

जवाबों:


127

क्या यह उम्मीद है कि कोई स्प्रिंग एमवीसी के व्यवहार की उम्मीद करेगा?

स्प्रिंग 4.3.7 के अनुसार, यहां स्प्रिंग एमवीसी कैसे व्यवहार करता है: यह HandlerExceptionResolverहैंडलर विधियों द्वारा फेंके गए अपवादों को संभालने के लिए उदाहरणों का उपयोग करता है ।

डिफ़ॉल्ट रूप से, वेब MVC कॉन्फ़िगरेशन एक HandlerExceptionResolverबीन, ए HandlerExceptionResolverComposite, जो पंजीकृत करता है

अन्य की सूची में प्रतिनिधि HandlerExceptionResolvers

वे अन्य रिसोल्वर हैं

  1. ExceptionHandlerExceptionResolver
  2. ResponseStatusExceptionResolver
  3. DefaultHandlerExceptionResolver

उस क्रम में पंजीकृत है। इस प्रश्न के उद्देश्य के लिए हम केवल परवाह करते हैं ExceptionHandlerExceptionResolver

एक है AbstractHandlerMethodExceptionResolverकि @ExceptionHandlerतरीकों के माध्यम से अपवादों को हल करता है ।

संदर्भ आरंभीकरण में, स्प्रिंग ControllerAdviceBeanप्रत्येक @ControllerAdviceएनोटेट वर्ग के लिए उत्पन्न करेगा जो यह पता लगाता है। ExceptionHandlerExceptionResolverसंदर्भ से इन प्राप्त करेंगे, और उन्हें प्रयोग करने का उपयोग कर सॉर्ट AnnotationAwareOrderComparatorजो

का एक विस्तार है OrderComparatorकि वसंत के समर्थन करता है, Ordered और साथ ही इंटरफ़ेस @Orderऔर @Priority, एनोटेशन एक आदेश दिया उदाहरण एक स्थिर परिभाषित एनोटेशन मूल्य (यदि हो तो) अधिभावी द्वारा प्रदान की एक आदेश मूल्य के साथ।

इसके बाद ExceptionHandlerMethodResolverइनमें से प्रत्येक ControllerAdviceBeanउदाहरण के लिए पंजीकरण करना होगा (उपलब्ध @ExceptionHandlerतरीकों को अपवादित करने के लिए उपलब्ध तरीकों को मैप करना)। इन्हें अंत में उसी क्रम में जोड़ा जाता है a LinkedHashMap(जो पुनरावृति क्रम को संरक्षित करता है)।

जब कोई अपवाद होता है, तो ExceptionHandlerExceptionResolverवसीयत इन के माध्यम से पुनरावृत्ति करेगी ExceptionHandlerMethodResolverऔर पहले वाले का उपयोग करेगी जो अपवाद को संभाल सकती है।

यहां मुद्दा तो यह है: यदि आप एक है @ControllerAdviceएक साथ @ExceptionHandlerके लिए Exceptionहै कि एक और पहले पंजीकृत हो जाता है @ControllerAdviceएक साथ कक्षा @ExceptionHandlerएक अधिक विशिष्ट अपवाद की तरह के लिए IOException, कि पहले एक कहा जाता हो जाएगा। जैसा कि पहले उल्लेख किया गया है, आप अपने @ControllerAdviceएनोटेट वर्ग को लागू करने Orderedया उसके साथ एनोटेट करके @Orderया @Priorityउसे उचित मूल्य देकर उस पंजीकरण आदेश को नियंत्रित कर सकते हैं ।


5
इसके अलावा, @ExceptionHandlerएक के भीतर कई तरीकों के मामले में @ControllerAdvice, फेंके गए अपवाद के सबसे विशिष्ट सुपरक्लास को संभालने वाले को चुना जाता है।
विजय अग्रवाल

वसंत बूट में। यह एक अभिभावक नियंत्रक सलाह वर्ग से एक नियंत्रक सलाह ExceptionHandler विधि की अनदेखी उपवर्ग पर @ आदेश की आवश्यकता नहीं है
Vadiraj पुरोहित

93

Sotirios Delimanolis उनके जवाब में बहुत मददगार थी, आगे की जांच में हमने पाया कि, वसंत 3.2.4 में, वैसे भी, जो कोड @ControllerAdvice एनोटेशन की तलाश करता है, वह @Order एनोटेशन की उपस्थिति की भी जाँच करता है और कंट्रोलर AdviceBeans की सूची टाइप करता है।

@Order एनोटेशन के बिना सभी नियंत्रकों के लिए परिणामी डिफ़ॉल्ट आदेश # LOWEST_PRECEDENCE का आदेश दिया गया है, जिसका अर्थ है कि यदि आपके पास एक नियंत्रक है जिसे सबसे कम प्राथमिकता देने की आवश्यकता है, तो आपके सभी नियंत्रकों को एक उच्च क्रम रखने की आवश्यकता है।

यहां एक उदाहरण दिखाया गया है कि कैसे कंट्रोलर एडवाइस और ऑर्डर एनोटेशन के साथ दो अपवाद हैंडलर कक्षाएं हैं जो उपयोगकर्ताप्रोफ़ाइल अपवाद या RuntimeException होने पर उपयुक्त प्रतिक्रियाओं की सेवा कर सकते हैं।

class UserProfileException extends RuntimeException {
}

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
class UserProfileExceptionHandler {
    @ExceptionHandler(UserProfileException)
    @ResponseBody
    ResponseEntity<ErrorResponse> handleUserProfileException() {
        ....
    }
}

@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)
class DefaultExceptionHandler {

    @ExceptionHandler(RuntimeException)
    @ResponseBody
    ResponseEntity<ErrorResponse> handleRuntimeException() {
        ....
    }
}
  • नियंत्रक देखें। AdiceiceBean # initOrderFromBeanType ()
  • कंट्रोलर एडविज़न बीन # FindAnnotatedBeans () देखें
  • ExceptionHandlerExceptionResolver # initExceptionHandlerAdviceCache () देखें

का आनंद लें!


21

@Orderएनोटेशन का उपयोग करके अपवाद संचालकों के क्रम को बदला जा सकता है ।

उदाहरण के लिए:

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ControllerAdvice;

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomExceptionHandler {

    //...

}

@Orderकोई भी पूर्णांक मान हो सकता है।


5

मैंने दस्तावेज में यह भी पाया कि:

https://docs.spring.io/spring-framework/docs/4.3.4.RELEASE/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.html#getExceptionHandlerMethod-org.springframework। web.method.HandlerMethod-java.lang.Exception-

ExceptionHandlerMethod

संरक्षित सर्वइंटरएबलहैंडलर मैथोड getExceptionHandlerMethod (हैंडलरमैथोड हैंडलरमैथोड, अपवाद अपवाद)

दिए गए अपवाद के लिए एक @ExceptionHandler विधि खोजें। डिफ़ॉल्ट कार्यान्वयन पहले नियंत्रक के वर्ग पदानुक्रम में विधियों की खोज करता है और यदि नहीं मिला, तो यह कुछ @ControllerAdvice स्प्रिंग-प्रबंधित बीन्स का पता लगाने वाले अतिरिक्त @ExceptionHandler तरीकों की खोज जारी रखता है । पैरामीटर: हैंडलरमैथोड - वह विधि जहां अपवाद उठाया गया था (शून्य हो सकता है) अपवाद - उठाया अपवाद रिटर्न: अपवाद या अशक्त को संभालने के लिए एक विधि

तो इसका मतलब यह है कि यदि आप इस मुद्दे को हल करना चाहते हैं, तो आपको अपने अपवाद को फेंकने वाले नियंत्रक के भीतर अपने विशिष्ट अपवाद हैंडलर को जोड़ना होगा। ग्लोबल डिफॉल्ट अपवाद हैंडलर को संभालने वाले एक और केवल कंट्रोलर ऐड को परिभाषित करने के लिए एएनडी।

यह प्रक्रिया को सरल करता है और हमें समस्या से निपटने के लिए ऑर्डर एनोटेशन की आवश्यकता नहीं है।


2

ग्लोबल एक्सेप्शन हैंडलिंग नामक अनुभाग में, स्प्रिंग ब्लॉग पर उत्कृष्ट " एक्सेप्शन हैंडलिंग इन स्प्रिंग एमवीसी " पोस्ट में एक समान स्थिति को रूपांतरित किया गया है । उनके परिदृश्य में अपवाद कक्षा पर पंजीकृत ResponseStatus एनोटेशन के लिए जाँच शामिल है, और यदि मौजूद है, तो फ्रेमवर्क को संभालने के लिए अपवाद को फिर से जोड़ना। आप इस सामान्य रणनीति का उपयोग करने में सक्षम हो सकते हैं - यह निर्धारित करने का प्रयास करें कि क्या वहाँ से बाहर एक अधिक उपयुक्त हैंडलर हो सकता है और पुन: डूब सकता है।

वैकल्पिक रूप से, कुछ अन्य अपवाद हैंडलिंग रणनीतियों को कवर किया गया है जिन्हें आप इसके बजाय देख सकते हैं।


1

संभाला जाने वाला महत्वपूर्ण वर्ग:

**@Order(Ordered.HIGHEST_PRECEDENCE)**
public class FunctionalResponseEntityExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(FunctionalResponseEntityExceptionHandler.class);

    @ExceptionHandler(EntityNotFoundException.class)
    public final ResponseEntity<Object> handleFunctionalExceptions(EntityNotFoundException ex, WebRequest request)
    {
        logger.error(ex.getMessage() + " " + ex);
        ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.getMessage(),
                request.getDescription(false),HttpStatus.NOT_FOUND.toString());
        return new ResponseEntity<>(exceptionResponse, HttpStatus.NOT_FOUND);
    }
}

कम प्राथमिकता के साथ अन्य अपवाद

@ControllerAdvice
    public class GlobalResponseEntityExceptionHandler extends ResponseEntityExceptionHandler
    {
    private final Logger logger = LoggerFactory.getLogger(GlobalResponseEntityExceptionHandler.class);
    @ExceptionHandler(Exception.class)
    public final ResponseEntity<Object> handleAllException(Exception ex, WebRequest request)
    {
        logger.error(ex.getMessage()+ " " + ex);
        ExceptionResponse exceptionResponse= new ExceptionResponse(new Date(), ex.toString(),
                request.getDescription(false),HttpStatus.INTERNAL_SERVER_ERROR.toString());
    }
    }

0

तुम भी नीचे की तरह एक नंबर मूल्य का उपयोग कर सकते हैं

@Order(value = 100)

निचले मूल्यों में उच्च प्राथमिकता है। डिफ़ॉल्ट मान * {@code आदेशित। LOWEST_PRECEDENCE} है, जो सबसे कम प्राथमिकता (किसी भी अन्य * निर्दिष्ट आदेश मूल्य को खोने) को दर्शाता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.