【Spring学习笔记 二】构建第一个Sping框架程序

简介: 【Spring学习笔记 二】构建第一个Sping框架程序

上一篇Blog我们大致了解了Spring的历史由来,以及Spring的核心思想:IOC和AOP,以及IOC的实现手段DI,并且了解了Spring的分层结构体系,本篇Blog就来快速上手一个Spring框架程序,看看Spring的这些核心思想和理论基础是如何在实践中发挥作用的。

初始化一个Spring程序

接下来我们就按照步骤初始化一个Spring程序:

1 新建Java Web项目

因为我们是搞Web开发么,所以这次依然选择构建一个Web程序

选择配件模块时依然跳过,在学习的过程中依次向pom.xml中加才更能领会配置意义。

2 pom.xml中引入Spring依赖

在maven的pom.xml文件中我们引入Spring的依赖,从网址Maven坐标搜索查看要引入的坐标:

找到Maven的坐标后加入依赖即可:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.9</version>
        </dependency>

上篇Blog我们提到spring-context模块建立在由 core和 beans 模块基础上,我们一般只需要在Maven中配置spring-context,就会自动将它的其它依赖,例如beans和core导入到项目中,如下图所示:

3 创建HelloSpring类

接下来我们在代码中创建HelloSpring类来测试如何通过Spring的IOC进行bean的注入:

package com.example.Spring.model;
import lombok.Data;
@Data
public class HelloSpring {
    private String message;
    private String from;
    public void show(){
        System.out.println(message+" "+ from);
    }
}

这里使用了lombook的注解@Data,这个注解帮我们实现了属性的get和set方法,注入时是依赖这些方法的,所以这个注解必须加上。

4 新建applicationContext.xml文件

在resources文件夹下新建applicationContext.xml.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
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--bean就是java对象 , 由Spring创建和管理-->
    <bean id="helloProperty" class="com.example.Spring.model.HelloSpring">
        <property name="message" value="tml first Spring from helloProperty"/>
        <property name="from" value="by property"/>
    </bean>
</beans>

5 创建测试类并进行测试

接下来我们就来测试下Spring的实现方式:

import com.example.Spring.model.HelloSpring;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest {
    @Test
    public void HelloSpringTest(){
        //解析beans.xml文件,生成管理相应的bean对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //getBean : 参数即为spring配置文件中bean的id
        System.out.println("属性注入方式===========================================================");
        HelloSpring helloProperty = (HelloSpring) context.getBean("helloProperty");//强制转换为Hello类型的
        helloProperty.show();
    }
}

打印结果如下:

Bean的注入方式

Bean的依赖注入方式有两种,一种是属性注入,一种是构造方法注入,其中构造方法注入又可以分为按照属性的索引、属性的类型和属性的名称三种方式。

1 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
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--bean就是java对象 , 由Spring创建和管理-->
    <bean id="helloProperty" class="com.example.Spring.model.HelloSpring">
        <property name="message" value="tml first Spring from helloProperty"/>
        <property name="from" value="by property"/>
    </bean>
    <bean id="helloCIndex" class="com.example.Spring.model.HelloSpring">
        <!-- index指构造方法 , 下标从0开始 -->
        <constructor-arg index="1" value="by constructor-index"/>
        <constructor-arg index="0" value="tml first Spring from hellCIndex"/>
    </bean>
    <bean id="helloCName" class="com.example.Spring.model.HelloSpring ">
        <!-- name指参数名 -->
        <constructor-arg name="message" value="tml first Spring from hellCName"/>
        <constructor-arg name="from" value="by constructor-name"/>
    </bean>
    <bean id="helloCType" class="com.example.Spring.model.HelloSpring ">
        <!-- type指参数类型,如果不指定索引顺序,那么按照配置顺序对应属性,所以最好也指定好索引顺序 -->
        <constructor-arg type="java.lang.String" index="0" value="tml first Spring from hellCType"/>
        <constructor-arg type="java.lang.String" index="1" value="by constructor-type"/>
    </bean>
</beans>

2 HelloSpring类增加注解

属性注入必须要求有无参的构造函数,而构造器注入则要求必须有有参的构造函数【且参数必须和构造函数的参数一一对应,不能多也不能少否则会报找不到这样的构造函数】,本质是因为SpringContext利用无参的构造函数创建一个对象,然后利用setter方法赋值。所以如果无参构造函数不存在,Spring上下文创建对象的时候便会报错。所以如果想两个都用,那么必须显式的实现两种构造函数:

package com.example.Spring.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HelloSpring {
    private String message;
    private String from;
    public void show(){
        System.out.println(message+" "+ from);
    }
}

所以这三个注解我们必须都加上:@Data,@AllArgsConstructor,@NoArgsConstructor

3 实现方式整体测试

那么接下来我们用单元测试看下执行结果:

