请多多包涵:
我们有一个Hibernate和Spring IoC的设置,其中每个实体(User
、Customer
、Account
、Payment
、Coupon
等)都有一堆“单例”接口和支持它的实现类。
例如:对于Customer
:
@Entity
public class Customer extends BaseEntity {
...
public name();
}
/* base API */
public interface Service {
public create();
public list();
public find();
public update();
public delete();
}
/* specific API */
public interface CustomerService extends Service {
public findByName();
}
/* specific implementation */
public class CustomerServiceImpl extends BaseService implements CustomerService {
...
}
这种模式一直在继续(CustomerManager
、CustomerDataProvider
、CustomerRenderer
等)。
最后,为了针对特定 API 的实例(例如CustomerService.findByName()
)工作,一个静态全局持有者已经进化 - 这使得如下引用可用:
public class ContextHolder {
private static AbstractApplicationContext appContext;
public static final CustomerService getCustomerService() {
return appContext.getBean(CustomerService.class);
}
//... omitting methods for each entity class X supporting class
}
@Configuration
public class ServicesConfiguration {
@Bean(name = "customerService")
@Lazy(false)
public CustomerService CustomerService() {
return new CustomerServiceImpl();
}
//... omitting methods for each entity class X supporting class
}
所以,问题是:
注入这些支持类的正确方法是什么,例如CustomerService
,给定一个实体实例,用于以下用途:
- 我有一个特定的实体(例如 a
Customer
),并且想要获得服务并调用特定的 API(例如findByName()
)? - 我有一个实体(不关心具体是哪一个),并且想调用一个通用 API(例如
find()
)
所有这一切,同时避免了全局静态引用(因此,在例如测试中交换实现,并简化调用者代码)。
因此,如果我有实体实例,我可以获得任何支持类
BaseEntity entity = ... // not injected
Iservice service = ...// should be injected
service.create(entity);
或者,获取给定实体类型所需的所有支持类
/* specific implementation */
public class CustomerServiceImpl extends BaseService implements CustomerService {
// inject specific supporting classes
@Autowire CustomerManager manager;
@Autowire CustomerDataProvider provider;
@Autowire CustomerRenderer renderer;
@Autowire CustomerHelper helper;
...
}
并且,在其他情况下稍微更改配置
// how to configure Spring to inject this double?
Class CustomerManagerDouble extends CustomerManager {...}
@Autowired @Test public void testSpecificAPI(CustomerService service) {
service.doSomethingSpecific();
assert ((CustomerManagerDouble) service.getManager()).checkSomething();
}