jjzjj

java - 是否可以保证@PostConstruct方法的调用顺序?

coder 2023-05-11 原文

我有一个使用Spring进行依赖注入(inject)的系统。我使用基于注释的 Autowiring 。 Bean是通过组件扫描发现的,即我的上下文XML包含以下内容:

<context:component-scan base-package="org.example"/>

我在下面创建了一个点头示例来说明我的问题。

有一个Zoo,它是Animal对象的容器。 Zoo的开发人员在开发Animal时不知道将包含哪些Zoo对象;由Spring实例化的具体Animal对象集在编译时是已知的,但是存在各种构建配置文件,导致生成了不同的Animal集,在这种情况下Zoo的代码不得更改。
Zoo的目的是允许系统的其他部分(在此处显示为ZooPatron)在运行时访问Animal对象集,而无需显式依赖某些Animal

实际上,具体的Animal类将全部由各种Maven工件提供。我希望能够仅通过包含这些具体Animal的各种工件来组合项目的发行版,并在编译时正确地 Autowiring 一切。

我试图通过使各个Animal依赖于Zoo来解决这个问题(未成功),以便他们可以在Zoo期间在@PostConstruct上调用注册方法。这避免了Zoo显式依赖于Animal的显式列表。

这种方法的问题在于,仅当所有Zoo已注册时,Animal的客户才希望与其进行交互。在编译时已知有一组有限的Animal,注册全部发生在我生命周期的Spring接线阶段,因此订阅模型应该是不必要的(即,我不希望将Animal添加到Zoo在运行时)。

不幸的是,Zoo的所有客户仅依赖Zoo。这与AnimalZoo的关系完全相同。因此,@PostConstructAnimalZooPatron方法以任意顺序调用。下面的示例代码对此进行了说明-在@PostConstruct上调用ZooPatron时,尚未注册Animal,所有这些都在几毫秒后注册。

因此,这里有两种类型的依赖关系,我正在努力在Spring中表达。一旦所有Zoo都在其中,Animal的客户只想使用它。 (也许“方舟”会是一个更好的例子……)

我的问题基本上是:解决此问题的最佳方法是什么?

@Component
public class Zoo {

    private Set<Animal> animals = new HashSet<Animal>();

    public void register(Animal animal) {
        animals.add(animal);
    }

    public Collection<Animal> getAnimals() {
        return animals;
    }

}

public abstract class Animal {

    @Autowired
    private Zoo zoo;

    @SuppressWarnings("unused")
    @PostConstruct
    private void init() {
        zoo.register(this);
    }

    @Component
    public static class Giraffe extends Animal {
    }

    @Component
    public static class Monkey extends Animal {
    }

    @Component
    public static class Lion extends Animal {
    }

    @Component
    public static class Tiger extends Animal {
    }

}

public class ZooPatron {

    public ZooPatron(Zoo zoo) {
        System.out.println("There are " + zoo.getAnimals().size()
                             + " different animals.");
    }

}

@Component
public class Test {

    @Autowired
    private Zoo zoo;

    @SuppressWarnings("unused")
    @PostConstruct
    private void init() {
        new Thread(new Runnable() {
            private static final int ITERATIONS = 10;
            private static final int DELAY = 5;
            @Override
            public void run() {
                for (int i = 0; i<ITERATIONS; i++) {
                    new ZooPatron(zoo);
                    try {
                        Thread.sleep(DELAY);
                    } catch (InterruptedException e) {
                        // nop
                    }
                }
            }
        }).start();     
    }

}

public class Main {

    public static void main(String... args) {
        new ClassPathXmlApplicationContext("/context.xml");
    }

}

输出:
There are 0 different animals.
There are 3 different animals.
There are 4 different animals.
There are 4 different animals.
... etc

接受的解决方案的说明

基本上,答案是:不,您不能保证@PostConstruct调用的顺序,而不必离开Spring外部或修改其行为。

真正的问题不是我想对@PostConstruct调用进行排序,这仅仅是依赖项表达不正确的征兆。

如果Zoo的使用者依赖于他,而Zoo反过来又取决于Animal,则一切正常。我的错误是我不希望Zoo依赖于Animal子类的显式列表,因此引入了这种注册方法。正如答案中指出的那样,如果没有不必要的复杂性,将自注册机制与依赖项注入(inject)混合在一起将永远无法工作。

答案是声明Zoo依赖于Animal的集合,然后允许Spring通过 Autowiring 来填充该集合。

因此,没有收集成员的硬列表,它们是由Spring发现的,但是正确表达了依赖关系,因此@PostConstruct方法按我想要的顺序发生。

感谢您的出色回答。

最佳答案

您可能反而将动物组@Inject编入了Zoo。

@Component
public class Zoo {

    @Inject
    private Set<Animal> animals = new HashSet<Animal>();

    // ...
}

然后,只有在注入(inject)所有动物后,才应调用Zoo的@PostConstruct。唯一的难题是系统中至少必须有一个动物,但这听起来不应该是一个问题。

关于java - 是否可以保证@PostConstruct方法的调用顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7066683/

有关java - 是否可以保证@PostConstruct方法的调用顺序?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  6. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  7. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  8. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  9. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  10. ruby - Highline 询问方法不会使用同一行 - 2

    设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案

随机推荐