Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Java config : Specify class only

Tags:

java

spring

I'm in the process of moving some Xml-Based spring config over to Java-based.

Previously, I've consciously mixed Xml <bean class='foo' /> declarations with @Component mappings on a case-by-case basis, as a means of documenting non-obvious beans.

A typical use case would be if I'm declaring beans that will modify the behaviour of spring itself, I'll declare these explicitly, rather than let them be discovered, purely to improve the clarity of the config file.

However, often these beans will need a degree of @Autowiring. If I new the bean up myself within a Java config, I become responsible for performing this wiring -- which is pointless.

Is there a pure Java configuration option that explicitly provides a class back to Spring, and let's it manage the instantiation?

ie:

Given the class:

public class MyFunkySpringBean implements InitializingBean {
    @Autowired Foo foo;
}

In XML config, this would be declared as simply as:

<bean class="MyFunkySpringBean" />

Is there an equivalent in Java syntax, where I can explicitly declare the bean class to Spring, but not be responsible for providing the actual instance -- leaving that to Spring.

Eg:

@Configuration 
public class MyAppConfig {

    // Explictly provide the class, not the instance to Spring
    @Bean
    public MyFunkySpringBean funkyBean; // No instance -- it's up to Spring to build
}

To be clear, I don't want to have to do this:

@Configuration 
public class MyAppConfig {

    @Bean
    public MyFunkySpringBean funkyBean() {
         MyFunkySpringBean bean = new MyFunkySpringBean();
         bean.foo = new Foo();
         // other dependencies go here
         return bean;
    }

}

Does facility like this exist within Spring?

like image 821
Marty Pitt Avatar asked Feb 14 '23 03:02

Marty Pitt


2 Answers

I understand from your comments that you are looking for a way how to achieve constructor autowiring (with type or annotation autowiring) in Java config... i.e. equivalent of:

<bean class="com.example.Foo" autowire="constructor" />

I've checked Spring's source to find who is actually responsible for the constructor resolution and autowiring and it is a combination of package private class ConstructorResolver and AbstractAutowireCapableBeanFactory. So that is something you will not be able to use on your own.

If you really really want to have constructor autowiring without XML, you can implement your own BeanDefinitionRegistryPostProcessor and manually register that bean definitions yourself:

public class CustomBeanDefinitionRegistrar implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // Not interested in this method
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        registry.registerBeanDefinition("foo", BeanDefinitionBuilder.
                genericBeanDefinition(Foo.class).
                setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR).
                getBeanDefinition());
    }

}

This bean factory post processor then needs to be registered via static @Bean method in your @Configuration:

@Configuration
public class MyAppConfig {

    public static BeanFactoryPostProcessor customBeanDefinitionRegistrar() {
        return new CustomBeanDefinitionRegistrar();
    }

}

I admit it is a bit "wild approach", but it seems to be the only way how to achieve constructor autowiring with pure Java config.

like image 182
Pavel Horal Avatar answered Feb 15 '23 15:02

Pavel Horal


In newer versions of Spring (as of 4.2) you can use org.springframework.context.annotation.Import e.g.

@Configuration
@Import(MyFunkySpringBean.class)
public class MyAppConfig {
   ... other config ...
}
like image 37
artbristol Avatar answered Feb 15 '23 17:02

artbristol