Spring集成Jersey(11)

转自https://www.jianshu.com/p/88f97b90963c

Spring集成Jersey

在正常应用中,Jersey只是作为服务端接口存在,而接口需要调用Service来完成具体的业务。在Jersey中,默认使用的是HK2这个DI/AOP框架来完成服务管理和注入的,所以我们前面看到的@Contract,@Service等,都是HK2框架提供的。但是我们平时用的更多的,肯定是Spring容器,所以我们需要把Jersey和Spring集成起来。

但是注意一点,Jersey和Spring集成,更多的应该叫做Jersey来集成Spring,或者叫Jersey来启动Spring框架,使用的是HK2-Spring Bridge(HK2-Spring桥)依赖完成的。所以,我们一般不会把Jersey和SpringMVC混合起来使用,如果有类似网站门户和WebAPI共存的情况下,也会区分两个项目。

那首先来看下Jersey怎么集成Spring:

  • 引入Jersey-Spring依赖:
<dependency>
    <groupId>org.glassfish.jersey.ext</groupId>
    <artifactId>jersey-spring4</artifactId>
    <version>2.26</version>
</dependency>

通过依赖包的名称,我们可以看出来,这里集成的是Spring4版本。当这个包引入之后,我们看看增加了哪些包到项目中:

 

image.png

 

如果我们需要使用自己的Spring版本,或者自己来控制Spring的依赖,我们可以在<dependency>中使用<exclusions>去掉Spring的依赖。

这里需要注意一下,第一次配置Spring+Jersey的时候,很容易出现java.lang.NoClassDefFoundError: org/glassfish/jersey/internal/inject/Binder异常,造成的原因是因为Jersey的版本不一致。注意jersey-spring4的版本都是2.26的,而我们之前使用的jersey都是2.25的,所以需要把各个版本调整一致即可:

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.26</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.26</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.26</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-spring4</artifactId>
        <version>2.26</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>

使用xml方式

首先创建一个简单的服务接口和对应实现:

public interface ISomeService {

    void doSomething(String msg);
}

创建对应的实现:

public class SomeServiceImpl implements ISomeService {

    @Override
    public void doSomething(String msg) {
        System.out.println("do some thing:" + msg);
    }

}

创建资源类:

@Path("spring")
public class SpringResource {

    @Autowired
    private ISomeService someService;

    @Autowired
    private ApplicationContext ctx;

    public void setSomeService(ISomeService someService) {
        this.someService = someService;
    }

    @Path("resource1")
    @GET
    public String resource1(@QueryParam("msg") String msg) {
        System.out.println(this);
        System.out.println(ctx.getBeansOfType(SpringResource.class));
        this.someService.doSomething(msg);
        return "success";
    }
}

在这个类中,注意几个点:
1,使用@Autowired标签尝试从spring容器中注入ISomeService;
2,同时注入ApplicationContext,并且在我们的资源方法中,使用ctx.getBeansOfType来查看我们的SpringResource是否被Spring管理;

添加一个Spring的配置文件applicationContext.xml,并在其中添加两个bean:

<bean id="someService" class="cn.wolfcode.jersey._10spring.SomeServiceImpl" />
<bean class="cn.wolfcode.jersey._10spring.SpringResource" />

因为使用@Autowire标签,所以没有使用<property>注入;

配置web.xml:

