2014-11-21 14 views
25

वसंत Profile एनोटेशन आपको प्रोफाइल का चयन करने की अनुमति देता है। हालांकि यदि आप दस्तावेज़ पढ़ते हैं तो यह आपको केवल एक से अधिक प्रोफ़ाइल का चयन करने के लिए या ऑपरेशन के साथ चुनने की अनुमति देता है। यदि आप @Profile ("ए", "बी" निर्दिष्ट करते हैं) तो यदि आपका प्रोफ़ाइल ए या प्रोफाइल बी सक्रिय है तो आपका बीन ऊपर जाएगा।वसंत: प्रोफाइल और प्रोफाइल में कैसे करें?

हमारा उपयोग मामला अलग है हम एकाधिक विन्यास के परीक्षण और प्रोडी संस्करणों का समर्थन करना चाहते हैं। इसलिए कभी-कभी हम केवल बीन को स्वचालित करना चाहते हैं यदि दोनों प्रोफाइल टेस्ट और CONFIG1 सक्रिय हैं।

क्या वसंत के साथ ऐसा करने का कोई तरीका है? सबसे आसान तरीका क्या होगा?

+1

दस्तावेज़ों में अच्छी तरह से '@//' व्यवहार के रूप में उल्लेख किया गया है '@profile ("a", "b") '। क्या आप वह नहीं ढूंढ रहे हैं? दस्तावेज़ - 'इसी तरह, यदि @ कॉम्पोनेंट या @ कॉन्फ़िगरेशन क्लास को @ प्रोफाइल ({"पी 1", "पी 2"} के साथ चिह्नित किया गया है), तब तक उस श्रेणी को पंजीकृत/संसाधित नहीं किया जाएगा जब तक प्रोफाइल' पी 1 'और/या' पी 2 ' सक्रिय किया गया। –

+0

@JavaBond जिसका अर्थ है कि यह "OR" ऑपरेटर है और नहीं "AND"। वे सिर्फ स्पष्ट रूप से इंगित करना चाहते थे कि यह अनन्य नहीं है या (xor) – Artem

+0

मैंने प्रोफ़ाइल एनोटेशन के लिए "AND" ऑपरेटर का समर्थन करने के लिए स्प्रिंग स्रोत के लिए टिकट खोला: https://jira.spring.io/browse/SPR-12458 – Artem

उत्तर

19

चूंकि वसंत बॉक्स से बाहर और सुविधा प्रदान नहीं करता है। मैं निम्नलिखित रणनीति का सुझाव दूंगा:

वर्तमान में @Profile एनोटेशन में सशर्त एनोटेशन @Conditional(ProfileCondition.class) है। ProfileCondition.class में यह प्रोफाइल के माध्यम से पुनरावृत्त करता है और जांच करता है कि प्रोफ़ाइल सक्रिय है या नहीं। इसी प्रकार आप अपना सशर्त कार्यान्वयन बना सकते हैं और बीन को पंजीकृत करना प्रतिबंधित कर सकते हैं। जैसे

public class MyProfileCondition implements Condition { 

    @Override 
    public boolean matches(final ConditionContext context, 
      final AnnotatedTypeMetadata metadata) { 
     if (context.getEnvironment() != null) { 
      final MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); 
      if (attrs != null) { 
       for (final Object value : attrs.get("value")) { 
        final String activeProfiles = context.getEnvironment().getProperty("spring.profiles.active"); 

        for (final String profile : (String[]) value) { 
         if (!activeProfiles.contains(profile)) { 
          return false; 
         } 
        } 
       } 
       return true; 
      } 
     } 
     return true; 
    } 

} 

अपनी कक्षा में:

@Component 
@Profile("dev") 
@Conditional(value = { MyProfileCondition.class }) 
public class DevDatasourceConfig 

नोट: मैं सभी कोने मामलों के लिए जांच न की हो (शून्य की तरह, लंबाई चेकों आदि)। लेकिन, यह दिशा मदद कर सकती है। @Mithun जवाब का

+0

और एक्सएमएल कॉन्फ़िगरेशन के साथ इसे कैसे पूरा किया जाए? –

+1

धन्यवाद! मेरे उत्तर में थोड़ा सा कोड सुधार गया। –

7

थोड़ा सा सुधार हुआ संस्करण:

public class AndProfilesCondition implements Condition { 

public static final String VALUE = "value"; 
public static final String DEFAULT_PROFILE = "default"; 

@Override 
public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) { 
    if (context.getEnvironment() == null) { 
     return true; 
    } 
    MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); 
    if (attrs == null) { 
     return true; 
    } 
    String[] activeProfiles = context.getEnvironment().getActiveProfiles(); 
    String[] definedProfiles = (String[]) attrs.getFirst(VALUE); 
    Set<String> allowedProfiles = new HashSet<>(1); 
    Set<String> restrictedProfiles = new HashSet<>(1); 
    for (String nextDefinedProfile : definedProfiles) { 
     if (!nextDefinedProfile.isEmpty() && nextDefinedProfile.charAt(0) == '!') { 
      restrictedProfiles.add(nextDefinedProfile.substring(1, nextDefinedProfile.length())); 
      continue; 
     } 
     allowedProfiles.add(nextDefinedProfile); 
    } 
    int activeAllowedCount = 0; 
    for (String nextActiveProfile : activeProfiles) { 
     // quick exit when default profile is active and allowed profiles is empty 
     if (DEFAULT_PROFILE.equals(nextActiveProfile) && allowedProfiles.isEmpty()) { 
      continue; 
     } 
     // quick exit when one of active profiles is restricted 
     if (restrictedProfiles.contains(nextActiveProfile)) { 
      return false; 
     } 
     // just go ahead when there is no allowed profiles (just need to check that there is no active restricted profiles) 
     if (allowedProfiles.isEmpty()) { 
      continue; 
     } 
     if (allowedProfiles.contains(nextActiveProfile)) { 
      activeAllowedCount++; 
     } 
    } 
    return activeAllowedCount == allowedProfiles.size(); 
} 

} 

