Spring框架的介绍和使用

Spring

以业务为驱动,开发业务的同时接触学习新知识
明确和记住开发某个业务的流程、顺序、套路。

Spring
Spring MVC 和 Spring Boot

  • SpringMVC:
    Controller,页面和java的交互,都是SpringMvc的功能。

    M:Model模型:实体类
    V:View视图:html页面,显示给用户看的界面
    C:Controller控制器:Controller类,视图与java进行数据交互
    SpringMVC框架简化了V和C之间的数据交互过程

  • Spring Boot
    boot:启动
    支持Spring Boot框架的项目内置了许多的配置
    使用该框架时,省去了繁琐配置的过程
    除了这些配置,还有一些约定,如static文件夹存放静态资源

什么是Spring

Spring是一个基础框架,是Spring MVC和Spring Boot等众多以Spring开头命名的框架的基础。
它的出现,是Java能够长盛不衰的原因。因为它提供了Java开发的生态环境。
几乎任何需求,Spring都有相应的解决方案。

IOC

IOC:控制反转

正常的控制称之为主动控制

主动控制:我们编写的程序主动控制对象组件的产生,再编写对象组件互相调用完成程序功能。

控制反转:程序需要的对象组件保存在外部容器中,需要时从容器中获取后调用相应的对象组件。

一. Spring 实现 IOC

1. 创建Spring项目

1. 依赖问题

    <dependencies>
        <!--    Spring依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.16</version>
        </dependency>

        <!--        Junit测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2. 创建实体类

//实体类即要保存的对象组件
//设置类是用来将组件保存到容器中


//实体类 Stu
public class Stu {
    private String name;
    private Integer age;
}

3. 创建配置类

使用 @Configuration 注解和 @Bean 注解

设置类:Config
package cn.zx.entity;

// 配置类,配置Spring容器下的内容
// 标准情况下,Spring的配置类要添加下面的注解

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

//    编写下面的 @Bean 注解
    //    这个注解下面,写个方法,该方法返回对象就会保存在容器中.
//    每个保存到Spring容器的对象都要有一个唯一的名字,该名字就是这个方法的方法名
    @Bean
    public Stu stu() {
        Stu stu = new Stu();
        stu.setName("杨过");
        stu.setAge(22);
        return stu;
    }

}

2. 获取容器对象

1. 通过xml配置文件

<!--resources文件夹创建xml文件->spring-->
application.xml
<!--spring配置文件格式-->

<?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 id="" class="类全限定名称"></bean>
    
</beans>

1)根标签是beans
2)beans后面是约束文件说明
3)beans里面是bean声明
4)什么是bean:bean就是java对象,spring容器管理的java对象,叫做bean

2. 通过注解 @Bean

之前使用的是文件配置,现在使用了注解的方式,配置类使用注解 @Configuration,然后使用AnnotationConfigApplicationContext 获取 context对象,通过context对象获取 对象组件。

// AnnotationConfigApplicationContext 和 getBean("name"),getBean(XX.class),
// getBean("name",xx.class);

package cn.zx.entity;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    public static void main(String[] args) {
//        初始化Spring容器 ACAC , 使用反射 ,通过注解,使spring容器创建该对象组件
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
//        从Spring容器获取对象
        Stu stu = context.getBean("stu", Stu.class);
        System.out.println(stu);
    }
}

单元测试Junit

使用单元测试 运行Spring

Junit测试程序

        <!--        Junit测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

测试类的包名建议和源文件的包名相同,这样会被视为是同一个包。

测试类的类名不能叫Test,测试类的方法上方添加注解:@Test,被视为测试方法,可直接运行。

import cn.zx.entity.Config;
import cn.zx.entity.Teacher;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class T {
    @Test
    public void test01() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        Teacher teacher = context.getBean("teacher", Teacher.class);
        System.out.println(teacher);
        context.close();
    }
}

发现context的实例化和关闭每次都要执行,可以利用Junit的@Before和@After这两个注解减少冗余,简化编写,代码如下:

// Before会在Test运行之前运行
// After会在Test运行之后运行

public class T {
    AnnotationConfigApplicationContext context = null;

    //    该方法会在@Test注解运行之前运行
    @Before
    public void init() {
        context = new AnnotationConfigApplicationContext(Config.class);
    }

    @Test
    public void test01() {
        Teacher teacher = context.getBean("teacher", Teacher.class);
        System.out.println(teacher);
        context.close();
    }

