是否有"还原"到Spring @DependsOn注释?

时间:2017-06-09 09:05:37

标签: java spring spring-boot

我需要在另一个之前初始化一个Component。使用@DependsOn它看起来像这样:

@Component("beana")
public class BeanA{

    @PostConstruct
    void init(){
       // do smth
    }
}

@Component("beanb")
@DependsOn("beana")
public class BeanB{

    @PostConstruct
    void init(){
       // do smth
    }
}

我现在必须告诉BeanB它取决于BeanA的初始化。 我的问题是我不希望BeanB知道BeanAs存在(例如,当BeanB刚刚在EventBus中发布事件时初始化并且BeanA处理这些事件)。我想在BeanA上使用一个注释,说它应该在BeanB之前初始化。所以它会是这样的:

@Component("beana")
@RequiredBy("beanb") 
public class BeanA{

    @PostConstruct
    void init(){
       // do smth
    }
}

@Component("beanb")
public class BeanB{

    @PostConstruct
    void init(){
       // do smth
    }
}

是否有任何Spring注释或处理它的可能性?

2 个答案:

答案 0 :(得分:2)

我相信没有开箱即用的弹簧注释,但你可以轻松制作自己的注释。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RequiredBy {
    String[] value();
}

然后可以遍历所有bean定义并将dependsOn设置为该required bean。

@Component
public static class RequiredByBeanDefinitionPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        for (String beanName : registry.getBeanDefinitionNames()) {
            final BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
            if (beanDefinition.getBeanClassName() == null) {
                continue;
            }
            try {
                final Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());
                if (beanClass.isAnnotationPresent(RequiredBy.class)) {
                    final String[] dependantBeanNames = beanClass.getAnnotation(RequiredBy.class).value();
                    for (String dependantBeanName : dependantBeanNames) {
                        BeanDefinition dependantBeanDefinition = registry.getBeanDefinition(dependantBeanName);
                        dependantBeanDefinition.setDependsOn(beanName);
                    }
                }
            }
            catch (ClassNotFoundException e) { throw new RuntimeException(e); }
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { }
}

然后像你的例子一样使用它:

@Component("beanA")
public static class BeanA {
    @PostConstruct
    private void init() {
        System.out.println(this.getClass().getSimpleName());
    }
}

@Component("beanB")
@RequiredBy({ "beanC", "beanA" })
public static class BeanB {
    @PostConstruct
    private void init() {
        System.out.println(this.getClass().getSimpleName());
    }
}

@Component("beanC")
@RequiredBy("beanA")
public static class BeanC {
    @PostConstruct
    private void init() {
        System.out.println(this.getClass().getSimpleName());
    }
}

=&GT;

BeanB
BeanC
BeanA

答案 1 :(得分:0)

您可以按照pvpkiran的建议使用@Order注释。

您的代码看起来像这样:

System.Data.Services.Client.DataServiceQueryException: An error occurred 
while processing this request. ---> 
System.Data.Services.Client.DataServiceClientException: <?xml version="1.0" 
encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code></code>
<message xml:lang="en-US">Type 'WebService.OData.EntityClasses.Container_E' does not have a property named 'Monitored'.</message>
</error> at System.Data.Services.Client.QueryResult.ExecuteQuery() at  System.Data.Services.Client.DataServiceRequest.Execute[TElement] DataServiceContext context, QueryComponents queryComponents)--- End of inner exception stack trace --- at 
System.Data.Services.Client.DataServiceRequest.Execute[TElement]
(DataServiceContext context, QueryComponents queryComponents) at System.Data.Services.Client.DataServiceQuery`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)