我是Spring新手,我需要将CDI类转换为Spring。
我在CDI中有以下代码
@Inject
private Instance<HealthCheck> healthChecks;
然后我遍历healthChecks。
我发现了一个类似的问题What is the Spring equivalent for CDI's Instance, or Guices Provider,建议使用
@Inject
Provider<MyObject> myObjectInstance;
//...
MyObject myObjectInstance.get();
但是,由于提供程序不实现iterable,我无法迭代。
有人可以帮助我如何将CDI代码块转换为弹簧。
答案 0 :(得分:2)
在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