2017-02-02 36 views
1

我是Spring的新手,我需要將CDI類轉換爲Spring。CDI實例的春季等價物

我有下面的代碼在CDI

@Inject 
private Instance<HealthCheck> healthChecks; 

然後我遍歷健康檢查。

我發現了一個類似的問題What is the Spring equivalent for CDI's Instance, or Guices Provider,它被建議使用

@Inject 
Provider<MyObject> myObjectInstance; 
//... 
MyObject myObjectInstance.get(); 

然而,由於供應商不實現可迭代的,我不能夠進行迭代。

有人可以請我幫助我如何將CDI代碼塊轉換爲彈簧。

+0

只需創建一個字段上鍵入'名單'和'耳光@ Autowired'。 –

回答

1

創建META-INF內的新文件spring.factories有以下內容:

org.springframework.context.ApplicationContextInitializer=package_name.CustomApplicationContextInitializer 

,或者你可以像你的JUnit測試使用它:

@SpringApplicationConfiguration(initializers = CustomApplicationContextInitializer.class) 

現在你可以使用像:

@Autowired 
private Instance<HealthCheck> healthChecks; 

CustomApplicationContextInitializer.class

public class CustomApplicationContextInitializer implements 
     ApplicationContextInitializer<ConfigurableApplicationContext> { 

    @Override 
    public void initialize(ConfigurableApplicationContext applicationContext) { 

     // Configure custom CustomAutowireCandidateResolver to handle CDI 
     // Instance<T> dependency requests 
     DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); 
     beanFactory.setAutowireCandidateResolver(new CustomAutowireCandidateResolver()); 
    } 
} 

CustomAutowireCandidateResolver.class

import java.lang.annotation.Annotation; 
import java.util.Arrays; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 
import java.util.stream.Collectors; 

import javax.annotation.Priority; 
import javax.enterprise.inject.Instance; 
import javax.enterprise.util.TypeLiteral; 

import org.springframework.beans.factory.DisposableBean; 
import org.springframework.beans.factory.ListableBeanFactory; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.beans.factory.config.DependencyDescriptor; 
import org.springframework.beans.factory.support.BeanDefinitionRegistry; 
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver; 
import org.springframework.core.annotation.Order; 
import org.springframework.util.ClassUtils; 

public class CustomAutowireCandidateResolver extends ContextAnnotationAutowireCandidateResolver { 

    static final boolean IS_CDI_INSTANCE_CLASS_PRESENT = ClassUtils.isPresent("javax.enterprise.inject.Instance", null); 

