当前位置: 首页 > java>阅读正文

Java框架-SpringFramework参考文档

2021.10.30 朱丰华 247 次 留下评论 7284字

SpringFrameWork是Spring家族中的一个基础开源框架,官方资料传送门:Spring Framework

Spring,翻译为“春天”,当然你也可以理解为”给java开发带来春天“的框架,目前几乎所有主流的Java技术都与Spring有关。

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

  • JAVA EE应该更加容易使用。
  • 面向对象的设计比任何实现技术(比如JAVA EE)都重要。
  • 面向接口编程,而不是针对类编程。Spring将使用接口的复杂度降低到零。
  • 代码应该易于测试。Spring框架会帮助你,使代码的测试更加简单。
  • JavaBean提供了应用程序配置的最好方法。
  • 在Java中,已检查异常(Checked exception)被过度使用。框架不应该迫使你捕获不能恢复的异常。

Spring框架的雏形是发布于2002年的interface21框架,该框架经过重新设计后于2004年发布了Spring之1.0版本。

Spring是一个轻量级的、控制反转(IOC)、面向切面(AOP)的框架。

在很多情况下Spring框架也指的是Spring家族,Spring非常庞大,它的官网地址:Spring.io.

在Spring发展起来后,Spring由于整合了太多技术,使用起来配置比较复杂,也有人称之为“配置地狱”,官方推荐使用SpringBoot进行开发。

认识SpringIOC

SpringIOC全称为:Spring Inverse Of Controller,翻译为控制反转。

Spring是一个”自助机“模型。这里的IOC是针对”用户“来说的。

本文所说的”自助机“,可以泛指很多东西,比如”自助银行“,”自助取餐“,等等。

以”取餐柜“来举例,原有的送餐模型中取决于送餐员,用户是没有选择的只能在特定时间等待送餐员送餐,而自从发明了”取餐柜“,用户可以随时从取餐柜中取餐,相对从”被动“,转为”主动“。这里的”取餐“,换成”获取对象“,那么控制反转主要指的是:用户获取对象的方式反转

控制反转能很大程度上解决”编译期“异常,对代码的维护更容易。

以下,编写一个基于xml的IOC示例,官方文档可参考:Spring Framework | Core Technologies,按照官方说法,在Spring5开始最低你应该使用java8,以下示例至少使用java8进行测试。

首先导入springmvc依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
</dependencies>

接下来,创建一个实体类Hello

package pojo;

public class Hello {
    private String str;

    public Hello() {
    }

    public Hello(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }
}

接下来,创建一个beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="hello" class="pojo.Hello">
        <property name="str" value="Spring"/>
    </bean>

</beans>

接下来,创建一个Test类

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.Hello;

public class Test {

    public static void main(String[] args) {
        ApplicationContext ApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Hello hello = (Hello) ApplicationContext.getBean("hello");
        System.out.println(hello);
    }

}

程序执行结果如下:

Hello{str='Spring'}

通过上述示例,我们可以发现,我们不再需要new创建对象,而是直接从Spring的ApplicationContext(应用上下文)对象中使用getBean方法获取。这样一来,对象就被Spring容器托管了。

对象创建方式

在Spring中,对象是托管在容器中的,这里的容器一般指的是ApplicationContext。

创建ApplicationContext的方式不止一种,使用ClassPathXmlApplicationContext创建时指定不同的xml,得到的“容器”对象也不同,这也意味着容器有很多种。

在创建容器时,就自动创建了beans,也就是说类被加载并实例化了,而getBean只是获取对象的引用,一个bean指的是实例化一个对象。

如果希望在创建容器时,不立刻加载,需要在bean标签添加lazy-init

<bean id="hello" class="pojo.Hello" lazy-init="true">
    <property name="str" value="Spring"/>
</bean>

在创建对象时,默认是无参构造,如果需要指定构造方法,需要添加constructor-arg标签

<bean id="hello" class="pojo.Hello" lazy-init="true">
    <constructor-arg name="str" value="Spring"/>
</bean>

其中,name表示属性名,value表示属性值,如果需要指定bean中的对象,可以使用ref属性指定,bean中对象名指的是bean的id。

