gpt4 book ai didi

java - Spring代理根据注释和运行时值选择实现

转载 作者:行者123 更新时间:2023-11-30 03:47:25 25 4
gpt4 key购买 nike

我想将接口(interface)的代理实现注入(inject)到组件中,然后让 spring 根据运行时属性(以及实现类中注释的值)选择正确的实现。所以我的组件不必关心选择正确的组件。

它有点像范围。但我认为作用域仅用于处理同一实现类的不同实例。我这样说有错吗?

我希望它可以针对任意接口(interface)运行,而无需为每个新服务创建服务定位器或其他一些构造。

这是一个示例。

假设我有一个定义服务的接口(interface)

package test;

public interface IService {
void doSomething();
}

和两个实现:

package test;

import javax.inject.Named;

@Named
@MyAnnotation("service1")
public class Service1 implements IService {

@Override
public void doSomething() {
System.out.println("this");
}
}

...

package test;

import javax.inject.Named;

@Named
@MyAnnotation("service2")
public class Service2 implements IService {

@Override
public void doSomething() {
System.out.println("that");
}
}

现在我想将 IService 注入(inject)另一个组件,并让 spring 根据一些可查询的运行时属性和 MyAnnotation 的值选择正确的实现。

有没有办法在 Spring 以通用的方式做到这一点?

编辑:

我有一个具有一定值(value)的上下文。在本例中它是本地线程。

package test;
public class MyValueHolder {

private static final ThreadLocal<String> value = new ThreadLocal<>();

public static void set(String newValue) {
value.set(newValue);
}

public static String get() {
return value.get();
}

public static void reset() {
value.remove();
}
}

我有一个使用 IService 的组件

package test;

import javax.inject.Inject;
import javax.inject.Named;

@Named
public class MyComponent {

@Inject
private IService service;

public void myImportantWorkflow(){

MyValueHolder.set("service1");
service.doSomething();

MyValueHolder.set("service2");
service.doSomething();
}
}

注入(inject)的服务应该只是一个代理。根据 MyValueHolder 中设置的值,对 doSomething 的调用应委托(delegate)给 service1 或 service2。因此,在此示例中,它应该在第一次调用中委托(delegate)给 service1 上的 doSomething,并在第二次调用中委托(delegate)给 service2 上的 doSomething。

我可以编写这样一个委托(delegate)器来实现IService 接口(interface),并将其用于这一服务。但随后我必须对其他所有服务重复此操作。我希望 spring 几乎可以自己用代理做这样的事情。当然,我必须提供一些方法来根据本地线程中保存的值查找bean并将其注册到spring。但我不知道在不修改 spring 框架的情况下这是否可能。如果可能的话如何实现这一点。

最佳答案

您可以使用 ProxyFactoryBean 创建代理,并使用 TargetSource 进行查找。

例如(未测试)

public class AnnotatedBeanTargetSource implements TargetSource, BeanFactoryAware {

private ConfigurableListableBeanFactory beanFactory;
private Class<? extends Annotation> annotationType;
private Class<?> implementedIterface;
private Map<String, Object> beans;

@Override
public Class<?> getTargetClass() {
return this.implementedIterface;
}

@Override
public boolean isStatic() {
return false;
}

@Override
public Object getTarget() throws Exception {
if (this.beans == null) {
this.beans = lookupTargets();
}

return this.beans.get(MyValueHolder.get());
}

protected Map<String, Object> lookupTargets() {
Map<String, Object> resolvedBeans = new HashMap<String, Object>();
String[] candidates = beanFactory.getBeanNamesForAnnotation(annotationType);
for (String beanName : candidates) {
Class<?> type = beanFactory.getType(beanName);

if (this.implementedIterface.isAssignableFrom(type)) {
Annotation ann = AnnotationUtils.getAnnotation(type, annotationType);
resolvedBeans.put((String) AnnotationUtils.getValue(ann), beanFactory.getBean(beanName));
}
}

return resolvedBeans;
}

@Override
public void releaseTarget(Object target) throws Exception {
// nothing to do
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;

}

public Class<? extends Annotation> getAnnotationType() {
return annotationType;
}

public void setAnnotationType(Class<? extends Annotation> annotationType) {
this.annotationType = annotationType;
}

public Class<?> getImplementedIterface() {
return implementedIterface;
}

public void setImplementedIterface(Class<?> implementedIterface) {
this.implementedIterface = implementedIterface;
}
}

关于java - Spring代理根据注释和运行时值选择实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25290935/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com