Spring框架原理 | IOC/DI | Bean

简介: Spring框架原理

☢Spring框架

be93eed2f89d468db9935a11eae7ccc5.jpeg

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


目的:解决企业应用开发的复杂性


功能:使用基本的JavaBean代替EJB


范围:任何Java应用

                                                   Spring + Spring MVC = Spring Boot


☢Spring架构图


💨组件介绍:


💫核心容器(IOC)


Core、Beans、Context、EL模块


Core模块:封装框架依赖的最底层部分,包括资源访问、类型转换及一些常用工具类


Beans模块:提供了框架的基础部分、包括反转控制和依赖注入。其中Beans Factory是容器核心,本质是"工厂设计模式"的实现,而且无需编程实现"单例设计模式",单例完全由容器控制,而且提倡面向接口编程,而非面向实现编程;所有应用程序对象及对象间关系由框架管理,从而真正把你从程序逻辑中吧维护对象之间的依赖关系提取出来,所有这些依赖关系都由BeansFactory来维护


Context模块:以Core和Beans为基础,集成Beans模块功能并添加资源绑定、数据验证、国际化、JavaEE支持、容器周期、事件传播等;核心接口是ApplicationContext


EL模块:提供强大的表达语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从Spring容器获取Bean,它也支持列表投影,选择和一般的列表聚合等


Test模块:Spring支持Junit和TestNG测试框架,而且还额外提供一些基于Spring的测试功能,如测试Web框架时,模拟Http请求的功能


💫面向切面编程模块(AOP)


面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。


OOP:面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。


💫数据访问模块(Data Access/Integration)


通过Spring提供的数据访问模块可以很方便地集成第三方的ORM框架,也可以使用Spring提供的JDBC模块实现数据的持久化


💫Web模块(Web)


Web模块建立在应用程序上下文模块之上,为基于Web的应用程序提供上下文,所以,Spring框架支持与Struts的集成。Web模块简化了处理多部分请求及将请求参数绑定到域对象的工作,并提供MVC的实现,即Spring MVC 这是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变为高度可配置的。MVC容纳了大量视图技术,包括JSP、Velocity、iText和POI


💫单元测试模块(Test)


单元测试模块提供了JUnit及TestNG,用于实现对应用的单元测试的集成测试,同时引入mock以实现对Web模块的单元测试


💫思维转变(传统开发—>IOC容器)


  • 传统开发

程序控制对象:如果有多种实现类,需要改变实现类,繁杂,无法适应变更

public class UserServiceImpl implements UserService{
    private UserDao userDao = new UserDaoImpl();
    public void getUser(){
        userDao.getUser();
    }
}
  • IOC容器

set注入,使程序更加灵活,降低耦合性,这就是IOC原型

public class UserServiceImpl implements UserService{
    private UserDao userDao;  
    //通过构造器函数参数,让容器把创建好的依赖对象注入setUserDao,当然也可以使用setter方法进行注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void getUser() {
        userDao.getUser();
    }
}

☢Spring IOC/DI


Spring IOC:控制反转


💨第一个Spring程序


案例:Hello Spring


  • 编写Hello实体类
package com.wei.pojo;
public class Hello {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void show() {
        System.out.println("Hello" + "," + name);
    }
}
  • 编写Spring文件,命名为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="hello" class="com.wei.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>
</beans>
  • 编写测试类
import com.wei.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
    public static void main(String[] args) {
        //解析beans.xml文件,生成管理相应的Bean对象
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //getBean:参数即为Spring配置文件中的bean的id
        Hello hello = (Hello) context.getBean("hello");     //强制类型转换
        hello.show();
    }
}

总结:

  • bean就是Java对象,由Spring创建和管理
  <bean id="hello" class="com.wei.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>
  • 解析beans.xml文件,生成管理相应的Bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
  • getBean:参数即为Spring配置文件中的bean的id
 Hello hello = (Hello) context.getBean("hello");     //强制类型转换


💨Spring配置说明


  • id:bean的唯一标识符,也就是相当于对象名
  • class:bean对象所对应的全限定名:包名.类型
  • name:别名
  <bean id="hello" class="com.wei.pojo.Hello">
        <property name="name" value="Spring"/>
    </bean>

💨import

  • import,一般用于团队开发中,可以将多个配置文件导入合并为一个
  • 将所有xml文件导入到applicationContext.xml中,方法如下
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>

💨IOC创建对象方式


