java - Jersey 2.x 中的依赖注入
问题描述
我定义了一个 AbstractBinder 并将其注册到我的 JAX-RS 应用程序中。binder 指定依赖注入应该如何创建我的类。
public class AppBinder extends AbstractBinder {
@Override
protected void configure() {
bind(TranslationImportServiceImpl.class).to(TranslationImportService.class);
bindAsContract(ImportCandidateBuilder.class);
bind(DomainsBusinessServices.class)
.to(IDomainsBusinessServices.class).in(Singleton.class);
bind(CodeBusinessService.class)
.to(ICodeBusinessService.class).in(Singleton.class);
bind(LangBusinessService.class)
.to(ILangBusinessService.class).in(Singleton.class);
bind(TranslationBusinessService.class)
.to(ITranslationBusinessService.class).in(Singleton.class);
bind(SessionImpl.class)
.to(Session.class).in(Singleton.class);
bind(SessionFactoryImpl.class)
.to(SessionFactory.class).in(Singleton.class);
bind(CriteriaImpl.class)
.to(Criteria.class).in(Singleton.class);
bindAsContract(DefaultBusinessService.class);
}
我实现了 Application 类(在 web.xml 的 init-param 中指定)。
public class Application extends ResourceConfig {
public Application() {
register(new AppBinder());
packages(true, "web.rest");
}
web.xml
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>web.rest</param-value>
</init-param>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>web.rest.Application</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
然后我的 RestService 注入工作正常
@Path("/call")
public class RestService {
@Inject
private TranslationImportService translationImportService;
@POST
@Path("/post")
@Consumes({MediaType.MULTIPART_FORM_DATA})
public Response upload(@FormDataParam("file") InputStream fileInputStream,
@FormDataParam("file") FormDataContentDisposition fileMetaData) throws Exception {
Map<String, TranslationImportResult> importResultMap = new HashMap<String, TranslationImportResult>();
try {
Map<String, InputStream> extractedFiles = extractFiles(fileMetaData.getFileName(), fileInputStream);
Set<Entry<String, InputStream>> entrySet = extractedFiles.entrySet();
TranslationImportResult importResult;
for (Entry<String, InputStream> entry : entrySet) {
importResult = null;
if (entry.getKey().endsWith(".xml") || entry.getKey().endsWith(".xlf")) {
importResult = translationImportService.importTranslations(entry.getKey(), entry.getValue(), 1320L, "admin", true);
} else {
logger.warn("Cannot process file (wrong extension): ", entry.getKey());
importResult = new TranslationImportResult(TranslationImportStatus.FAILURE, -1, -1);
}
importResultMap.put(entry.getKey(), importResult);
}
} catch (Exception e) {
logger.error("A problem with the file extention occured! \n", e);
}
return Response.ok("File uploaded successfully").build();
}
我将接口 TranslationImportService 注释为 @Contract
@Contract
public interface TranslationImportService
以及作为@Service 的实现
@Service
public class TranslationImportServiceImpl implements TranslationImportService{
@Inject
private ImportCandidateBuilder importCandidateBuilder;
@Override
public TranslationImportResult importTranslations(String inputName, InputStream inputStream, Long domainId,
String username, boolean allOrNothing) throws Exception {
TranslationImportStatus ret;
InputDeserializer inputDeserializer = InputDeserializerFactory.newInputDeserializer(inputName);
List<InputTranslationBean> translationBeans = inputDeserializer.deserialize(inputStream);
List<ImportCandidate> candidates = importCandidateBuilder.buildCandidates(domainId, translationBeans);
insertStartImportEvent(candidates, inputName);
translationImportOrchestrator.performTranslationsImport(candidates, username, allOrNothing);
TranslationImportResult importResult = buildImportResult(translationImportOrchestrator);
insertStopImportEvent(candidates, inputName);
return importResult;
}
问题在于注入 importCandidateBuilder。虽然我已经绑定了它,但它会抛出异常:
org.glassfish.hk2.api.UnsatisfiedDependencyException: Injectee 没有可用于注入的对象 (requiredType=ImportCandidateBuilder,parent=TranslationImportServiceImpl...)
导入候选生成器类:
@Service
public class ImportCandidateBuilder {
private static Logger logger = LoggerFactory.getLogger(ImportCandidateBuilder.class);
private IDomainsBusinessServices domainService;
private ICodeBusinessService codeService;
private ILangBusinessService vlService;
private ITranslationBusinessService translationService;
public ImportCandidateBuilder(IDomainsBusinessServices domainService, ICodeBusinessService codeService,
ILangBusinessService vlService, ITranslationBusinessService translationService) {
this.domainService = domainService;
this.codeService = codeService;
this.vlService = vlService;
this.translationService = translationService;
}
public List<ImportCandidate> buildCandidates(Long domainId, List<InputTranslationBean> inputBeans) {
Validate.notNull(domainId, "arg [domainId] is null");
Validate.notEmpty(inputBeans, "arg [translations] is null or empty");
List<ImportCandidate> ret = new ArrayList<>();
Domains domain = fetchDomain(domainId);
for (InputTranslationBean inputBean : inputBeans) {
Tables table = fetchTable(domain, inputBean.getTableName());
Codes code = (table == null) ? null : fetchCode(table, inputBean.getCodeName());
Vl lang = fetchVl(inputBean.getLang());
Trad translation = (code == null) ? null : fetchTranslation(code, lang);
String transText = inputBean.getTranslation();
String instructions = inputBean.getInstructions();
ImportCandidate candidate = new ImportCandidate(domain, table, code, lang, translation, transText, instructions, inputBean);
logger.debug("New import candidate built: [{}]", candidate);
ret.add(candidate);
}
return ret;
}
}
当我调用 getCurrentSession() 方法时抛出无法注入 SessionFactory 的异常,当我尝试为 DefaultBusinessService 创建和注入构造函数时,sessionfactory 返回为 null。我还绑定了课程。
@Service
public class DomainsBusinessServices extends DefaultBusinessService
implements IDomainsBusinessServices
{
public Domains getDomainById(Long domainId, boolean fetchLangs,
boolean fetchTables, boolean fetchCodes) {
Criteria domainCriteria = getCurrentSession().createCriteria(Domains.class);
domainCriteria.add(Restrictions.idEq(domainId));
if(fetchLangs){
domainCriteria.setFetchMode("Vls", FetchMode.JOIN);
}
if(fetchTables){
domainCriteria.setFetchMode("Tableses", FetchMode.JOIN);
}
if(fetchCodes){
domainCriteria.setFetchMode("Codeses", FetchMode.JOIN);
}
Domains domainVL = (Domains)domainCriteria.uniqueResult();
if (domainVL != null) {
Hibernate.initialize(domainVL.getVls());
}
return domainVL;
}
}
@Service
public class DefaultBusinessService {
@Inject
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
protected Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
解决方案
ImportCandidateBuilder
无法创建该类,因为没有默认构造函数。你有一个构造函数,但是所有这些参数应该来自哪里
public ImportCandidateBuilder(IDomainsBusinessServices domainService,
ICodeBusinessService codeService,
ILangBusinessService vlService,
ITranslationBusinessService translationService) {
}
当你想要一个注入框架来创建服务时,要么需要一个将被调用的默认构造函数,要么需要一个带有需要注释@Inject
的参数的构造函数,并且所有参数也必须绑定到 DI 容器。
@Inject
public ImportCandidateBuilder(IDomainsBusinessServices domainService,
ICodeBusinessService codeService,
ILangBusinessService vlService,
ITranslationBusinessService translationService) {
}
register(new AbstractBinder() {
@Override
public void configure() {
bind(DomainsBusinessServices.class)
.to(IDomainsBusinessServices.class).in(Singleton.class);
//.. bind others
}
});
推荐阅读
- size - 在 Photoshop 中测量前后图像的大小
- javascript - 没有争论会关闭我的不和谐机器人
- r - 删除与特定字符串对应的行,但保留 NA 值
- javascript - 悬停后点击效果
- python - 在 Python 中创建一个 for 循环来检查列表值
- gps - gpsd 在 Ubuntu 18.04 中没有收到信号
- excel - Excel 不会在下载的文件上提示“启用内容”
- html - 如何从两个超链接之间的空间获取html链接?
- python-3.x - Python Windows 资源管理器强制刷新
- java - Maven Surefire 未运行 JUnit 5 测试