Jersey2中如何注入Spring组件

引入Maven依赖

下面以Jersey 2.0和Spring 3.0版本为例。


<dependency>
	<groupId>org.glassfish.jersey.coregroupId>
	<artifactId>jersey-serverartifactId>
	<version>2.0version>
dependency>
<dependency>
	<groupId>org.glassfish.jersey.containersgroupId>
	<artifactId>jersey-container-servletartifactId>
	<version>2.0version>
dependency>


<dependency>
	<groupId>org.glassfish.jersey.extgroupId>
	<artifactId>jersey-spring3artifactId>
	<version>2.2version>
dependency>

代码示例

// 使用Spring的Service注解生成实现类
@Service
public class WorkServiceImpl implements WorkService {
     
	...
}

@Path("/work")
public class WorkResource {
     

	// 使用Spring的Autowired注解
	@Autowired
	private WorkService	workService;

	@Path("/")
	@POST
	@Produces(MediaType.TEXT_PLAIN)
	public void accept(@BeanParam WorkVO work) {
     
		workService.accept(work);
	}
}

可能会遇到的问题

一般情况下,上边代码中的workService可以被正常调用。但是如果项目中WorkService接口有多个实现类,此时在Spring环境下就不可以按照接口类型(byType)进行注入了,而只能按照名称(byName)注入,所以需要在@Service中增加beanName,例如:

@Service("weixinWorkService")
public class WeixinWorkServiceImpl implements WorkService {
     
	...
}

@Service("appWorkService")
public class AppWorkServiceImpl implements WorkService {
     
	...
}

这时如果想在WorkService中注入WeixinWorkServiceImpl,我们可能首先想到的是使用javax.annotation.Resource注解,将代码修改成:

@Path("/work")
public class WorkResource {
     

	// 使用Javax的Resource注解
	@Resource(name = "weixinWorkService")
	private WorkService	workService;

	@Path("/")
	@POST
	@Produces(MediaType.TEXT_PLAIN)
	public void accept(@BeanParam WorkVO work) {
     
		workService.accept(work);
	}
}

但运行代码后发现控制台会报出空指针异常,然后定位到是workService为null导致的。

后来经过一系列尝试并追踪到相关源码才发现,原来Jersey-Spring3组件只支持Spring的@Autowired和@Qualifier,根本就不会解析@Resource。

Jersey-Spring3中负责解析注入组件的是org.glassfish.jersey.server.spring.AutowiredInjectResolver类。

public class AutowiredInjectResolver implements InjectionResolver<Autowired> {
     

 	@Override
    public Object resolve(Injectee injectee, ServiceHandle<?> root) {
     
        AnnotatedElement parent = injectee.getParent();
        String beanName = null;
        if(parent != null) {
     
        	// 划重点:解析@Qualifier注解,尝试获取beanName
            Qualifier an = parent.getAnnotation(Qualifier.class); 
            if(an != null) {
     
                beanName = an.value();
            }
        }
        return getBeanFromSpringContext(beanName, injectee.getRequiredType());
    }

    private Object getBeanFromSpringContext(String beanName, Type beanType) {
     
        Class<?> bt = getClassFromType(beanType);
        // 划重点:如果beanName不为空,则通过名称获取Spring 
        if(beanName != null) {
      bean
            return ctx.getBean(beanName, bt);
        }
        // 划重点:如果beanName为空,则按照类型获取
        Map<String, ?> beans = ctx.getBeansOfType(bt);
        // 划重点:如果未获取到bean或者获取到多个bean,则返回null。
        // 如果一个接口有多个实现类但没有定义@Qualifier时,注入也会失败,运行代码后会报出NPE。
        if(beans == null || beans.size() != 1) {
     
            LOGGER.warning(LocalizationMessages.NO_BEANS_FOUND_FOR_TYPE(beanType)); 
            return null;
        }
        return beans.values().iterator().next();
    }
}

找到原因后,解决就很容易了。

@Path("/work")
public class WorkResource {
     

	// 同时使用Autowired和Qualifier
	@Autowired
	@Qualifier(name = "weixinWorkService")
	private WorkService	workService;

	......
}

小结

  1. Jersey2支持通过注解与Spring进行整合,但仅支持@Autowired和@Qualifier。
  2. 不同框架或者组件对于注解的支持范围可能是不同的。因为平时使用Spring比较多,所以很容易混淆。
  3. 尽量使用统一的技术栈。例如,在没有特殊情况下,Spring环境可以使用SpringMVC替换Jersey。

你可能感兴趣的:(开发框架)