简体   繁体   English

开发Java API并将其包含在Spring App中

[英]Developing a Java API and including it in a Spring App

We have a large Spring based App that includes different modules but also custom APIs. 我们有一个大型的基于Spring的应用程序,其中包括不同的模块以及自定义API。 While there are modules that need a Spring context since they just wrap parts of the domain model we think that some of our APIs do not. 尽管有些模块需要Spring上下文,因为它们仅包装了部分域模型,但我们认为某些API不需要。

For example we wrote a wrapper around Jackson / Jersey to provide and consume REST services. 例如,我们围绕Jackson / Jersey编写了一个包装器,以提供和使用REST服务。 There is a central interface to access this API. 有一个访问此API的中央接口。 The implementation however needs another class and that another and so on. 但是,该实现需要另一个类以及另一个类,依此类推。 So a simple initialization would be 所以一个简单的初始化是

A a = new A(new B(new C(), new D(new E())))

Which we currently are saved from using @Inject . 我们目前通过使用@Inject来保存。 The context for this API scans the package and then gets imported into the target app. 此API的上下文扫描程序包,然后将其导入到目标应用程序中。

<import resource="classpath:api-context.xml" />

We don't feel that comfortable with this and want to kick the spring context out of the REST wrapper, meaning we want the API not to require one, but are not sure how to do it. 我们对此感到不满意,希望将Spring上下文排除在REST包装之外,这意味着我们希望API不需要一个,但不确定如何做到这一点。 It should mean either of the following two: 它应表示以下两个之一:

constructor arguments 构造函数参数

In the target context this will require the creation of several beans each initialized with its dependencies 在目标上下文中,这将需要创建几个Bean,每个Bean都使用其依赖项进行初始化

<bean id="a" class="...A">
    <constructor-arg>
        <ref = b " />
    </constructor-arg>
</bean>

<bean id="b" class="...B">
    <constructor-arg>
        <ref = c " />
    </constructor-arg>
</bean>
<!-- And so on -->

Getters and Setters 吸气剂和二传手

Or, assuming that A is a specific implementation of the AInterface and AInterface is the central access we could just say, A uses a certain implementation of BInterface by default and so on and actually set them internally with new: 或者,假设AAInterface的特定实现,而AInterface是我们可以说的中央访问,则A默认使用BInterface的某个实现,依此类推,并在内部使用new对其进行实际设置:

public class A implements AInterface {
    private BInterface b = new B();
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}
// and so on

Then in my target context I can initialize the central access with one line if I want to use the default configuration 然后在目标上下文中,如果要使用默认配置,我可以用一行初始化中央访问

<bean id="a" class="...A" />

or use properties to set its B. Then however if I want to change something farther down the line I'd have to initialize all beans and set the properties. 或使用属性来设置其B。但是,如果我想在线下进行一些更改,则必须初始化所有bean并设置属性。

Also it does not seem clean to me if I use new for a service outside my tests. 如果我在测试之外将new用于服务,这对我来说似乎也不干净。


So we're wondering how do other API developers make their interfaces and beans accessible without relying on a context import (which btw also clutters up the target context with many potentially unneeded beans, like for example if an API provides several services and I only want to use one)? 因此,我们想知道其他API开发人员如何在不依赖上下文导入的情况下使他们的接口和Bean可以访问(顺便说一句,它也使许多可能不需要的Bean杂乱了目标上下文,例如,某个API提供了几种服务,而我只想用一个)?


edit 编辑

Not sure if any of this is better: 不知道这是否更好:

public class A implements AInterface {
    private BInterface b
    public A() {
        b = new B();
    }
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}

or 要么

public class A implements AInterface {
    private BInterface b
    public A(B b) {
        this.b = b;
    }
}

The latter feels the best from test point of view but it brings us back to the chain I described above where I'll have to initialize all depending beans in my context before I can initialize A. That feels like too much configuration overhead. 从测试的角度来看,后者感觉是最好的,但它使我们回到了上面描述的链,在该链中,我必须先初始化上下文中的所有依赖bean,然后才能初始化A。这感觉像是过多的配置开销。

One could argue that that's quite normal that all dependencies need to be initialized before using a class and that we should refactor our code. 有人可能会说这很正常,在使用类之前,所有依赖项都需要初始化,并且我们应该重构代码。 Then however we'll end up with a lot of utility / helper classes which are also not the best design as they are hard to replace or test. 然后,我们将得到许多实用程序/帮助程序类,它们也不是最佳设计,因为它们很难替换或测试。

Basically, if your API does not need the Spring context, there is really no reason for putting it there. 基本上,如果您的API不需要Spring上下文,那么实际上没有理由将其放在那里。

Please note that the second method you suggested: 请注意,您建议的第二种方法是:

public class A implements AInterface {
    private BInterface b = new B();
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}

Its a bit problematic becasue you initialize interface inside your class, that will cause you problems with testing since you cannot mock these objects. 因为在类中初始化接口会有些问题,因为您无法模拟这些对象,因此会导致测试问题。 A better solution is to initialize it in the constructor of the class using it. 更好的解决方案是使用它在类的构造函数中对其进行初始化。

Just define all your beans to load lazily by default, and then you won't instantiate services you don't use. 只需将所有bean定义为默认情况下延迟加载,然后就不会实例化不使用的服务。

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>

See http://static.springsource.org/spring/docs/2.0.x/reference/beans.html#beans-factory-lazy-init for more details. 有关更多详细信息,请参见http://static.springsource.org/spring/docs/2.0.x/reference/beans.html#beans-factory-lazy-init

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM