Ссылки на Spring Singletons, созданные в родительском контексте из дочернего контекста - PullRequest
3 голосов
/ 17 июня 2011

Трудно придумать название для этого!У меня есть боб, который инициализируется в контейнере пружины.Он загружает классы, которые также создают объекты из файлов, используя загрузчики классов Spring.Некоторые из этих объектов могут зависеть от дорогих объектов, и я хотел бы, чтобы эти объекты были инициализированы в родительском объекте.Хорошо, я не могу объяснить словами на упрощенном примере:

public class MainLoader {
    public static void main(String[] args) {
        XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("top-context.xml"));

        ChildLoader childLoader = (ChildLoader)beanFactory.getBean("childLoader");

        childLoader.loadChildAndDoSomething("message1.xml");
        childLoader.loadChildAndDoSomething("message2.xml");        
    }
}

public class ChildLoader {

    public void loadChildAndDoSomething(String childContextfile){       
        XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(childContextfile));
        ClassThatDoesStuff classThatDoesStuff = (ClassThatDoesStuff)beanFactory.getBean("classThatDoesStuff");  
        classThatDoesStuff.saySomething();
    }

}

public class ClassThatDoesStuff {
private ReallyExpensiveService reallyExpensiveService;  
private String messageStart;

public void saySomething(){
    System.out.println(messageStart + reallyExpensiveService.getName());
}

    // .. field setters removed for brevity
}

public class ReallyExpensiveService {
public String getName(){
    return "Joe";
}
}

У них есть следующие компоненты в файлах:

top-context.xml:

<bean id="childLoader" class="com.mark.test.ChildLoader" />

message1.xml (message2.xml аналогично):

<bean id="classThatDoesStuff" class="com.mark.test.ClassThatDoesStuff">
    <property name="messageStart" value = "Hello! " />  
    <property name ="reallyExpensiveService" ref="theExpensiveserviceReference" />  
</bean>
<bean id="theExpensiveserviceReference" class="com.mark.test.ReallyExpensiveService" />

При их запуске вы получите ожидаемое:

Hello! Joe
Goodbye! Joe

Единственная проблема здесь заключается в том, что "«Действительно, дорогой сервис» создается и кэшируется Spring каждый раз.Это подтверждается журналом.Лучше загружать любые сервисы, которые могут понадобиться классам "ClassThatDoesStuff" (представьте, что это интерфейс), когда инициализируется MainLoader.Т.е. (концептуально) изменить контекстные файлы пружины на:

top-context.xml:

<bean id="childLoader" class="com.mark.test.ChildLoader" />
<bean id="theExpensiveserviceReference" class="com.mark.test.ReallyExpensiveService" />

message1 / 2.xml

    <bean id="classThatDoesStuff" class="com.mark.test.ClassThatDoesStuff"
  autoWired="byType">   
        <property name="messageStart" value = "Hello! " />  
    </bean>

Я понимаю, чтоВыход из этого состоит в том, чтобы ClassThatDoeStuff имел установщик для службы и устанавливал значение из дочернего контейнера, который сам вводил его через основной контекст.Но представьте, что есть произвольные сервисы, и каждый из реализаторов ClassThatDoesStuff использовал разные. Есть ли способ, чтобы это работало в Spring?

Ответы [ 2 ]

1 голос
/ 17 июня 2011

Похоже, что лучшее, на что вы можете надеяться, - это один раз создать экземпляр каждой службы ReallyExoyService. (Вы упоминаете там, что вы не уверены, какой ClassThatDoesStuff может использовать другой.) Я бы, вероятно, попытался определить все мои bean-компоненты ReallyExoyService в контексте верхнего уровня, а затем раздать их классам, которые используют их, где это уместно. либо через файлы конфигурации XML, которые вы используете, либо через какую-то фабрику, которую вы внедрили в bean-компоненты ClassThatDoesStuff.

Вы также можете попытаться найти способ отложить дорогостоящие операции запуска ReallyExoyService до тех пор, пока вы не будете уверены, что они будут использоваться. Конечно, это зависит от того, что означает «дорогой». Это то, что сервисы используют слишком много памяти, и вы не хотите, чтобы они были рядом, если они не используются, или что их создание занимает слишком много времени?

В любом случае, ключевым моментом здесь является как можно меньшее количество экземпляров дорогих вещей, поэтому вам нужно будет настроить их на верхнем уровне, чтобы ссылки на отдельные экземпляры можно было передавать где угодно.

0 голосов
/ 20 июня 2011

Я много поиграл с этим и узнал много нового о весне.Я не думаю, что можно получить родительский весенний контекст для динамического применения этих свойств.Я обошел проблему, реализовав кеширование в объекте mainloader, чтобы дорогие типы не создавались многократно из определения Spring.

Другой возможностью, которую я исследовал, было информирование контекста ChildLoader и возможность использования ClassThatDoesStuff для использования ClassThatDoesStuff.родительский контекст, чтобы получить ручку на бобах, но весной это было слишком много для приложения, на мой взгляд.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...