我听说了很多关于Spring的事情,人们在网上说Spring是一个很好的web开发框架。简而言之,Spring框架到底是用来干什么的?为什么我要用它而不是纯Java。


当前回答

我认为这有两部分:

"What exactly is Spring for" -> see the accepted answer by victor hugo. "[...] Spring is [a] good framework for web development" -> people saying this are talking about Spring MVC. Spring MVC is one of the many parts of Spring, and is a web framework making use of the general features of Spring, like dependency injection. It's a pretty generic framework in that it is very configurable: you can use different db layers (Hibernate, iBatis, plain JDBC), different view layers (JSP, Velocity, Freemarker...)

注意,不使用Spring MVC,你也可以在web应用程序中很好地使用Spring。我想说,大多数Java web应用程序都这样做,同时使用其他web框架,如Wicket, Struts, Seam,…

其他回答

过去,Spring只是一个依赖注入框架(Guice, PicoContainer,…),但现在它是构建企业应用程序的完整解决方案。

spring依赖注入,当然,spring的核心仍然在那里(你可以在这里查看其他好的答案),但是还有更多来自spring的答案……

Spring现在有很多项目,每个项目都有一些子项目(http://spring.io/projects)。当有人谈到spring时,你一定要弄清楚他说的是什么spring项目,是仅仅是spring核心,也就是spring框架,还是另一个spring项目。

值得一提的春季项目有:

Spring Security - http://projects.spring.io/spring-security/ Spring Webservices - http://projects.spring.io/spring-ws/ Spring集成- http://projects.spring.io/spring-integration/

如果你的应用程序需要一些更指定的功能,你也可以在那里找到:

Spring批处理框架设计,使批处理能够开发 批处理应用程序 Spring HATEOAS基于HATEOAS原理轻松创建REST API Spring Mobile和Spring Andriod用于移动应用程序开发 Spring Shell构建一个功能齐全的Shell(又名命令行)应用程序 Spring Cloud和Spring Cloud Data Flow用于云应用程序

还有一些小项目,比如spring-social-facebook (http://projects.spring.io/spring-social-facebook/)

你可以使用spring进行web开发,因为它有spring MVC模块,这是spring框架项目的一部分。或者你可以将spring与另一个web框架一起使用,比如struts2。

你可能想在一个web应用程序中使用Spring -

Spring MVC, which with 2.5+ allows you to use POJOs as Controller classes, meaning you don't have to extend from any particular framework (as in Struts or Spring pre-2.5). Controller classes are also dead simple to test thanks in part to dependency injection Spring integration with Hibernate, which does a good job of simplifying work with that ORM solution (for most cases) Using Spring for a web app enables you to use your Domain Objects at all levels of the application - the same classes that are mapped using Hibernate are the classes you use as "form beans." By nature, this will lead to a more robust domain model, in part because it's going to cut down on the number of classes. Spring form tags make it easier to create forms without much hassle.

此外,Spring是巨大的——所以在web应用程序中使用很多其他的东西你可能会感兴趣,比如Spring AOP或Spring Security。但上面列出的四件事描述了Spring在web应用程序中使用的常见组件。

基本上Spring是一个依赖注入框架,这种模式允许构建非常解耦的系统。

这个问题

例如,假设你需要列出系统的用户,并声明一个名为UserLister的接口:

public interface UserLister {
    List<User> getUsers();
}

也许一个实现访问一个数据库来获取所有的用户:

public class UserListerDB implements UserLister {
    public List<User> getUsers() {
        // DB access code here
    }
}

在你的视图中,你需要访问一个实例(只是一个例子,记住):

public class SomeView {
    private UserLister userLister;

    public void render() {
        List<User> users = userLister.getUsers();
        view.render(users);
    }
}

注意,上面的代码没有初始化变量userLister。我们该怎么办?如果我像这样显式地实例化对象:

UserLister userLister = new UserListerDB();

...我将视图与访问DB的类的实现结合在一起。如果我想从DB实现切换到另一个从逗号分隔的文件(记住,这是一个例子)获取用户列表的实现呢?在这种情况下,我将再次转到我的代码,并将上面的行更改为:

UserLister userLister = new UserListerCommaSeparatedFile();

这样的小程序没有问题,但是……在具有数百个视图和类似数量的业务类的程序中会发生什么?维护变成了噩梦!

Spring(依赖注入)方法

Spring所做的是使用XML文件或注释将类连接起来,这样所有的对象都由Spring实例化和初始化,并注入到正确的位置(servlet、Web框架、业务类、dao,等等,等等……)

回到Spring中的例子,我们只需要为userLister字段设置一个setter,并有一个像这样的XML文件:

<bean id="userLister" class="UserListerDB" />

<bean class="SomeView">
    <property name="userLister" ref="userLister" />
</bean>

或者更简单地用@Inject注释视图类中的字段:

@Inject
private UserLister userLister;

这样,当视图创建时,它将神奇地有一个UserLister准备工作。

List<User> users = userLister.getUsers();  // This will actually work
                                           // without adding any line of code

太棒了!不是吗?

如果您想使用UserLister接口的另一种实现呢?只需更改XML。 如果没有UserLister实现呢?编写UserLister的临时模拟实现,简化视图的开发。 如果我不想再使用Spring了怎么办?千万别用!您的应用程序没有与它耦合。控制反转:“应用程序控制框架,而不是框架控制应用程序”。

还有一些其他的依赖注入选项,在我看来,除了简单、优雅和稳定之外,Spring之所以如此有名,是因为SpringSource的人编写了许多pojo,这些pojo有助于将Spring与许多其他通用框架集成在一起,而不会对应用程序造成干扰。此外,Spring还有几个不错的子项目,比如Spring MVC、Spring WebFlow、Spring Security,还有一长串等等。

无论如何,我鼓励你阅读Martin Fowler关于依赖注入和控制反转的文章,因为他在这方面做得比我好。在了解了基本知识之后,看看Spring Documentation,在我看来,它是有史以来最好的Spring书籍。

Spring非常适合将类实例粘合在一起。你知道你的Hibernate类总是需要一个数据源,Spring将它们连接在一起(也有一个数据源的实现)。

数据访问对象总是需要Hibernate访问,Spring将Hibernate类连接到dao中。

此外,Spring基本上为您提供了一系列库的可靠配置,并指导您应该使用哪些库。

Spring真的是一个很棒的工具。(我说的不是Spring MVC,只是基本框架)。

其优点是依赖注入(DI)。这意味着将对象创建任务外包出去。让我用一个例子来解释。

public interface Lunch
{
   public void eat();
}

public class Buffet implements Lunch
{
   public void eat()
   {
      // Eat as much as you can 
   }
}

public class Plated implements Lunch
{
   public void eat()
   {
      // Eat a limited portion
   }
}

现在在我的代码中,我有一个类LunchDecide,如下所示:

public class LunchDecide {
    private Lunch todaysLunch;
    public LunchDecide(){
        this.todaysLunch = new Buffet(); // choose Buffet -> eat as much as you want
        //this.todaysLunch = new Plated(); // choose Plated -> eat a limited portion 
    }
}

在上面的类中,根据心情选择Buffet()或Plated()。但是这个系统是紧密耦合的。每次需要不同类型的对象时,我们都需要更改代码。在本例中,注释掉一行!假设有50个不同的人使用50个不同的类。那会是一团乱麻。在这种情况下,我们需要解耦系统。让我们重写LunchDecide类。

public class LunchDecide {
    private Lunch todaysLunch;
    public LunchDecide(Lunch todaysLunch){
        this.todaysLunch = todaysLunch
        }
    }

Notice that instead of creating an object using new keyword we passed the reference to an object of Lunch Type as a parameter to our constructor. Here, object creation is outsourced. This code can be wired either using Xml config file (legacy) or Java Annotations (modern). Either way, the decision on which Type of object would be created would be done there during runtime. An object would be injected by Xml into our code - Our Code is dependent on Xml for that job. Hence, Dependency Injection (DI). DI not only helps in making our system loosely coupled, it simplifies writing of Unit tests since it allows dependencies to be mocked. Last but not the least, DI streamlines Aspect Oriented Programming (AOP) which leads to further decoupling and increase of modularity. Also note that above DI is Constructor Injection. DI can be done by Setter Injection as well - same plain old setter method from encapsulation.