    // 该方法会在@Test注解运行之后运行
    @After
    public void destory() {
        context.close();
    }
}

3. 组件扫描方式@ComponentScan

除了@Bean方式保存到容器,还有组件扫描方式保存到Spring容器。

1. 创建实体类

@Component

/*
 @Component该注解意思是组件,
 一旦被标记,表示当前类要自动实例化对象,并保存在Spring容器中
 这个对象保存在Spring容器中的id名就是当前类名,首字母小写
*/
@Component
public class Hero {
    private String name;
    private String job;
}

2. 创建配置类

@ComponentScan 声明组件扫描,后面的() 填写要扫描的包名,扫描填写的包名及子包等等的所有的包中带有 @Component的类。并将其添加到 Spring容器中。

package cn.zx.dao;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//创建配置类
//    启动组件扫描的主动方式,如果向让Hero类上的@Component生效,还要配置类中声明扫描的包
@Configuration
@ComponentScan("cn.zx.dao")
public class Config {
}

测试类

package cn.zx.dao;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class T {
    AnnotationConfigApplicationContext context;

    @Before
    public void init() {
        context = new AnnotationConfigApplicationContext(Config.class);
        ;
    }

    @After
    public void destory() {
        context.close();
    }

    @Test
    public void test() {
        Hero hero = context.getBean(Hero.class);
        System.out.println(hero);

    }
}

微总结:

目前了解了两种 将 对象组件保存到容器中的方法
1. 使用@Bean方法
	- 通过创建配置类,@Configuration , 其中的方法配以@Bean注解,
	- 该方法的方法名就是对象组件名。
	- 该方法的返回值就是即将保存到容器中的对象组件。
	
	
2. 使用组件扫描方法 ComponentScan
	- 实体类 即 要被保存到容器中的对象组件需要首先进行组件声明@Component
	- 创建配置类,配置类不仅声明配置类,还要声明组件扫描@ComponentScan(包名)
	- 组件扫描包名,扫描该包及其子包所有,只要发现有组件声明的对象组件
	- 则将其保存到容器中。该对象组件的id就是该对象的Class名,不过首字母小写。

这两种方法可以混用,反正Spring容器只有一个。

获取Spring容器的方法:

 AnnotationConfigApplicationContext context;
 context = new AnnotationConfigApplicationContext(Config.class);
 
Config.class 就是配置类的反射。
通过该配置类,将对象组件添加到Spring容器中。

----- day01 pm 1小时处。

4. 保存到Spring的细节

  • 除了@Component还有以下常见注解有相同功能

    • @Controller\RestController
    • @Service
    • Reposity
    • ......

    为什么相同功能设置不同注解?

    见到注解名称就知道类的作用。

  • 关于特殊的类名

    • 组件扫描,当前类型对象的 id 是类名首字母小写,如果类名有连续两个字母大写,则该类名就是 id 名,不再需要小写。
  • 自定义组件id

    • 不希望组件id是类名,可以自定义id,在@Component("id")(并不推荐)
    例如:
    @Component("pn")
    public class Person {
        @Value("木鱼")
        private String name;
        @Value("21")
        private Integer age;
    }
    

二. Spring中对象的作用域

1. 作用域概述

作用域英文:scope

单例(singleton):从程序开始到程序结束,某个类型的对象只有一个。

原型(prototype):从程序开始到程序结束,某个类型不断出现新的对象,没有数量限制

/*
Spring默认获取的对象都是单例的,也就是获取的对象都是同一个,可以通过查看内存地址查看

查看内存地址的方法,需要先添加依赖
      <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
        
然后使用VM.current().addressOf( 对象 )
*/  
    
    
package cn.zx.so;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openjdk.jol.vm.VM;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class T {
    AnnotationConfigApplicationContext context;

    @Before
    public void init() {
        context = new AnnotationConfigApplicationContext(Config.class);
    }

    @Test
    public void test() {
        Person p1 = (Person) context.getBean("pn");
        Person p2 = (Person) context.getBean("pn");
        System.out.println(p1 == p2);
        System.out.println(VM.current().addressOf(p1));
    }

    @After
    public void destory() {
        context.close();
    }
}

2. 修改作用域为prototype

将单例作用域修改成原型作用域,将对象修改成prototype(原型)的scope

1. @Bean的保存方式

在@Bean下添加@Scope("prototype")

