5

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?

4
  • I don't understand the question. You want to provide a class and let Spring manage its lifecycle for you (which is the common behavior) or you want to define how the class should be generated and let Spring manage this logic when autowiring it? Commented Apr 26, 2014 at 16:06
  • 1
    The first one. I want an XML-Free way to provide a class and let Spring manage it's lifecycle. I don't want to be responsible for newing it up. However, I don't want it discovered via @Component scanning -- I want to be explicit about the declaration of this class. Commented Apr 26, 2014 at 16:09
  • Your rephrased question still does not use constructor autowiring! I can see that you don't understand how property autowiring works in Spring... there are bean post processors, which detects properties and methods annotated with @Autowired annotation. These post processors are still active when using Java config. You don't need to do the autowiring manually. It will be done by Spring! Your presumption that you need to call bean.foo = new Foo() is incorrect... check again Sotirios answer (mainly the emphasized statement). Commented Apr 30, 2014 at 9:08
  • To be more clear - bean instantiation and dependency injection (including autowiring) are two separate processes... unless you are using constructor injection. Constructor autowiring is the only thing which is currently not possible with Java config. In Java config you are responsible for creating the instance... however as soon as the instance is returned from the @Bean method, it will be subject for additional processing - proxying, autowiring, special interface and annotation handling (factory beans, initializing beans, common annotations, ...). All the Spring magic is still there. Commented Apr 30, 2014 at 9:15

4 Answers 4

3

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 ...
}
Sign up to request clarification or add additional context in comments.

Comments

3

You need to notify Spring a way to discover the beans that will manage. You only have three ways (there's a fourth one but it is more complex and requires annotations as well, explained here):

  • XML based configuration:

    <bean id="foo" class="some.package.Foo" />
    
  • Annotation configuration:

    @Component
    public class Foo {
    }
    
  • Create a @Configuration class that declares the beans explicitly:

    @Configuration
    public class MyConfiguration {
        @Bean
        public Foo getFoo() {
            return new Foo(); //foo doesn't need any annotation at all.
        }
    }
    

AFAIK you're able to do something similar using CDI:

class MyConfiguration {

    @Produces
    Foo foo = new Foo();
}

Or by injecting a resource from another container, like JPA:

class MyConfiguration {

    //JPA will provide the object reference based on the persistence unit
    //CDI will just work as a by-pass to inject this reference in other beans
    @PersistenceContext //JPA annotation
    @Produces
    EntityManaged em;
}

But even CDI needs a way to know how to initialize the bean or where to retrieve it first.

Refer to:

5 Comments

Image
@MartyPitt I'm really missing the point of having that. How would Spring know what instance to create and how to create it? What is it managing?
@MartyPitt I doubt of this. What would happen if your bean doesn't offer a default constructor, how Spring should manage it? Or what if you declare an abtract class or an interface, how is supposed that Spring have to create such instance?
@SotiriosDelimanolis & LuiggiMendonza : Gents -- There's no difference between what is being expressed here, and what is possible to express via Xml config. In XML, it's possible (though, not valid) to declare definitions of abstract classes, classes with non-default constructors, ambiguous classes, primitive classes, and a plethora of other configs that are invalid. There's a rich resolution algo that evaluates & either rejects or allows those configs. I submit that Java configs should be allowed to get explicitly included in the same resolution process -- that's all.
Image
@MartyPitt Yes, the Java alternative of that is a @Bean method. I still don't see a valid use case for what you propose or a valid solution.
No, they're very different. @Bean provides a value. ("Here's a foo. I built it for you"). Xml provides a class, but no value, and leaves it to the Container to provide one. ("Build me a foo"). The responsibilities & obligations of the two are miles apart. The closest Java equivalent to this concept is @Component. But, that's implicit / discovered, not explicit / decalared, like the xml version.
3

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.

Comments

1

Does facility like this exist within Spring?

The answer is kind of, but it is not clean.

All bean definitions in Spring depend on a BeanDefinition object in the ApplicationContext.

With an XML configuration like

<bean class="com.example.SomeType">
</bean>

Spring will generate a RootBeanDefinition with that class type and as a singleton, but with no other information about how it should be constructed. Instead the ApplicationContext will determine how to create the bean.

With Java configuration like

@Bean
public com.example.SomeType someType() {
    return new com.example.SomeType();
}

Spring will create a RootBeanDefinition but specifically state that the bean should be generated from the @Configuration bean as a factory-bean and its someType() method as a factory-method. The ApplicationContext therefore doesn't have to decide for itself, it just does what the BeanDefinition tells it.

(Incomplete, I'll be back later to finish this.)


You have to understand that XML and Java configurations are different but try to achieve the same thing.

When you declare an XML <bean> element like so

<bean class="com.example.SomeType">
</bean>

You are telling Spring to use the parameterless constructor of SomeType to instantiate the bean class and create a bean.

In Java, the equivalent would be

@Bean
public com.example.SomeType someType() {
    return new com.example.SomeType();
}

Similarly,

<bean class="com.example.SomeType">
    <constructor-arg type="java.lang.String" value="hello world"/>
    <property name="some" value="some value" />
</bean>

is telling Spring to use a constructor with one parameter of type String with that given value to instantiate the bean class. Then set some property. The equivalent is

@Bean
public com.example.SomeType someType() {
    com.example.SomeType someType = new com.example.SomeType("hello world");
    someType.setSome("some value");
    return someType;
}

These beans will still be candidates for autowiring just like any other. If they have @Autowired fields or methods, those will be injected.

All the above configs tell Spring exactly how to create the bean. Something like this

@Bean
public MyFunkySpringBean funkyBean; // No instance -- it's up to Spring to build

doesn't really say anything unless conventions are set. I don't see any advantage to that feature that you can't get with a classic @Bean method.

8 Comments

In the XML example, if com.example.SomeType doesn't provide a parameterless constructor, but declares a parameterized constructor, annotated with @Autowired, it will be invoked, and the appropriate values injected by Spring. What's the Java equivalent?
In the XML example, you're not telling Spring which constructor to invoke. You're telling it : "Here's a class -- Use reflection to work out what to do next". There's no guarantees made that a parameterless constructor exists. In XML you may choose to get more explicit, by providing constructor args. But, omitting them and providing an @Autowired parameterized constructor on the bean is also valid. And, if you don't provide a valid config, Spring will tell you that too. There is no Java equivalent of that which is explicit. (Only, the implicit @Component annotation)
Image
@MartyPitt So what you're looking for is implicit constructor invocation through a Java configuration?
Image
@MartyPitt But also still be able to use property setters (or any other method) on the bean like you would in a @Bean method?
I'm looking for an explicit java mechanism that submits a type to the same instantiation criteria as the xml version. (ie., use reflection, invoke a parameterless constructor if it exists, or invoke the @Autowired parameterized constructor, and wire it up).
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.