    @Override 
    public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) { 

     if (IS_CDI_INSTANCE_CLASS_PRESENT && Instance.class.equals(descriptor.getDependencyType())) { 

      // TODO refactor getLazyResolutionProxyIfNecessary to allow to 
      // customize lazy dependency resolution for Instance<T> 
      return getInstanceAdapterFor(descriptor); 
     } 

     return super.getLazyResolutionProxyIfNecessary(descriptor, beanName); 
    } 

    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    private Object getInstanceAdapterFor(DependencyDescriptor descriptor) { 

     ListableBeanFactory listableBeanFactory = (ListableBeanFactory) getBeanFactory(); 
     BeanDefinitionRegistry registry = (BeanDefinitionRegistry) listableBeanFactory; 

     // Instance<TargetType> 
     Class targetType = descriptor.getResolvableType().getGeneric(0).getRawClass(); 
     Map<String, Object> beansOfType = listableBeanFactory.getBeansOfType(targetType); 

     List<Bean> beansInstances = beansOfType.entrySet().stream() // 
       .map(e -> new Bean(e.getValue(), registry.getBeanDefinition(e.getKey()).isPrimary()))// 
       .collect(Collectors.toList()); 

     Annotation[] qualifiers = retainQualifierAnnotations(descriptor.getAnnotations()); 

     Beans beans = new Beans(targetType, beansInstances); 
     return qualifiers.length == 0 ? beans : beans.select(qualifiers); 
    } 

    private Annotation[] retainQualifierAnnotations(Annotation[] annotations) { 
     return Arrays.stream(annotations) // 
       .filter(a -> a.annotationType().isAnnotationPresent(Qualifier.class)) // 
       .toArray(Annotation[]::new); 
    } 

    static class Beans<T> implements Instance<T> { 

     private final List<Bean> beans; 
     private final Class<?> type; 

     public Beans(Class<?> type, List<Bean> beans) { 
      this.type = type; 
      this.beans = beans; 
     } 

     protected List<Bean> getBeans() { 
      return beans; 
     } 

     @Override 
     public T get() { 
      return (T) findDefaultInstance(); 
     } 

     protected Object findDefaultInstance() { 

      List<Bean> beans = getBeans(); 

      if (beans.size() == 1) { 
       return beans.get(0).getInstance(); 
      } 

      Object highestPrioBean = returnPrimaryOrHighestPriorityBean(beans); 

      if (highestPrioBean != null) { 
       return highestPrioBean; 
      } 

      // TODO figure out a sane default to use here - maybe throw an 
      // exception? 
      return beans.get(0).getInstance(); 
     } 

     private Object returnPrimaryOrHighestPriorityBean(List<Bean> beans) { 

      long highestPriority = Integer.MIN_VALUE; 
      Object highestPrioBean = null; 

      for (Bean bean : beans) { 

       if (bean.isPrimary()) { 
        return bean.getInstance(); 
       } 

       // TODO figure out to retrieve order from BeanDefinition/
       // BeanDeclaration 

       Object instance = bean.getInstance(); 
       Order order = instance.getClass().getAnnotation(Order.class); 
       if (order != null) { 
        if (order.value() > highestPriority) { 
         highestPriority = order.value(); 
         highestPrioBean = instance; 
        } 
       } 

       Priority priority = instance.getClass().getAnnotation(Priority.class); 
       if (priority != null) { 
        if (priority.value() > highestPriority) { 
         highestPriority = priority.value(); 
         highestPrioBean = instance; 
        } 
       } 
      } 

      return highestPrioBean; 
     } 

     @Override 
     @SuppressWarnings("unchecked") 
     public Instance<T> select(Annotation... qualifiers) { 
      return select((Class<T>) type, qualifiers); 
     } 

     @Override 
     public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers) { 
      return new Beans<U>(subtype, filterBeans(subtype, qualifiers)); 
     } 

     protected List<Bean> filterBeans(Class<?> subtype, Annotation... qualifiers) { 

      List<Annotation> requiredQualifiers = Arrays.asList(qualifiers); 

      return getBeans().stream() // 
        .filter(bean -> subtype.isInstance(bean.getInstance())) // 
        .filter(bean -> bean.getAnnotations().containsAll(requiredQualifiers)) // 
        .collect(Collectors.toList()); 
     } 

     @Override 
     public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers) { 

      // TODO implement (Class<U> subtype, Annotation... qualifiers) via 
      // select(TypeLiteral<U> subtype, Annotation... qualifiers) 
      return select(subtype.getRawType(), qualifiers); 
     } 

     @Override 
     public Iterator<T> iterator() { 
      return getBeans().stream().map(bean -> (T) bean.getInstance()).iterator(); 
     } 

     @Override 
     public boolean isUnsatisfied() { 
      return getBeans().isEmpty(); 
     } 

     @Override 
     public boolean isAmbiguous() { 
      return getBeans().size() > 1; 
     } 

     @Override 
     public void destroy(Object bean) { 

      if (bean instanceof DisposableBean) { 
       try { 
        ((DisposableBean) bean).destroy(); 
       } catch (Exception e) { 
        throw new RuntimeException(e); 
       } 
      } 
     } 
    } 

    static class Bean { 

     private final boolean primary; 
     private final Object instance; 
     private final List<Annotation> annotations; 

     public Bean(Object instance, boolean primary) { 
      this.primary = primary; 
      this.instance = instance; 
      this.annotations = Arrays.asList(instance.getClass().getAnnotations()); 
     } 

     public Object getInstance() { 
      return instance; 
     } 

     public boolean isPrimary() { 
      return primary; 
     } 

     public List<Annotation> getAnnotations() { 
      return annotations; 
     } 
    } 
} 

這裏充滿源鏈接:https://github.com/thomasdarimont/spring-boot-cdi-instance-example