Evan Reynolds
Evan Reynolds

Reputation: 450

Spring's Javaconfig and Prototyped Beans

I've moved my code from Spring's XML configuration to Java Configuration. I have everything working, but I have a question about how I implemented prototype beans - mainly, while what I'm doing works, is it the best way to do this? Somehow it just feels off!

I wrote the bean class this way:

@Component
@Scope("prototype")
public class ProtoBean {
    ...
}

Then to use the bean - this is the part that I'm just not sure about, although it does work:

@Component
public class BeanUser implements ApplicationContextAware {
    ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext context)throws BeansException
    {
        this.context = context;
    }

    public void getProtoBean() {
         ProtoBean protoBean = context.getBean(ProtoBean.class);
    }
}

This gets me a prototyped bean, and in unit tests I just mocked the context, called setApplicationContext with the mock, and had the getBean call of the mock return a mock ProtoBean. So all is well.

I did this in the XML by using a factory, but that didn't seem to work too well, so this is where I ended up. But is there a way to do this without the context? Or just a better way?

Thanks!

Upvotes: 0

Views: 869

Answers (1)

Mike Reardon
Mike Reardon

Reputation: 135

I don't think is so much an issue of Spring XML vs Java-base configuration, but one of matching dependency scopes. Since Spring can only do dependency injection on the singleton-scoped bean at creation time, you have to lookup the prototype-scoped bean on demand. Of course the current bean-lookup approach works, but creates a dependency on the ApplicationContext. I can suggest a few other possibilities but the root of the issue is really what is involved in producing a ProtoBean, and what trade-offs should you accept.

You could make BeanUser itself prototype-scoped, which would allow you to wire in the ProtoBean as a member. Of course the trade-off is you now have the same problem on the clients of BeanUser, but sometimes that would not be a problem.

Another path could be using something like a singleton-scoped ProtoBeanFactory to provide ProtoBean instances, and hiding dependency lookups within the ProtoBeanFactory.

Finally, you could use a scoped-proxy bean to effectively hide the factory. It uses AOP to do this, and isn't always clear to others what sort of voodoo you have going. With XML you'd use <aop:scoped-proxy/> on the bean declaration. For annotations you'd use:

@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")

Upvotes: 1

Related Questions