टिप्पणी में यह पोस्ट करने में असमर्थ था।

5

आप पहले से ही एक विन्यास वर्ग या @Profile टिप्पणी के साथ सेम विधि में चिह्नित किया है, तो यह Environment.acceptsProfiles()

@Autowired Environment env; 

@Profile("profile1") 
@Bean 
public MyBean myBean() { 
    if(env.acceptsProfiles("profile2")) { 
     return new MyBean(); 
    } 
    else { 
     return null; 
    } 
} 
6

साथ अतिरिक्त प्रोफ़ाइल (उदाहरण AND शर्त) के लिए जाँच करने के लिए एक और विकल्प पर खेलने के लिए है सरल है @Profile एनोटेशन द्वारा अनुमत कक्षा/विधि स्तर। MyProfileCondition को कार्यान्वित करने के रूप में लचीला नहीं है, लेकिन यह आपके मामले के अनुरूप होने पर त्वरित और साफ है।

उदा। इस शुरू कर देंगे नहीं जब फास्ट & देव दोनों सक्रिय हैं, लेकिन होगा यदि केवल देव है:

@Configuration 
@Profile("!" + SPRING_PROFILE_FAST) 
public class TomcatLogbackAccessConfiguration { 

    @Bean 
    @Profile({SPRING_PROFILE_DEVELOPMENT, SPRING_PROFILE_STAGING}) 
    public EmbeddedServletContainerCustomizer containerCustomizer() { 
5

मैं के बाद से है कि इसका जवाब इस तथ्य के लिए खाते में नहीं था @ rozhoc के जवाब में सुधार हुआ है कि कोई प्रोफ़ाइल 'डिफ़ॉल्ट' के बराबर है जब @Profile का उपयोग करने की बात आती है। साथ ही, जो शर्तें मैं चाहता था वे !default && !a थीं जो @ rozhoc का कोड ठीक से संभाल नहीं था। अंत में मैंने कुछ जावा 8 का उपयोग किया और ब्रेवटी के लिए केवल matches विधि दिखाएं।

@Override 
public boolean matches(final ConditionContext context, final AnnotatedTypeMetadata metadata) { 
    if (context.getEnvironment() == null) { 
     return true; 
    } 
    MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName()); 
    if (attrs == null) { 
     return true; 
    } 

    Set<String> activeProfilesSet = Arrays.stream(context.getEnvironment().getActiveProfiles()).collect(Collectors.toSet()); 
    String[] definedProfiles = (String[]) attrs.getFirst(VALUE); 
    Set<String> allowedProfiles = new HashSet<>(1); 
    Set<String> restrictedProfiles = new HashSet<>(1); 
    if (activeProfilesSet.size() == 0) { 
     activeProfilesSet.add(DEFAULT_PROFILE); // no profile is equivalent in @Profile terms to "default" 
    } 
    for (String nextDefinedProfile : definedProfiles) { 
     if (!nextDefinedProfile.isEmpty() && nextDefinedProfile.charAt(0) == '!') { 
      restrictedProfiles.add(nextDefinedProfile.substring(1, nextDefinedProfile.length())); 
      continue; 
     } 
     allowedProfiles.add(nextDefinedProfile); 
    } 
    boolean allowed = true; 
    for (String allowedProfile : allowedProfiles) { 
     allowed = allowed && activeProfilesSet.contains(allowedProfile); 
    } 
    boolean restricted = true; 
    for (String restrictedProfile : restrictedProfiles) { 
     restricted = restricted && !activeProfilesSet.contains(restrictedProfile); 
    } 
    return allowed && restricted; 
} 

यहाँ कैसे आप वास्तव में ऐसा होता है कि रूप में अच्छी तरह भ्रामक था में इसका इस्तेमाल होता है:

@Profile({"!default", "!a"}) 
@Conditional(value={AndProfilesCondition.class}) 
+0

रोज़ोक, रोज़ोक प्लस नहीं। –

+0

अरे काम किया। जीतना! – sbzoom

2

चाल का एक अन्य प्रकार है, लेकिन कई स्थितियों में काम कर सकते हैं @Configuration और दूसरे पर @Profile एनोटेशन डाल दिया है @Bean पर @Profile - जो जावा-आधारित वसंत कॉन्फ़िगरेशन में लॉजिकल और 2 प्रोफाइल के बीच बनाता है।

@Configuration 
@Profile("Profile1") 
public class TomcatLogbackAccessConfiguration { 

    @Bean 
    @Profile("Profile2") 
    public EmbeddedServletContainerCustomizer containerCustomizer() { 
संबंधित मुद्दे