无参构造(默认)

  • 默认使用无参构造创建对象
    public User(){
        System.out.println("User的无参构造");
    }
    <bean id="user" class="com.wei.pojo.User">
    <property name="name" value="秦疆"/>-->
    </bean>
<!--
输出:
User的无参构造
name=秦疆
-->

带参构造

  • 第一种方法:下标赋值
    public User(String name){
        this.name=name;
    }
<!--    第一种,下标赋值-->
    <bean id="user" class="com.wei.pojo.User">
        <constructor-arg index="0" value="wei_shuo"/>
    </bean>
<!--
输出:
name=wei_shuo
-->
  • 第二种方法:类型创建
    public User(String name){
        this.name=name;
    }
    <bean id="user" class="com.wei.pojo.User">
        <constructor-arg type="java.lang.String" value="秦疆"/>
    </bean>
  • 第三种方法:参数名称
    public User(String name){
        this.name=name;
    }
    <bean id="user" class="com.wei.pojo.User">
        <constructor-arg name="name" value="秦疆"/>
    </bean>

💨DI依赖注入


依赖:bean对象的创建依赖于容器


注入:bean对象中的所有属性,容器注入


  • 构造器注入
    即无参构造/带参构造注入
  • Set注入
//复杂类型
public class Address {
    private String address;
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
//真实测试对象
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> game;
    private String wife;
    private Properties info;
    //以及set/get方法  toString实现方法 此处省略
}
   <bean id="student" class="com.wei.pojo.Student">
        <!--第一种,普通值注入,使用Value-->
        <property name="name" value="秦疆"/>
    </bean>

💫完整注入信息

  • Studnet类
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> game;
    private String wife;
    private Properties info;
    //以及set/get方法  toString实现方法 此处省略
}
  • Address类
    private String address;
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
  • beans.xml配置
  <bean id="address" class="com.wei.pojo.Address">
        <property name="address" value="武汉"/>
    </bean>
    <bean id="student" class="com.wei.pojo.Student">
        <!--第一种,普通值注入,使用Value-->
        <property name="name" value="秦疆"/>
        <!--第二种,Bean注入,使用ref-->
        <property name="address" ref="address"/>
        <!--数组注入-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒传</value>
                <value>三国演义</value>
            </array>
        </property>
        <!--List注入-->
        <property name="hobbys">
            <list>
                <value>听音乐</value>
                <value>看电影</value>
                <value>听书</value>
            </list>
        </property>
        <!--Map注入-->
        <property name="card">
            <map>
                <entry key="学生编号" value="123"/>
                <entry key="书籍编号" value="456"/>
            </map>
        </property>
        <!--Set注入-->
        <property name="game">
            <set>
                <value>英雄联盟</value>
                <value>Apex</value>
            </set>
        </property>
        <!--Null注入-->
        <property name="wife">
            <null/>
        </property>
        <!--Properties注入-->
        <property name="info">
            <props>
                <prop key="学号">2000</prop>
                <prop key="性别">男</prop>
                <prop key="姓名">小明</prop>
            </props>
        </property>
    </bean>
  • 测试类
public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }
}
/*
输出结果:
Student{
  name='秦疆', 
  address=Address{address='武汉'}, 
  books=[红楼梦, 西游记, 水浒传, 三国演义], 
  hobbys=[听音乐, 看电影, 听书], 
  card={
    学生编号=123, 
    书籍编号=456
  }, 
  game=[英雄联盟, Apex], wife='null', 
  info={
    学号=2000, 
    性别=男, 
    姓名=小明
    }
}
*/

💨Bean作用域


  • singleton 单实例(单例)(默认)   ----全局有且仅有一个实例
<bean id="user2" class="com.wei.pojo.User" c:name="wei_shuo" c:age="18" scope="singleton"/>
  • prototype 多实例(多例)   ---- 每次获取Bean的时候会有一个新的实例
 <bean id="user2" class="com.wei.pojo.User" c:name="wei_shuo" c:age="18" scope="prototype"/>

以下在web开发中使用

  • request
  • session
  • application
  • websocket


💨Bean自动装配(Autowire)


自动装配是Spring满足bean依赖的方式,Spring会在上下文中自动寻找,自动给bean装配属性

  • xml中显示装配
  • Java中显示配置
  • 隐式自动装配bean


案例实现:

  • 一个人(people)有两个宠物(dog/cat)
  • 狗实现方法wang
  • 猫实现方法mioa


  • Dog类