<filter>
    <filter-name>JerseyServletContainer</filter-name>
    <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>cn.wolfcode.jersey</param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </init-param>
    <init-param>
        <param-name>jersey.config.server.provider.classnames</param-name>
        <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>JerseyServletContainer</filter-name>
    <url-pattern>/webapi/*</url-pattern>
</filter-mapping>

注意两个参数:
1,jersey.config.server.provider.classnames,使用该参数添加Provider和Feature;
2,contextConfigLocation:通过该参数设置Spring的配置文件地址。注意,jersey中默认的spring配置文件地址就是classpath:applicationContext.xml

测试:当请求GET localhost:8082/webapi/spring/resource1?msg=wolfcode.cn,我们可以看到后台控制台输出:

cn.wolfcode.jersey._10spring.SpringResource@7bf502a0
{cn.wolfcode.jersey._10spring.SpringResource#0=cn.wolfcode.jersey._10spring.SpringResource@b090cd5}
do some thing:wolfcode.cn

如果只是简单看一眼这个输出,仿佛输出都是正确的,并且也正确的返回了success字符串。

注意:当我们再仔细看这段输出,就会发现,我们实际使用的SpringResource其实并不是Spring容器中的SpringResource,所以我们能得出这样的结论:如果只是在applicationContext.xml中配置资源类,资源类本身是不会被Spring管理的,但是资源类中的@Autowired标签是起作用了的。
所以,我们需要修改我们的资源类,在资源类上再添加@Component标签:

@Component
@Path("spring")
public class SpringResource {

再次执行测试请求:

cn.wolfcode.jersey._10spring.SpringResource@7002e440
{cn.wolfcode.jersey._10spring.SpringResource#0=cn.wolfcode.jersey._10spring.SpringResource@7002e440}
do some thing:wolfcode.cn
cn.wolfcode.jersey._10spring.SpringResource@7002e440
{cn.wolfcode.jersey._10spring.SpringResource#0=cn.wolfcode.jersey._10spring.SpringResource@7002e440}
do some thing:wolfcode.cn

可以看到,这次确实Jersey使用的资源对象就是Spring容器中管理的资源对象了。
注意:可能这里的写法很奇怪,就是我们在applicationContext.xml中配置了SpringResource类,在SpringResource类上面又添加了@Component注解。如果要使用xml的配置方式,也就必须要这样做了。

使用全注解方式

上面的配置我们发现,要让资源类注入依赖的服务对象,是很简单的,只需要把依赖的服务对象配置到spring容器中,并使用@Autowired标签即可。但是如果要让Jersey的资源类也被Spring容器管理(才能享受AOP等功能),就需要在资源类上添加@Component,并且在Spring的配置文件中再次配置该bean。

下面我们换成全注解的方式。首先修改我们的applicationContext.xml:

<context:component-scan base-package="cn.wolfcode.jersey._10spring" />

配置组件扫描;
其次,修改服务对象,添加@Service注解:

@Service
public class SomeServiceImpl implements ISomeService {

这次,我们的资源类不用修改:

@Component
@Path("spring")
public class SpringResource {

也需要添加@Component注解;
执行测试请求:

cn.wolfcode.jersey._10spring.SpringResource@1a1b0074
{springResource=cn.wolfcode.jersey._10spring.SpringResource@1a1b0074}
do some thing:wolfcode.cn
cn.wolfcode.jersey._10spring.SpringResource@1a1b0074
{springResource=cn.wolfcode.jersey._10spring.SpringResource@1a1b0074}
do some thing:wolfcode.cn

测试通过。

使用ResourceConfig方式

上面的测试案例中,我们使用的web.xml方式来配置的,接下来,我们使用ResourceConfig的方式。资源类,服务类,Spring配置文件都不用修改,修改我们的ResoureConfig类:

@ApplicationPath("webapi")
public class RestApplication extends ResourceConfig {

    public RestApplication() {
        this.packages("cn.wolfcode.jersey");
        this.register(MultiPartFeature.class);
        this.property("contextConfigLocation","classpath:applicationContext.xml");
        this.register(MyRequestTestFilter.class).register(MyResponseTestFilter.class);
    }
}

在其中添加contextConfigLocation参数,指向Spring配置文件即可。

Provider的注入

当Jersey容器交给Spring管理之后,Jersey中的各种Provider也可以交给Spring容器管理。

我们创建一个过滤器:

@Provider
@Component
public class MyResponseTestFilter implements ContainerResponseFilter {

    @Autowired
    private ApplicationContext ctx;

    @Override
    public void filter(ContainerRequestContext requestContext,
            ContainerResponseContext responseContext) throws IOException {
        System.out.println("===my response filter test===");
        System.out.println(this);
        System.out.println(ctx.getBeansOfType(MyResponseTestFilter.class));
    }

}

注意,在该过滤器上,我们添加了@Provider和@Component注解。很明显,@Provider是提供给Jersey自动发现的,@Component是让该Filter交给Spring容器管理。

再来看这次我们的ResourceConfig类:

@ApplicationPath("webapi")
public class RestApplication extends ResourceConfig {

    public RestApplication() {
        this.packages("cn.wolfcode.jersey");
        this.register(MultiPartFeature.class);
        this.property("contextConfigLocation","classpath:applicationContext.xml");
        this.register(MyRequestTestFilter.class);
    }
}

注意,在ResourceConfig中,我们并没有配置MyResponseTestFilter;
我们来执行一次测试请求:

cn.wolfcode.jersey._10spring.SpringResource@b6653b0
{springResource=cn.wolfcode.jersey._10spring.SpringResource@b6653b0}
do some thing:wolfcode.cn
===my response filter test===
cn.wolfcode.jersey._10spring.MyResponseTestFilter@128994a0
{myResponseTestFilter=cn.wolfcode.jersey._10spring.MyResponseTestFilter@128994a0}

注意===my response filter test===之后的这块内容,可以看到,我们的responsefilter确实已经配置成功,并且可以发现,Jersey使用的filter实例确实是由Spring容器管理和提供的。

小结

在本节中,我们简单的看了一下Jersey和Spring容器的集成,其实真正起作用的还是HK2提供的SpringBridge类。如果有兴趣想了解Jersey和Spring的集成原理,可以看看org.glassfish.jersey.server.spring.SpringComponentProvider类的源码。
因为Springboot使用越来越多,下一节,我们介绍Springboot对Jersey的集成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将SpringJersey整合在一起,可以使用Spring提供的Spring Boot Starter来快速集成Jersey。 以下是整合步骤: 1. 在项目的pom.xml文件中添加以下依赖项: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> </dependency> ``` 这将为您提供JerseySpring Boot Starter Web的依赖项。 2. 创建一个ResourceConfig类,用于配置Jersey应用程序: ``` @Configuration public class JerseyConfig extends ResourceConfig { public JerseyConfig() { register(MyResource.class); } } ``` 在这里,我们注册了一个名为MyResource的资源类。您应该将MyResource替换为您自己的资源类。 3. 创建一个Spring Boot应用程序类,并将JerseyConfig类添加为一个bean: ``` @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public JerseyConfig jerseyConfig() { return new JerseyConfig(); } } ``` 这将确保JerseyConfig类被加载并配置了Jersey应用程序。 4. 创建一个资源类: ``` @Path("/hello") public class MyResource { @GET public String hello() { return "Hello, World!"; } } ``` 这是一个简单的资源类,它将响应GET请求并返回字符串“Hello, World!”。您可以将其替换为您自己的资源类。 5. 启动应用程序并测试: 运行应用程序并访问http://localhost:8080/hello。您应该看到“Hello, World!”的响应。 这就是将SpringJersey整合在一起的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值