在这种情况下,我希望查找带有给定注释的接口,然后检查是否有匹配的实现可用。如果不是,我想提供一个bean,它实际上是接口的JDK代理,本质上是这样的:
@ConditionalOnMissingBean 就可以了,除非没有为其中的每一个写一个工厂方法。
我有“有时”工作的代码--它似乎对类加载器结构非常敏感,具体而言,是否类是从弹靴胖jar加载的(工作),或者是否某些部分是从单独的类路径条目加载的(大多数情况下不起作用)。
以下是我正在做的事情:
@Service
@Order(value = Ordered.LOWEST_PRECEDENCE)
public class RemotingImportService implements BeanFactoryPostProcessor {
private static Log log = LogFactory.getLog(RemotingExportService.class);
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// scan classpath with classgraph, then:
for (ClassInfo classInfo : scanResult.getClassesWithAnnotation(MyAnnotation.class.getCanonicalName())) {
Class c = Class.forName(classInfo.getName());
if(beanFactory.getBeanNamesForType(c).length > 0) {
implFound = true;
log.info(c.getName()+" already has an implementation ... skipping");
continue;
}
// create proxy, then:
GenericBeanDefinition bdService = new GenericBeanDefinition();
bdService.setBeanClassName(classInfo.getName());
bdService.setInstanceSupplier(new ProxySupplier(proxy));
bdService.setLazyInit(true);
((DefaultListableBeanFactory) beanFactory).registerBeanDefinition(classInfo.getName(), bdService);
log.info(c.getName()+" has NO implementation ... proxy registerd");
}在某些情况下,豆瓣工厂似乎还没有完成,而且
beanFactory.getBeanNamesForType() 返回一个空列表,尽管它稍后会为该类型找到bean。我知道,处理这个问题可能并不理想--但最好能找到一种解决方案,它可以很好地处理弹簧引导。
对如何解决这个问题有什么建议吗?将bean定义标记为"ConditionalOnMissingBean“的方法也很棒。
发布于 2019-10-21 11:39:19
您应该使用BeanPostProcessor而不是BeanFactoryPostProcessor
BeanPostProcessor是通过组装bean操作的,而BeanFactoryPostProcessor则使用原始bean定义。阅读更多这里
public class ConditionalOnMissingProcessor implements BeanPostProcessor, Ordered, ApplicationContextAware
{
private static final Logger LOG = Logger.getLogger(ConditionalOnMissingProcessor .class);
private ApplicationContext applicationContext;
// Ordering to last in chain.
@Override
public int getOrder()
{
return Ordered.LOWEST_PRECEDENCE;
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
/**
* Process each bean and inject proxy objects in fields marked with: {@ConditionalOnMissingBean}
*/
@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException
{
LOG.debug("Processing bean: " + beanName);
final Class clazz = bean.getClass();
ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback()
{
@Override
public void doWith(final Field field)
{
try
{
if(field.isAnnotationPresent(ConditionalOnMissingBean.class))
{
ReflectionUtils.makeAccessible(field);
final String beanFieldName = field.getName();
...
// Find proper implementation in application context
// Or create a proxy.
// Inject proxy or impl into a bean
field.set(bean, <value>));
}
}
catch(IllegalAccessException e)
{
LOG.error("Cannot set " + field.getName() + " in " + beanName, e);
}
}
});
return bean;
}UPD:
首先,我必须指出您的IMHO(IMHO)的缺点:-您正在尝试扫描类路径以使用@RemoteEndpoint注释查找所有接口,如果当前的应用程序上下文不包含实现该接口的bean --创建一个代理bean。但是,如果我说,并不是所有标记为@RemoteEndpoint的接口都应该被考虑进去呢?开发人员应该显式地标记这些接口,然后您可以创建所有需要的bean(例如,开发人员创建一个公共服务库)。-在用@RemotingEndpoint(value=RandomService.class)注释标记impl类时,可能是指定了红色信息。您已经提到过,当您实现时,会有一个接口。
有多种方法来实现您的想法。
@Autowired。
优点:- simply check all bean fields for presence of your custom annotation, and inject dependency (proxy or impl), using `BeanPostProcessor`.缺点:
- developer should mark all bean dependencies with custom annotation;
- it won't work if developer would have to obtain new dependencies at runtime.
@Autowired和@Value注释注入远程服务代理--在本例中--您应该使用BeanFactoryPostProcessor (正如您已经尝试过的那样)。您必须遍历所有bean定义,收集必须注册的远程服务代理的字段名和接口的映射(依赖项元信息)。下一步是使用依赖项元信息创建和注册bean (只有在上下文中没有实现bean的情况下才创建新的bean)。春天以后会把那些田里弄得水汪汪的。但是,这些依赖项应该是单例bean。
优点:- no mess with custom annotations;
- works at runtime缺点:
- proxies are singletons (you need prototypes as diagram displayed).
@Autowired和@Value注释和BeanFactoryPostProcessor,但是不需要注册新bean,您应该为每个接口@RemoteEndpoint注册一个FactoryBean。
优点:- no mess with custom annotations.
- works at runtime
- prototype-scoped proxies
https://stackoverflow.com/questions/58484759
复制相似问题