Spring 3 - Dynamic Autowiring at runtime based on another object attribute

后端 未结 4 450
北荒
北荒 2020-12-08 11:27

I am working on a Spring 3.1 MVC application and for one of my scenarios, I had to write two implementations of a DAO. I would like to know how to autowire this in a service

相关标签:
4条回答
  • 2020-12-08 11:59

    My solution would be as follows:

    a method isResponsibleFor in the VehicleDao interface:

    interface VehicleDao {
        public boolean isResponsibleFor(Vehicle vehicle);
    }
    

    example implementation:

    @Repository
    class CarDAO implements VehicleDAO {
        public boolean isResponsibleFor(Vehicle vehicle) {
            return "CAR".equals(vehicle.getType());
        }
    }
    

    then autowire a list of all VehicleDao-implementations in the VehicleService:

    public class VehicleServiceImpl implements VehicleService {
    
        @Autowired
        private List<VehicleDao> vehicleDaos;
    
        private VehicleDao daoForVehicle(Vehicle vehicle) {
             foreach(VehicleDao vehicleDao : vehicleDaos) {
                  if(vehicleDao.isResponsibleFor(vehicle) {
                       return vehicleDao;
                  }
             }
    
             throw new UnsupportedOperationException("unsupported vehicleType");
        }
    
        @Transactional
        public void save(Vehicle vehicle) {
             daoForVehicle(vehicle).save(vehicle);
        }
    }
    

    This has the advantage that you don't need to modify the service when you are adding a new vehicleType at a later time - you just need to add a new VehicleDao-implementation.

    0 讨论(0)
  • 2020-12-08 12:00

    Please one note: previous solution is great and simple, but spring is creating each instance of each bean.

    So my solution is to create abstract class VehicleService instead of interface

    then in appContext

    @Bean
    @Primary
    VehicleService paymentProviderService()
    {
        return ...new (your requested instance by your own)...
    }
    
    0 讨论(0)
  • 2020-12-08 12:08

    Since Vehicle is a @Model it is a runtime value, you won't be able to use it for autowiring values.

    The vehicle has to be passed to the service methods as an argument.

    public interface VehicleService { void doSomething(Vehicle vehicle); }

    Assuming both CarDao and TrainDAO are implementing the same VehicleDao Service, other wise it won't make much sense.

    So in your VehicleServiceImpl I would recommend you to write a method like getVehicleDao(Vehicle v){} to get the correct instance of the dao.

    public class VehicleServiceImpl implements VehicleService {
    
        @Resource(name="carDAO")
        private VehicleDao carDAO ;
    
    
        @Resource(name="trainDAO")
        private VehicleDao trainDAO ;
    
        private VehicleDao getDao(Vehicle v){
            if(v instanceof Train){
                return trainDao;
            } else if(v instanceof Car) {
                return carDao;
            } else {
                throw new RuntimeException("unsupported vehicle type");
            }
        }
    
        void doSomething(Vehicle vehicle){
            VehicleDao dao = getDao(vehicle);
            dao.doSomethind(vehicle);
        }
    }
    
    0 讨论(0)
  • 2020-12-08 12:21

    There is an cleaner option to accomplish this strategy. We know Spring is smart enough to inject where it sees a bean that it has control over, so when it sees your VehicleDAO with an @Autowire or @Resource annotation, it will correctly inject that concrete implementation.

    Keeping that in mind, this will work anywhere you ask Spring to perform dependency injection, using a Map<> or a List<> for instance.

    // Injects the map will all VehicleDAO implementations where key = the
    // concrete implementation (The default name is the class name, otherwise you 
    // can specify the name explicitly).
    @Autowired
    private Map<String, VehicleDAO> vehicleDAO;
    
    // When you want to use a specific implementaion of VehicleDAO, just call the  
    // 'get()' method on the map as in:
    ...
    vehicleDAO.get("carDAO").yourMethod();
    ...
    
    0 讨论(0)
提交回复
热议问题