50

Is possible in Spring that class for bean doesn't have public constructor but only private ? Will this private constructor invoked when bean is created? Thanks.

user710818
  • 23,228
  • 58
  • 149
  • 207

6 Answers6

84

Yes, Spring can invoke private constructors. If it finds a constructor with the right arguments, regardless of visibility, it will use reflection to set its constructor to be accessible.

KevinS
  • 7,715
  • 4
  • 38
  • 56
  • Could you please give me the reference to docs? Constructor has parameters, and in xml file to this arguments assigned values. – user710818 Aug 31 '11 at 08:52
  • you mean if a bean has specifically something like private bean() { ... } spring can invoke that? How is that possible, that defies the whole purpose of "private". – Ashkan Aryan Aug 31 '11 at 08:56
  • 1
    Sorry, I'm probably wrong about it only being no-arg constructors. I'm just going by what I've noticed on my own projects. I can't say I've ever seen it in the Spring documentation anywhere. But this is the javadoc for the class that is responsible for doing the instantiation. http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#instantiateClass(java.lang.reflect.Constructor,%20java.lang.Object...) – KevinS Aug 31 '11 at 09:01
  • 4
    @Ashkan It is possible using reflection. In particular, the Spring BeanUtils class uses a class called ReflectionUtils to make the constructor accessible. See javadocs for Constructor.setAccessible(). – KevinS Aug 31 '11 at 09:03
  • @Kevin Stembridge you are correct, it is possible using Reflection. – Ashkan Aryan Aug 31 '11 at 09:07
  • I think yes, it possible use private constructor by means of reflection. May be spring do it. – user710818 Aug 31 '11 at 09:13
  • +1: Note that if you've got a non-Spring-aware third-party bean implementation, you'll have to use XML to configure it (including setting what values to pass as arguments to the constructor, if necessary). Not that that should be a problem. – Donal Fellows Aug 31 '11 at 09:27
3

Yes, Private constructors are invoked by spring. Consider my code:

Bean definition file:

<bean id="message" class="com.aa.testp.Message">
        <constructor-arg index="0" value="Hi Nice"/>
    </bean>

Bean class:

package com.aa.testp;

public class Message {

    private String message;

    private Message(String msg) {
       // You may add your log or print statements to check execution or invocation
        message = msg;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public void display() {
        System.out.println(" Hi " + message);
    }

}

The above code works fine. Hence, spring invoked the private constructor.

Ashish Ani
  • 324
  • 1
  • 7
3

You can always use a factory method to create beans rather than relying on a default constructor, from The IoC container: Instantiation using an instance factory method:

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="com.foo.DefaultServiceLocator">
  <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="exampleBean"
      factory-bean="serviceLocator"
      factory-method="createInstance"/>

This has the advantage that you can use non-default constructors for your bean, and the dependencies for the factory method bean can be injected as well.

Matthew Farwell
  • 60,889
  • 18
  • 128
  • 171
1

Yes ! Spring can access private constructor. It will works internally like below code.

 try {
    Class clazz = Class.forName("A"); // A - Fully qualified class name
    Constructor constructor[] = clazz.getDeclaredConstructors();
    constructor[0].setAccessible(true);
    A a = (A) constructor[0].newInstance();
 }
 catch (Exception e) {
        e.printStackTrace();
 }
bb121622
  • 1,036
  • 11
  • 13
GnanaJeyam
  • 2,780
  • 16
  • 27
0

Spring will never call private constructor as Bean scope. If do it will through the below error.

Common causes of this problem include using a final class or a non-visible class. Nested exception is

java.lang.IllegalArgumentException: No visible constructors in class.

Giorgio
  • 1,973
  • 4
  • 36
  • 51
0

You would normally have a static factory method in such beans, you can specify that method for spring to get an instance of that bean. See 3.3.1.3 here. This is the way it's recommended by Spring, rather than going against visibility restrictions.

Ashkan Aryan
  • 3,504
  • 4
  • 30
  • 44
  • strange, there are no static method, no public constructor but when I do debug - private constructor invoked! by sun.reflect.NativeConstructorAccessorImpl – user710818 Aug 31 '11 at 08:47
  • Without specifics/code it won't be possible to comment any further! – Ashkan Aryan Aug 31 '11 at 08:48
  • I suppose you are wrong. There are no specific code - I see in debugger only standard sun/spring methods. – user710818 Aug 31 '11 at 08:50
  • 1
    @Ashkan: I suspect you're getting the -1 votes because you're wrong. Spring _can_ peek behind the curtain (unless there's a strict security manager in place and the Spring code isn't marked as trusted). – Donal Fellows Aug 31 '11 at 09:33
  • @Donal Fellows thanks! Probably! But the rest of my comment is correct and is what is in Spring docs actually so I'm not sure what's -1s are for. I can remove the 1st sentence if it's wrong though. So, if you have a constructor that is explicitly marked private it can still be used by Spring, is that what we are saying? – Ashkan Aryan Aug 31 '11 at 09:44
  • 1
    @Ashkan: It's _very bad style_ to go against visibility restrictions. Don't do it! Or if you do, feel very bad about it. (Spring does it because it wants to split the definition of a bean from its configuration, but they're typically still closely linked. This question happens to be about the exceptional case where that's not true…) – Donal Fellows Aug 31 '11 at 09:50
  • @Donal Fellows: Exactly, hence my initial reply. I just can't understand why he would want to do that, what is he trying to achieve, despite me and Matthew asking repeatedly. – Ashkan Aryan Aug 31 '11 at 09:56