@Bean
@Scope("prototype")
public Stu stu() {
    Stu stu = new Stu();
    stu.setName("杨过");
    stu.setAge(22);
    return stu;
}

2. @Component的保存方式

在@Component下添加 @Scope("prototype") 注解

原型模式下,每次获得对象,Spring都会实例化一个新的对象返回,每个对象都是不同的引用。

@Component("pn")
@Scope("prototype")
public class Person {
    private String name;
    private Integer age;
}

今后使用Spring的时候,如果需要修改Scope,根据这两个特性来设置修改即可。

3. 惰性初始化(懒惰初始化)

单例模式,验证容器中的对象初始化时机。
原型模式本来就是 懒惰初始化,因此 @Scope("prototype")@Lazy没必要共存。
    
/*
Spring在初始化的时候就已经创建好了 对象实例,这叫惰性初始化。
也就是在获取Spring容器对象的时候,容器内的对象已经实例化了。只有单例模式才会惰性初始化。
原型模式中的初始化,是在获取具体对象的时候,才会实例化该对象。
    
简而言之:实例化容器对象的时候,也会实例化容器内保存的大量对象。

*/ 

@Scope("singleton")
    
    @Before
    public void init() {
    // 这里的时候容器中的对象已经实例化了。
        context = new AnnotationConfigApplicationContext(Config.class);
    }

    @Test
    public void test() {
        System.out.println("----------");
        Person p1 = (Person) context.getBean("pn");
        Person p2 = (Person) context.getBean("pn");
        System.out.println(p1 == p2);
        System.out.println(VM.current().addressOf(p1));
        System.out.println(VM.current().addressOf(p2));
    }

针对实例化会消耗较多资源,但是运行过程不一定用到的对象,我们设置为懒惰初始化。
什么时候需要用到该对象,什么时候懒惰初始化的对象才会实例化。
使用 @Lazy 来设置惰性加载。

1. @Bean对象设置懒惰加载

@Bean
@Lazy
public Stu stu() {
    Stu stu = new Stu();
    stu.setName("杨过");
    stu.setAge(22);
    return stu;
}

2. @Component对象设置懒惰加载

@Component("pn")
@Lazy
public class Person {
    private String name;
    private Integer age;
}

添加 @Lazy 注解后,表示Spring容器实例化的时候,便不再实例化所需对象。只有在需要的时候,Spring容器才会实例化所需的对象。

惰性初始化不宜大范围使用,会引起运行缓慢。

三. DI

1. 什么是DI

Dependency Injection,依赖注入。
IOC是控制反转,是一种编程思想。DI是基于控制反转思想的一种操作。

2. 什么是依赖

依赖:程序中A类的操作执行需要使用B类对象的情况,就说A类依赖B类。

实现依赖注入

实体类

首先声明一个警察,一个手枪,警察要拿着枪

public class Police {
    private String name;
    private Gun weapon;
    set/get略
}

public class Gun {
    private String type = "左轮";
    set/get略
}

Config类

Config类 设置Spring容器保存Police对象和Gun对象
    
@Configuration
public class Config {
    
    @Bean
    public Gun gun(){
        return new Gun();
    }

    @Bean
    public Police police() {
        return new Police();
    }

}

测试类:

此时的police需要拿起枪,police也就是依赖于gun,那么能不能让police自己去Spring容器中去找Gun类型的依赖。

@Test
public void test() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
//        获取Gun
        Gun gun = context.getBean("gun", Gun.class);
//        获取Police对象
        Police police = context.getBean("police", Police.class);
        police.setName("大卫");
//        Police对象拿起枪
        police.setWeapon(gun);
//        输出查看
        System.out.println(police);
        context.close();
}

修改Config,让police自动寻找依赖

@Configuration
public class Config {

    @Bean
    public Gun gun() {
        return new Gun();
    }

    /*
    所谓依赖注入,就是将两个或更多类的依赖关系,实现在Spring容器内部。
    只需要在police方法中添加Gun形参,然后再方法体中,将gun赋给police即可。
    */
    
    @Bean
    public Police police(Gun gun) {
        Police police = new Police();
        police.setWeapon(gun);
        return police;
    }

}

测试类:

@Test
public void test() {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
//        获取Gun
    Gun gun = context.getBean("gun", Gun.class);
//        获取Police对象
    Police police = context.getBean("police", Police.class);
    police.setName("大卫");
//        输出查看
    System.out.println(police);
    context.close();
}
posted @   zxinlog  阅读(214)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示