Question

Is there a ready out-of-the-box solution in Spring to proxy a class so that it is CREATED (new instance) and INITIALIZED (setters called) when a method of that class is invoked?

I found and tried using org.springframework.aop.target.LazyInitTargetSource.

Maybe I'm doing something wrong but in the following scenario my class instance is created TWICE. Once when the bean is retrived from the context and then ONCE AGAIN when a method is called:

My proxied class:

public class NewClass {

    private Integer i;

    public NewClass() {
        System.out.println("NewClass()");
    }

    public void setI(Integer i) {
        System.out.println("setI(): " + i);
        this.i = i;
    }

    public Integer add() {
        return i + 1;
    }
}

Spring config:

<bean id="newClassTarget" class="com.mycompany.spring.NewClass" lazy-init="true">
    <property name="i" value="1"/>
</bean>

<bean id="newClass" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource">
        <bean class="org.springframework.aop.target.LazyInitTargetSource">
            <property name="targetBeanName">
                <idref local="newClassTarget"/>
            </property>
        </bean>
    </property>
</bean>

Running code:

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("lazy.xml");
    System.out.println("Context initialized");
    System.out.println("before getting bean");
    NewClass newClass = (NewClass) applicationContext.getBean("newClass");
    System.out.println("after getting bean");
    System.out.println("calling add()...");
    System.out.println(newClass.add());
}

produces:

Context initialized
before getting bean
NewClass()
after getting bean
calling add()...
NewClass()
setI(): 1
2

So NewClass constructor is called when getting the bean from Spring context and when calling add() method. I don't think it's nice, did I screw something up?

Anyway, the first call comes from enhancer.create() in Cglib2AopProxy.getProxy(). Is seems the proxy creates an instance of the proxied class when the bean is requested, not when the first method call occures. That is not what I want.

I could create my own java.lang.reflect.Proxy as a holder for my NewClass and create an instance of NewClass in handler's invoke() the first time a method is called. I would have play around with calling setters first, though.

Is there any ready solution in Spring I could use to achieve:

Context initialized
before getting bean
after getting bean
calling add()...
NewClass()
setI(): 1
2

?

Was it helpful?

Solution

I was able to replicate your behavior - the fix that I have is to simply define an interface for your NewClass, this way Java Dynamic proxies are created instead of CGLIB enhanced proxies. Then it works as expected - instantiating NewClass at the point of the methods being called.

public interface NewInterface {
    public void setI(Integer i);
    public Integer add() ;
}

public class NewClass implements NewInterface{

    private Integer i;

    public NewClass() {
        System.out.println("NewClass()");
    }

    public void setI(Integer i) {
        System.out.println("setI(): " + i);
        this.i = i;
    }

    public Integer add() {
        return i + 1;
    }
}

OTHER TIPS

You can try initialize your class in @PostConstruct method. I suppose Spring will call this method only for actual instance of your class, not proxy.

UPDATE

If you enabled annotation config then you try this:

public class NewClass {

    private Integer i;

    public NewClass() {
        System.out.println("NewClass()");
    }

    @PostConstruct
    public void init() {
        System.out.println("Initialization");
    }

    public void setI(Integer i) {
        System.out.println("setI(): " + i);
        this.i = i;
    }

    public Integer add() {
        return i + 1;
    }
}

Check how many times "Initialization" printed to console.

Some links:
Init method without annotation: http://www.mkyong.com/spring/spring-init-method-and-destroy-method-example/
Init method with annotation: http://www.mkyong.com/spring/spring-postconstruct-and-predestroy-example/

Thanks for all the comments. I came up with a fast (not perfect) solution for CREATING and INITIALIZING a class as late as when its method is called. I hope it's not too complicated. The thing I don't like about this solution is the problem with delegating setter calls. I made the factory and the class implement the same 'settable' interface. Maybe somebody will have a better idea.

A common interface for the class and its proxy factory:

public interface ProxiedClassSettable {

    void setI(Integer i);
}

Proxied class interface (extends the 'setter' interface):

public interface ProxiedClass extends ProxiedClassSettable {

   Integer add();

}

Proxied class:

public class ProxiedClassImpl implements ProxiedClass {

    private Integer i;

    public ProxiedClassImpl() {
        System.out.println("ProxiedClassImpl()");
    }

    public Integer add() {
        return i + 1;
    }

    public void setI(Integer i) {
        System.out.println("setI(): " + i);
        this.i = i;
    }
}

Proxy factory (I made it implement the 'setter' interface to show coupling with ProxiedClass):

public class ProxiedClassFactory implements FactoryBean, ProxiedClassSettable {

    private Integer i;

    public Object getObject() throws Exception {
        return Proxy.newProxyInstance(ProxiedClass.class.getClassLoader(),
                new Class[]{ProxiedClass.class},
                new InvocationHandler() {

                    private ProxiedClass proxiedClass;

                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (proxiedClass == null) {
                            proxiedClass = new ProxiedClassImpl();
                            //not a very nice way to initialize the proxied class
                            proxiedClass.setI(i);
                        }
                        return method.invoke(proxiedClass, args);
                    }
                });
    }

    public Class getObjectType() {
        return ProxiedClass.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public void setI(Integer i) {
        this.i = i;;
    }
}

Spring XML:

<bean id="proxiedClass" class="com.mycompany.spring.proxy.ProxiedClassFactory">
    <property name="i" value="1"/>
</bean>

Running:

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("proxiedClass.xml");
    System.out.println("Context initialized");
    System.out.println("before getting bean");
    ProxiedClass newClass = (ProxiedClass) applicationContext.getBean("proxiedClass");
    System.out.println("after getting bean");
    System.out.println("calling add()...");
    System.out.println(newClass.add());
}

produces what I wanted - the class is first created what its method is called:

Context initialized
before getting bean
after getting bean
calling add()...
ProxiedClassImpl()
setI(): 1
2
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top