我慢してください:
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
これらのサポート クラスを注入する適切な方法は何でしょう。
- 特定のエンティティ (例:
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();
}