bean文件可以分模块,也就是在一个bean.xml中可以使用import标签引入其他bean.xml,这样很方便的管理大量的bean对象。

DI依赖注入

依赖注入,指的是创建bean对象并把bean对象注入到容器中的过程。

依赖注入 Dependence Injection,可参考:Dependency Injection | Spring Framework

依赖注入,有多种方式,除了上面说的“构造器注入”,还有set注入、扩展方式注入。其中set注入是掌握重点。

Set注入,需要使用property标签,由类型不同故用法也不同。

  • 对于基本数据类型、String类型,可以使用value注入
  • 对于自定义数据类型,可以使用ref注入
  • 对于数组,可以先嵌套array标签,再嵌入value或ref等标签
  • map注入时,使用entry对象,例如
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>

对于null注入时,使用<null/>标签注入,对于properties可以使用pros标签,再套pro标签写入每个key和value。

对于其他对象,注入方式非常接近,一个property标签对应一个属性,对于多个属性的注入,可以并排多个property表情。

其中额外注入有p注入以及c注入,需要引入额外命名空间,例如下面的p注入例子

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="classic" class="com.example.ExampleBean">
        <property name="email" value="someone@somewhere.com"/>
    </bean>

    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="someone@somewhere.com"/>
</beans>

一旦在命名空间中添加了p约束,就可以在后续的标签中使用p:属性=xxx,它等价于property标签,另外的c注入,则表示constructor-arg的简化方式。

Bean作用域

bean是存在作用域的,此部分内容对应官方文档:Bean Scope | Spring Framework

前面说过,一个bean标签实例化一个对象,那么你也可以显示增加一个scope标签值为singleton,效果是等价的

<bean id="accountService" class="com.something.DefaultAccountService"/>
<!-- 等价于 -->
<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
ScopeDescription
singleton(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.
prototypeScopes a single bean definition to any number of object instances.
requestScopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.
sessionScopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.
applicationScopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.
websocketScopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

如果你想要多例,使用的是prototype,也就是“原型”,每一次调用时会创建一个对象,可以调用对象的hashCode()验证。

除了单例和原型,其他作用域仅在web开发时使用。

Bean的自动装配

默认情况下,我们手动配置每个bean的属性。

Spring提供了bean的自动装配机制:Spring自动在上下文中寻找,并进行bean的自动装配。

bean的自动装配,是Spring提供的bean依赖的一种方式,在Spring中,共有3种bean装配方式:

  • 在xml显式配置
  • 在Java中显式配置
  • 隐式的自动装配【重要】

自动装配,实际中是指自动为bean配置属性,属性只能是已经导入容器中的其他bean。需要设置xml的autowire属性,有多种方式

  • byName:会自动在容器上下文中查找,和当前对象set方法的值对应的beanid
  • byType:会自动在容器上下文中查找,和当前对象属性类型相同的bean

在使用byName配置时,需要保证所有beanid均是唯一的。

自动装配支持注解,首先需要在xml中配置支持注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

那么就可以使用@Autowired自动装配属性,该注解也可以用于方法上,默认是byType

public class MovieRecommender {

    private final CustomerPreferenceDao customerPreferenceDao;

    @Autowired
    private MovieCatalog movieCatalog;

    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }

    // ...
}

该注解有一个required属性,设置为false时容器中不存在也不报错

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired(required = false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // ...
}

允许为空也可以使用另一个注解@Nullable

public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
        ...
    }
}

当容器中存在多个相同类型的bean,那么默认的byType自动装配就会失败,可以添加另一个注解@Qualifier指定属性的beanid

public class MovieRecommender {

    @Autowired
    @Qualifier("main")
    private MovieCatalog movieCatalog;

    // ...
}

与@Autowire同样作用的还有@Resource注解,它对应的属性是name,不过更推荐使用@Autowired,它会先匹配类型,而@Resource会先匹配名称

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Resource(name="myMovieFinder") 
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

使用注解开发

Spring支持全注解开发,完全取代xml。

要开启注解开发支持,必须要导入aop依赖包,在springmvc依赖默认包含了该依赖。

等待更新。。

本篇完,还有疑问?留下评论吧

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注