Spring DI - не инициализировать все зависимые бины - PullRequest
6 голосов
/ 14 ноября 2011

У меня есть ServiceA, который зависит от ServiceB.ServiceB происходит из файла подпружиненного компонента с lazy-init = true, т. Е. Я хочу, чтобы serviceB инициализировался только тогда, когда я запрашиваю этот компонент.

Однако я использую ServiceA во всем приложении и когдаинициализация ServiceB на основе инъекции инициализируется.

Я хочу, чтобы ServiceA не инициализировала ServiceB до тех пор, пока не будет вызван какой-либо метод в ServiceA, которому требуется ServiceB.Одним из способов сделать это было использование Аспектов , но я искал простейшее из возможных решений для этого, в частности, в весеннем XML-файле для serviceB или в некоторой аннотации в serviceB или в любом флаге прокси.Может кто-нибудь помочь?

Ответы [ 4 ]

6 голосов
/ 14 ноября 2011

Я думаю LazyInitTargetSource делает то, что вам нужно.

Полезно, когда при инициализации необходима ссылка на прокси, но фактический целевой объект не должен быть инициализирован до первого использования . Когда целевой компонент определяется в ApplicationContext (или в BeanFactory, которая с готовностью создает экземпляры одноэлементных компонентов), он также должен быть помечен как "lazy-init", иначе он будет создан указанным ApplicationContext (или BeanFactory) при запуске. 1009 *

1 голос
/ 17 апреля 2012

Другой подход, который вы, возможно, захотите попробовать, обсуждается на http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/aop/framework/autoproxy/target/LazyInitTargetSourceCreator.html:

[LazyInitTargetSourceCreator является] TargetSourceCreator, который применяет LazyInitTargetSource для каждого компонента это определяется как "ленивый-init". Это приведет к созданию прокси для каждый из этих бобов, позволяющий получить ссылку на такой боб без фактической инициализации экземпляра целевого компонента.

Быть зарегистрированным как пользовательский TargetSourceCreator для авто-прокси создатель, в сочетании с пользовательскими перехватчиками для конкретных бобов или только для создания прокси lazy-init. Например, как автоматически определяемый инфраструктурный компонент в контексте приложения XML Определение:

 <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
   <property name="customTargetSourceCreators">
     <list>
       <bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator"/>
     </list>
   </property>
 </bean>

 <bean id="myLazyInitBean" class="mypackage.MyBeanClass" lazy-init="true">
   ...
 </bean>

Если вы обнаружите, что делаете это несколько раз в контексте приложения, это сэкономит на конфигурации.

0 голосов
/ 14 ноября 2011

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

Пример:

package org.test.lazy;

public abstract class ParentBean {
    public abstract LazyBean getLazy();
    public void lazyDoingSomething() {
        getLazy().doSomething();
    }
}

package org.test.lazy;

public class LazyBean {
   public void init() {
       System.out.println("Initialized");
   }
   public void doSomething() {
       System.out.println("Doing something");
   }
}

package org.test.lazy;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class LazyTest {

    @Autowired
    private ParentBean parentBean;

    @Test
    public void test() {
        parentBean.lazyDoingSomething();
        parentBean.lazyDoingSomething();
    }
}

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
">
    <import resource="classpath:org/test/lazy/Lazy-context.xml"/>
    <bean id="parentBean" class="org.test.lazy.ParentBean">
        <lookup-method bean="lazyBean" name="getLazy"/>
    </bean>
</beans>

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
"
default-lazy-init="true">

    <bean id="lazyBean" class="org.test.lazy.LazyBean" init-method="init" />
</beans>

Таким образом, ваш ленивый компонент будет инициализирован только один раз по требованию.

0 голосов
/ 14 ноября 2011

Я не знаю о Spring, но в Guice вы бы использовали Provider<ServiceB>, так что, когда вы будете готовы использовать сервис, вы перейдете provider.get().callMethodOnB(...).

Это, я полагаю, часть спецификации JSR-330, поэтому вполне возможно, что в Spring есть нечто подобное (я уже довольно давно не использовал последнюю версию Spring).

...