import com.example.Spring.model.HelloSpring;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloTest {
    @Test
    public void HelloSpringTest(){
        //解析beans.xml文件,生成管理相应的bean对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //getBean : 参数即为spring配置文件中bean的id
        System.out.println("属性注入方式===========================================================");
        HelloSpring helloProperty = (HelloSpring) context.getBean("helloProperty");//强制转换为Hello类型的
        helloProperty.show();
        System.out.println("构造器-属性索引顺序 注入方式===========================================================");
        HelloSpring helloCIndex = (HelloSpring) context.getBean("helloCIndex");//强制转换为Hello类型的
        helloCIndex.show();
        System.out.println("构造器-属性名 注入方式===========================================================");
        HelloSpring helloCName = (HelloSpring) context.getBean("helloCName");//强制转换为Hello类型的
        helloCName.show();
        System.out.println("构造器-属性类型 注入方式===========================================================");
        HelloSpring helloCType = (HelloSpring) context.getBean("helloCType");//强制转换为Hello类型的
        helloCType.show();
    }
}

执行结果如下:

Sping的方式更换实现类

我们说IOC的实现方式可以更便捷的为我们更换实现类,接下来我们测试下:

1 创建Service和Dao相关类

我们沿用三层架构的方式,先把相关的Service和Dao创建完毕,整体目录结构如下

PersonService

package com.example.Spring.service;
public interface PersonService {
    void showPersonMessage();
}

PersonServiceImpl

package com.example.Spring.serviceImpl;
import com.example.Spring.dao.PersonDao;
import com.example.Spring.service.PersonService;
import lombok.Data;
@Data
public class PersonServiceImpl implements PersonService {
    private PersonDao personDao;
    @Override
    public void showPersonMessage() {
       personDao.showPersonMessage();
    }
}

PersonDao

package com.example.Spring.dao;
public interface PersonDao {
    void showPersonMessage();
}

PersonDaoFirstImpl

package com.example.Spring.daoImpl;
import com.example.Spring.dao.PersonDao;
import lombok.Data;
@Data
public class PersonDaoFirstImpl implements PersonDao {
    private String message;
    @Override
    public void showPersonMessage() {
        System.out.println("PersonDaoFirstImpl 实现当前方法");
    }
}

PersonDaoSecondImpl

package com.example.Spring.daoImpl;
import com.example.Spring.dao.PersonDao;
import lombok.Data;
@Data
public class PersonDaoSecondImpl implements PersonDao {
    private String message;
    @Override
    public void showPersonMessage() {
        System.out.println("PersonDaoSecondImpl 实现当前方法");
    }
}

2 配置beans.xml文件

我们对这几个实现类分别进行配置,并配置他们的依赖关系,其中ref表示依赖的类型id。

<bean id="personServiceImpl" class="com.example.Spring.serviceImpl.PersonServiceImpl">
        <property name="personDao" ref="personDaoSecondImpl"/>
    </bean>
    <bean id="personDaoFirstImpl" class="com.example.Spring.daoImpl.PersonDaoFirstImpl">
        <property name="message" value="PersonDaoFirstImpl 实现当前方法"/>
    </bean>
    <bean id="personDaoSecondImpl" class="com.example.Spring.daoImpl.PersonDaoSecondImpl">
        <property name="message" value="PersonDaoSecondImpl 实现当前方法"/>
    </bean>

3 编写测试类进行测试

然后我们编写测试类进行测试:

import com.example.Spring.serviceImpl.PersonServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonServiceTest {
    @Test
    public void PersonServiceTest(){
        //解析beans.xml文件,生成管理相应的bean对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //getBean : 参数即为spring配置文件中bean的id
        PersonServiceImpl personServiceImpl = (PersonServiceImpl) context.getBean("personServiceImpl");
        personServiceImpl.showPersonMessage();
    }
}

打印结果如下:

所以当我们想要更换实现的时候,不需要在每个用到PersonDao的地方重新构建替换实现,而仅仅在配置文件上的ref进行以下修改即可,调用方再也不需要关系依赖对象的实现方式,也不再需要费力的构建它们了。

总结一下

这篇博客详细的实践了Spring的IOC思想,对这部分内容有了一个较深的体会,事实上,正是因为有了IOC,我们发现调用方再也不需要关心细节而只需要关心业务逻辑和需求了,这一切都可以通过配置和描述进行统一管理,这就是框架的美妙之处吧。

相关文章
|
1月前
|
XML 安全 Java
|
14天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
10天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
38 13
|
22天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
40 5
|
20天前
|
前端开发 Java 开发者
这款免费 IDEA 插件让你开发 Spring 程序更简单
Feign-Helper 是一款支持 Spring 框架的 IDEA 免费插件,提供 URL 快速搜索、Spring Web Controller 路径一键复制及 Feign 与 Controller 接口互相导航等功能,极大提升了开发效率。
|
1月前
|
缓存 Java 数据库连接
Spring框架中的事件机制:深入理解与实践
Spring框架是一个广泛使用的Java企业级应用框架,提供了依赖注入、面向切面编程(AOP)、事务管理、Web应用程序开发等一系列功能。在Spring框架中,事件机制是一种重要的通信方式,它允许不同组件之间进行松耦合的通信,提高了应用程序的可维护性和可扩展性。本文将深入探讨Spring框架中的事件机制,包括不同类型的事件、底层原理、应用实践以及优缺点。
67 8
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
265 2
|
14天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
21天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
76 14
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
61 1
SpringBoot入门(7)- 配置热部署devtools工具