public class Dog {
    public void shout(){
        System.out.println("wang");
    }
}
  • Cat类
public class Cat {
    public void shout(){
        System.out.println("miao");
    }
}
  • people类
public class People {
    private Cat cat;
    private Dog dog;
    private String name;
    /*
    get/set方法 
    toString方法
    需要写,笔者为了不影响文章美观此处省略……
    */ 
}

beans.xml

  • byName:会自动在容器上下文中查找,和自己对象set方法后面的值(dog/cat)对应的beanid,如果beanid满足则自动装配
  • byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean,如果类型全局唯一满足则自动装配
    <!--beanid-->
    <bean id="cat" class="com.wei.pojo.Cat"/>
    <bean id="dog" class="com.wei.pojo.Dog"/>
    <!--
    autowire的属性值
    byName:会自动在容器上下文中查找,和自己对象set方法后面的值(dog/cat)对应的beanid,如果beanid满足则自动装配
    byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean,如果类型全局唯一满足则自动装配
    -->
    <bean id="people" class="com.wei.pojo.People" autowire="byName">  <!--autowire="byName" 根据名字自动装配-->
<!--<bean id="people" class="com.wei.pojo.People" autowire="byType">    autowire="byType 根据对象属性类型自动装配-->
        <property name="name" value="wei_shuo"/>
        <!--如下-->
  <!--<property name="dog" ref="dog"/>-->
  <!--<property name="cat" ref="cat"/>-->
    </bean>

💨Spring框架xml配置中属性 ref 与 value的区别


  • 属性 ref :对象引用类型,代表引用这个对象


  • 属性 value:字符串引用类型,代表引入的这个对象名字的字符串
目录
相关文章
|
19天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
10天前
|
缓存 Java Spring
实战指南:四种调整 Spring Bean 初始化顺序的方案
本文探讨了如何调整 Spring Boot 中 Bean 的初始化顺序,以满足业务需求。文章通过四种方案进行了详细分析: 1. **方案一 (@Order)**:通过 `@Order` 注解设置 Bean 的初始化顺序,但发现 `@PostConstruct` 会影响顺序。 2. **方案二 (SmartInitializingSingleton)**:在所有单例 Bean 初始化后执行额外的初始化工作,但无法精确控制特定 Bean 的顺序。 3. **方案三 (@DependsOn)**:通过 `@DependsOn` 注解指定 Bean 之间的依赖关系,成功实现顺序控制,但耦合性较高。
实战指南:四种调整 Spring Bean 初始化顺序的方案
|
15天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
34 2
|
14天前
|
消息中间件 NoSQL Java
springboot整合常用中间件框架案例
该项目是Spring Boot集成整合案例,涵盖多种中间件的使用示例,每个案例项目使用最小依赖,便于直接应用到自己的项目中。包括MyBatis、Redis、MongoDB、MQ、ES等的整合示例。
65 1
|
23天前
|
Java 数据库连接 开发者
Spring 框架:Java 开发者的春天
【10月更文挑战第27天】Spring 框架由 Rod Johnson 在 2002 年创建,旨在解决 Java 企业级开发中的复杂性问题。它通过控制反转(IOC)和面向切面的编程(AOP)等核心机制,提供了轻量级的容器和丰富的功能,支持 Web 开发、数据访问等领域,显著提高了开发效率和应用的可维护性。Spring 拥有强大的社区支持和丰富的生态系统,是 Java 开发不可或缺的工具。
|
Java Spring
Spring原理学习系列之五:IOC原理之Bean加载
其实很多同学都想通过阅读框架的源码以汲取框架设计思想以及编程营养,Spring框架其实就是个很好的框架源码学习对象。我们都知道Bean是Spring框架的最小操作单元,Spring框架通过对于Bean的统一管理实现其IOC以及AOP等核心的框架功能,那么Spring框架是如何把Bean加载到环境中来进行管理的呢?本文将围绕这个话题进行详细的阐述,并配合Spring框架的源码解析。
Spring原理学习系列之五:IOC原理之Bean加载
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
1月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
162 2
|
8天前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
19 2
 SpringBoot入门(7)- 配置热部署devtools工具
|
4天前
|
存储 运维 安全
Spring运维之boot项目多环境(yaml 多文件 proerties)及分组管理与开发控制
通过以上措施,可以保证Spring Boot项目的配置管理在专业水准上,并且易于维护和管理,符合搜索引擎收录标准。
14 2