简体   繁体   中英

How to inject bean via generic variable in spring

I have problem with injecting bean with generic types. Look at the example. I will inject to the service a repository which types takes from App class. Now i have exception:

No qualifying bean of type 'asd.IRepository' available: expected single matching bean but found 2: a,b

asd here is package, just for tests.

What can I do in this situation? Is any way to makes it?

public interface IRepository<T, V> {
    void print();
}


@Component
public class A implements IRepository<String,String> {

    @Override
    public void print() {
        System.out.println("A");
    }
}

@Component
public class B implements IRepository<Double,String> {

    @Override
    public void print() {
        System.out.println("A");
    }
}

@Service
public class ServiceABC<V, T> {

    @Autowired
    private IRepository<V,T> repo;

    public void print(){
        repo.print();
    }
}

@Controller
public class App {

    @Autowired
    private ServiceABC<String, String> serviceABC;

    public static void main(String[] args) {
        ApplicationContext ctx =
                new AnnotationConfigApplicationContext("asd");

        App app = ctx.getBean(App.class);
        app.serviceABC.print();
    }

You have to name your components and autowire by name:

@Component("A")
public class A implements IRepository<String,String> {...}

@Component("B")
public class B implements IRepository<Double,String> {...}

[...]

@Autowired
@Qualifier("B")
private IRepository repo;

It looks like you don't know in advance which implementation of your IRepository interface you will need. And you will know that at runtime. In this case it is a typical case for Factory pattern where you will have a IRepositoryFactory that will have a method thhat retrieves specific implementation by type (for example IRepositoryFactory.getInstance(String type); So in your ServiceABC you may use the IRepository to get specific bean at runtime. So Factory pattern may be an answer to your question. I also wrote an article that deals with this type of problem and proposes the idea of self-populating Factory (using Open source library that provides such utility). Here is the link to the article: Non-intrusive access to "Orphaned" Beans in Spring framework

Something like that?

@Controller
public class RepositoryFactory {

    @Autowired
    private IRepository<String, String> a;

    @Autowired
    private IRepository<Double, String> b;

    public IRepository getRepository(String className) {

        if(className.equalsIgnoreCase("a")) {
            return a;
        } else if(className.equalsIgnoreCase("b")) {
            return b;
        }

        return null;
    }
}

@Service
public class ServiceABC {

    @Autowired
    private RepositoryFactory repositoryFactory;

    public void print(String className){
        repositoryFactory.getRepository(className).print();
    }
}


@Controller
public class App {

    @Autowired
    private ServiceABC serviceABC;

    public static void main(String[] args) {
        ApplicationContext ctx =
                new AnnotationConfigApplicationContext("asd");

        App app = ctx.getBean(App.class);
        app.serviceABC.print(A.class.getSimpleName());
    }
}s

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM