Spring tworząc obiekty korzysta z refleksji i oczekuje istnienia konstruktora bezparametrowego. Widoczność nie znaczenia. Co w przypadku gdy nie mamy możliwości bądź nie chcemy takiego konstruktora udostępniać ? Istnieją inne metody.
Możemy utworzyć statyczną metodę fabrykującą. Spójrzmy na klasę i jej konfigurację :
public class ExampleService implements Service {
    private Repository repo;
    public ExampleService(Repository repository) {
        super();
        this.repo = repository;
    }
    private static ExampleService newInstance(Repository repository) {
        return new ExampleService(repository);
    }
}
oraz konfiguracja :
<bean id="service" class="pl.turo.spring.service.ExampleService" factory-method="newInstance">
    <constructor-arg ref="repository" />
</bean>
<bean id="repository" class="pl.turo.spring.repository.ExampleRepository" />  Spring tworząc beana "service" nie będzie szukał konstruktora z parametrem zgodnym typem z Repository, ale na klasie ExampleService uruchomi metodę newInstance i jej w parametrze przekaże referencję do beana "repository". Jak widać metoda ta może być prywatna. Jeśli chcielibyśmy mieć taką metodę w innej klasie to nie ma problemu :public class ServiceFactory {
    private Repository repository;
    public ExampleService newService() {
        return new ExampleService(repository);
    }
    public void setRepository(Repository repository) {
        this.repository = repository;
    }
}
oraz konfiguracja :<bean id="serviceFactory" class="pl.turo.spring.service.ServiceFactory"> <property name="repository" ref="repository" /> </bean> <bean id="service" class="pl.turo.spring.service.ExampleService" factory-method="newService" factory-bean="serviceFactory" /> <bean id="repository" class="pl.turo.spring.repository.ExampleRepository" />Tym razem spring tworząc beana "service" oddeleguje utworzenie obiektu do bena-fabryki ("serviceFactory") i na nim wywoła metodę newService.
Zauważmy, że przeciwnie do pierwszego przykładu - tutaj tworzymy beana będącego fabryką, więc metoda nie jest już statyczna.
Kolejną możliwością jest zaimplementowanie interefejsu FactoryBean. Beany takie są automatycznie wykrywane przez springa (BeanFactoryPostProcessor).
Przykład :
public class RepositoryFactory implements FactoryBean<Repository> {
 private boolean singleton;
 private Repository instance;
 
 public Repository getObject() throws Exception {
  if (!singleton || instance == null) {
   instance = new ExampleRepository();
  } 
  return instance;
 }
 public Class getObjectType() {
  return Repository.class;
 }
 public boolean isSingleton() {
  return singleton;
 }
 
 public void setSingleton(boolean singleton) {
  this.singleton = singleton;
 }
}
oraz konfiguracja : <bean id="repositoryFactory" class="pl.turo.spring.repository.RepositoryFactory"> <property name="singleton" value="false" /> </bean> <bean id="service" class="pl.turo.spring.service.ExampleService"> <constructor-arg ref="repositoryFactory" /> </bean>Widzimy konfigurację fabryki. Bean tej fabryki jest użyty w miejscu, gdzie powinien pojawić się bean 'repository' i spring domyśli się, że należy uruchomić metodę getObject().
Ponieważ fabryka to najzwyklejszy w świecie bean, to można jej wstrzykiwać wartości/beany. Jedną z częściej wykorzystywanych fabryk w springu jest fabryka sesji hibernate :
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="pl.turo.spring" /> <property name="schemaUpdate" value="true" /> <property name="hibernateProperties"> <props> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> </props> </property> <!-- dalsza konfiguracja --> </bean>
To nie koniec możliwości. Spring 3 umożliwia tworzenie konfiguracji w kodzie javy - wystarczy dodać adnotację @Configuration do beana. Przykład :
@Configuration
public class RepositoryConfiguration {
 @Bean
 public Repository repository() throws Exception {
  RepositoryFactory repositoryFactory = new RepositoryFactory();
  repositoryFactory.setSingleton(true);
  return repositoryFactory.getObject();
 }
}
oraz :@Configuration
@Import({ RepositoryConfiguration.class })
public class ServiceConfiguration {
 
 @Autowired
 private Repository repository;
 
 @Bean
 public Service service () throws Exception {
  return new ExampleService(repository);
 }
}
i konieczny xml : <context:annotation-config /> <bean class="pl.turo.spring.configuration.RepositoryConfiguration" /> <bean class="pl.turo.spring.configuration.ServiceConfiguration" />Pokazałem jak utworzyć więcej niż jeden bean konfiguracyjny i jak z jednego wyciągnąć beany aby wstrzyknąć drugiemu (repository wstrzykujemy do service).
W temacie instancjonowania obiektów należy jeszcze wspomnieć o metodach zwrotnych cyklu życia beana. Możemy chcieć aby spring uruchomił metodę beana zaraz po jego utworzeniu i wstrzyknięciu zależności. Możemy to osiągnąć na 3 sposoby :
- adnotacją @PostConstruct z JSR-250 (metoda musi być bezparametrowa - to jedyne wymaganie)
- atrybutem init-method w tagu bean (metoda musi być bezparametrowa - to jedyne wymaganie)
- implementując interfejs InitalizingBean (metoda afterPropertiesSet())
Podobnie możemy chcieć wykonać jakąś akcję przed zniszczeniem beana (dokładniej tuż przed odpięciem beana od fabryki springa)
- adnotacją @PreDestroy
- atrybutem destroy-method w tagu bean
- implementując interfejs DisposableBean (metod destroy())
To na tyle w tamacie instancjonowania obiektów.
