How to pass constructor parameter while using spring auto wiring?

拟墨画扇 提交于 2020-01-24 09:58:29

问题


Our Project is using spring DI/IoC, so i am using autowiring to inject beans. The program needs to pass parameters to an object during it's instantiation. And the parameters are know at run time (not at compile time).

How to achive this while using autowiring. Sample code is as below.

Interface - IMessage

package com.example.demo.services;

public interface IMessage {
        String message(String name);
}

Implementations -
SayHelloService

package com.example.demo.services;

import org.springframework.stereotype.Service;

@Service
public class SayHelloService implements IMessage {

    String id;

    public SayHelloService(String id) {
        super();
        this.id = id;
    }

    @Override
    public String message(String name) {
        return "Hello Dear User - " + name + ". Greeter Id: " + id ;
    }
}

MasterService

package com.example.demo.services;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class MasterService implements IMessage  {

    String creationTime;

    MasterService() {
        System.out.println("ms... default constructor");
        creationTime = Long.toString(System.currentTimeMillis());
    }

    //classic java way of creating service
    IMessage sayHelloServiceClassicWay = new SayHelloService(creationTime);

    //how to achieve above using spring auto wiring. Below code does not exactly do same.
    @Autowired
    @Qualifier("sayHelloService")
    IMessage sayHelloServiceAutoWired;

    @Override
    public String message(String name) {
        return name.toString();
    }    
}

Now in the above program (in MasterService) how to replace

IMessage sayHelloServiceClassicWay = new SayHelloService(creationTime);

with spring equivalent code.


回答1:


Spring doesn't work in this way.

Your two beans are too coupled, both in terms of execution and instantiation : as the first one is created, it created during its construction, the second one and it passes to it a generated value at runtime in argument constructor.

Even by playing with dependency injection order (@DependsOn, @Order or with two @Configuration which one depends on the other) it would not solve your problem because of the runtime generated value that is not a dependency.

As a workaround, providing a method to value once creationTime in the IMessage interface may be acceptable.
SayHelloService could look like :

package com.example.demo.services;

import org.springframework.stereotype.Service;

    @Service
    public class SayHelloService implements IMessage {

        String id;

        public SayHelloService(String id) {
            super();
            this.id = id;
        }

        @Override
        public void setId(String id){
            // you can add this check to enforce the immutability of id
            if (this.id != null){//exception handling}
            this.id = id;
        }

        @Override
        public String message(String name) {
            return "Hello Dear User - " + name + ". Greeter Id: " + id ;
        }
    }

And you could change MasterService in this way :

private IMessage sayHelloServiceAutoWired;

@Autowired
MasterService( @Qualifier("sayHelloService")
IMessage sayHelloServiceAutoWired) {
    System.out.println("ms... default constructor");
    creationTime = Long.toString(System.currentTimeMillis());
    this.sayHelloServiceAutoWired = sayHelloServiceAutoWired;
    this.sayHelloServiceAutoWired.setId(creationTime);
}

PS : The autowiring constructor is not mandatory but it is cleaner that having no API to set dependencies of the class. You may also use a setter.




回答2:


It works differently, create SayHelloService in Spring context with constructor args and then Spring will autowire it. No-xml congif example:

class B1 {
    @Autowired
    B2 b2;
}

class B2 {
    B2(int i) {
    }
}

@Configuration
class Config {

    @Bean
    B1 b1() {
        return new B1();
    }

    @Bean
    B2 b2() {
        return new B2(1);
    }
}

In this example Spring will autowire B2 which has constructor with one arg



来源:https://stackoverflow.com/questions/46639069/how-to-pass-constructor-parameter-while-using-spring-auto-wiring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!