1、初识Spring

1.1 什么是Spring?

  1. Spring 是轻量级的开源的 JavaEE 框架

  2. Spring 可以解决企业应用开发的复杂性

  3. Spring 有两个核心部分:IOC 和 AOP
    IOC:控制反转,把创建对象过程交给 Spring 进行管理
    AOP:面向切面,不修改源代码进行功能增强

  4. Spring 特点
    1、方便解耦,简化开发
    2、AOP 编程支持
    3、方便程序测试
    4、方便和其他框架进行整合
    5、方便进行事务操作
    6、降低 API 开发难度

1.2 IOC概念和原理

1.控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
2.使用 IOC 目的:为了耦合度降低

两种IOC接口
Spring 的核心容器有两种:
1、BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
2、ApplicationContext(这个接口经常使用):BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用,加载配置文件时候就会把在配置文件对象进行创建。所以我们着重了解下这个接口

而创建ApplicationContext接口实例通常采用两种方法,一个是通过ClassPathXmlApplicationContext创建,一个则是通FileSystemXmlApplicationContext创建(这种方法如果在参数中写的不是绝对路径,那么调用的时候会默认绝对路径来找,这会导致程序的灵活性变差,所以这个一般不推荐使用)
重点了解下ClassPathXmlApplicationContext

//1、初始化Spring容器,加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext01.xml");
        //2、通过容器获取userDao实例
        UserDao userDao = (UserDao) applicationContext.getBean("userDao");
    

1.3 Spring快速入门程序

1、Spring入门程序所需要的jar包

2、

程序代码如下
// 创建一个接口
public interface UserDao {
    public void say();
}

// 接口实现类
public class UserDaoImpl implements UserDao {
    public void say(){
        System.out.println("say hello world!");
    }
}
创建Spring的配置文件

在这里插入图片描述

// Spring文件创建Bean
<?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">

    <!--让指定类配置给Spring,让Spring创建其对象的实例-->
    <bean id = "userDao" class="com.yuan.firstSpring.UserDaoImpl"/>
</beans>
创建测试类
package com.yuan.firstSpring;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @description:
 * @author: ManolinCoder
 * @time: 2022/2/24
 */
public class TestFirstSpring {
    @Test
    public void test01(){
        //1、初始化Spring容器,加载配置文件
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("applicationContext01.xml");
        //2、通过容器获取userDao实例
        UserDao userDao = (UserDao) applicationContext.getBean("userDao");

        //3、调用实例中的say方法
        userDao.say();
    }
}

运行结果

在这里插入图片描述

1.4、DI(依赖注入)

什么是DI(Dependency Injection依赖注入)?
DI(依赖注入)与控制反转(IOC)的含义相同,实现IOC思想需要DI做支持,就是spring这个容器中,替你管理着一系列的类,前提是你需要将这些类交给spring容器进行管理,然后在你需要的时候,不是自己去定义,而是直接向spring容器索取,当spring容器知道你的需求之后,就会去它所管理的组件中进行查找,然后直接给你所需要的组件.

DI(依赖注入)的实现方式有两种:

  • 属性setter方法注入 (p13)
  • 构造方法注入

2、Spring中的Bean

2.1 Bean的实例化

一共三种实例化方式:构造器实例化、静态工厂方式实例化、实例工厂方式实例化。

  • 构造器实例化
创建一个Bean1类,空类里面有默认的无参构造器
package com.yuan.beanInstance;

/**
 * @description:
 * @author: ManolinCoder
 * @time: 2022/2/24
 */
public class Bean1 {

}

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 = "bean1" class="com.yuan.beanInstance.Bean1"></bean>
</beans>
创建测试类测试构造器是否能够实例化
public class TestBean {
    @Test
    public void test1(){
        //定义配置文件路径
        String xmlPath = "com.yuan.beanInstance.bean01.xml";
        //ApplicationContext在加载配置文件的同时,对Bean进行实例化
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext(xmlPath);
        Bean1 bean = (Bean1) applicationContext.getBean("bean1");
        System.out.println(bean);
    }
}

结果:

com.yuan.beanInstance.Bean1@7b69c6ba

说明bean可以通过构造器实例化对象

2.2 Bean的作用域

作用域的种类如下:
在这里插入图片描述

在这里插入图片描述
只需要掌握singleton(单例)、prototype(原型)模式就行!
其余的request、session、application这些只能在web开放中使用!

2.3 Bean的生命周期

Bean的生命周期分很多步,最主要的有以下几步:
1、第一步,执行无参构造创建Bean实例
2、第二步,调用set方法,设置属性值
3、第三步,执行初始化方法
4、第四步,获取Bean对象
5、第五步,执行销毁方法

先创建一个Order类
/*
* 验证bean的生命周期
*
* */
public class Order {
    //无参构造
    public Order() {
        System.out.println("第一步,执行无参构造创建bean实例");
    }

    private String oname;

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步,调用set方法,设置属性值");
    }

    //bean的初始化方法
    public void initMethod(){
        System.out.println("第三步,执行初始化的方法");
    }

    //bean的销毁方法
    public void destoryMethod(){
        System.out.println("第五步,执行销毁的方法");
    }


}
<?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="order" class="com.atguigu.spring5.bean.Order" init-method="initMethod" destroy-method="destoryMethod">
        <!--依赖注入-->
        <property name="oname" value="袁伟"></property>
    </bean>

</beans>
用测试类测试顺序
public class TestBean2 {

    @Test
    public void testBean(){
        //加载Spring配置文件
//        ApplicationContext context =
//                new ClassPathXmlApplicationContext("bean4.xml");
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean4.xml");
        //获取配置创建的对象
        Order order = context.getBean("order", Order.class);
        System.out.println("第四步,获取bean对象");
        System.out.println(order);

        //手动让bean实例销毁
        context.close();

    }

}

结果如下图所示:
在这里插入图片描述

2.4 Bean的装配方式(基于xml和基于注解)

Bean的装配可以理解为依赖关系的注入,bean的装配方式即Bean依赖注入的方式。Spring容器支持多种形式的装配,如基于注解,基于XML、和自动装配等(其中最常用的是基于注解的装配

2.4.1 基于XML的装配

xml装配也有两种方式:(p27)
1、设值注入:需要使用元素的子元素来为每个属性注入值。
2、构造注入:需要使用元素的子元素来定义构造方法的参数,可以使用value属性来设置该参数的值

设值注入:
public class Book {
 //创建属性
 private String bname;
 private String bauthor;
 //创建属性对应的 set 方法
 public void setBname(String bname) {
 this.bname = bname;
 }
 public void setBauthor(String bauthor) {
 this.bauthor = bauthor;
 } }
<!--set 方法注入属性--> 
<bean id="book" class="com.atguigu.spring5.Book">
 <!--使用 property 完成属性注入
 name:类里面属性名称
 value:向属性注入的值
 -->
 <property name="bname" value="易筋经"></property>
 <property name="bauthor" value="达摩老祖"></property>
</bean>
构造注入:
public class Orders {
 //属性
 private String oname;
 private String address;
 //有参数构造
 public Orders(String oname,String address) {
 this.oname = oname;
 this.address = address;
   }
 }
<!--有参数构造注入属性--> 
<bean id="orders" class="com.atguigu.spring5.Orders">
 <constructor-arg name="oname" value="电脑"></constructor-arg>
 <constructor-arg name="address" value="China"></constructor-arg>
</bean>

2.4.2 基于注解(Annotation)装配(最常用)

在spring中,尽管使用xml配置文件可以实现Bean的装配工作,但如果应用中有很多bean时,会导致xml文件过于臃肿,给后续的维护和升级带来一定的困难。为此,Spring提供了对Annotation(注解)技术的全面支持。
1、什么是注解?
(1)注解是代码的特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值…)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置
2、Spring 针对 Bean 管理中创建对象提供注解
(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
上面四个注解功能是一样的,都可以用来创建 bean 实例
3、基于注解方式实现对象创建
第一步:引入依赖
在这里插入图片描述
第二步:开启组件扫描

<!--开启组件扫描
 1 如果扫描多个包,多个包使用逗号隔开
 2 扫描包上层目录
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>

第三步:创建类,在类上面添加创建对象注解

//在注解里面 value 属性值可以省略不写,
//默认值是类名称,首字母小写
//UserService -- userService
@Component(value = "userService") //就相当于<bean id="userService" class=".."/>
public class UserService {
 public void add() {
 System.out.println("service add.......");
   }
  }

4、开启组件扫描细节配置

<!--示例 1
 use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter
 context:include-filter ,设置扫描哪些内容
-->
<context:component-scan base-package="com.atguigu" use-defaultfilters="false">
 <context:include-filter type="annotation" 
 
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--示例 2
 下面配置扫描包所有内容
 context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.atguigu">
 <context:exclude-filter type="annotation" 
 
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

5、基于注解方式实现属性注入重要
(1)@Autowired:根据属性类型进行自动装配
一般@Autowired与@Qualifier配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定
第一步: 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解
第二步:在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解

//在注解里面value的属性值可以省略不写,默认的value的值为类名称的首字母小写
//@Component(value = "userService")
@Service
//@Controller
public class UserService {

   //定义dao类型属性
   //不需要添加set方法
   //添加注入属性注解
   @Autowired //根据类型进行注入,找到实现类UserDaoImpl自动创建对象
   @Qualifier(value = "userDaoImpl1")
   private UserDao userDao;

   public void add(){
       System.out.println("service add.......");
       userDao.add();
   }
}

@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{
   @Override
   public void add() {
       System.out.println("用注解创建对象成功!");

   }
}
   @Test
    public void testService2(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        System.out.println(userService);
        userService.add();
    }

在这里插入图片描述
(2)@Qualifier:根据名称进行注入
这个@Qualifier 注解的使用,和上面@Autowired 一起使用

//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired //根据类型进行注入
@Qualifier(value = "userDaoImpl1") //根据名称进行注入
private UserDao userDao; 

(3)@Resource:可以根据类型注入,可以根据名称注入


//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao; 

(4)@Value:注入普通类型属性

@Value(value = "abc")
private String name;

6、完全注解开发
(1)创建配置类,替代 xml 配置文件

@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}

(2)编写测试类

@Test
public void testService2() {
 //加载配置类
 ApplicationContext context
 = new AnnotationConfigApplicationContext(SpringConfig.class);
 UserService userService = context.getBean("userService", 
UserService.class);
 System.out.println(userService);
 userService.add();
}

2.4.3 自动装配

一、xml实现自动装配
Spring的元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。所谓自动装配,就是将一个Bean自动地注入到其他Bean的Property

下面先演示不用autowire属性的,然后对比用的时候哪不一样
public class Cat {
    public void shout(){
        System.out.println("喵~");
    }
}
public class Dog {
    public void shout(){
        System.out.println("汪~");
    }
}
public class People {
    private Dog dog;
    private Cat cat;
    private String name;

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }
}
<?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="cat" class="com.yuan.pojo.Cat"></bean>
        <bean id="dog" class="com.yuan.pojo.Dog"></bean>

        <bean id="people" class="com.yuan.pojo.People">
            <property name="name" value="码农阿伟啊"/>
            <property name="dog" ref="dog"/>
            <property name="cat" ref="cat"/>
        </bean>
</beans>
public class MyTest {
    @Test
    public void test01(){
        ApplicationContext context
                = new ClassPathXmlApplicationContext("beanPoJo.xml");
        People people = context.getBean("people",People.class);
        people.getDog().shout();
        people.getCat().shout();


    }
}

在这里插入图片描述

如果采用自动装配,配置文件会变成这样


        <bean id="cat" class="com.yuan.pojo.Cat"></bean>
        <bean id="dog" class="com.yuan.pojo.Dog"></bean>

        <bean id="people" class="com.yuan.pojo.People" autowire="byName">
            <property name="name" value="码农阿伟啊"/>
        </bean>

结果依然正确

小结:用byName时,需要保证所有Bean的id唯一,而且这个Bean需要和自动注入的属性的set方法的值一致。
用byType时,需要保证所有Bean的class唯一,而且这个Bean需要和自动注入的属性的类型一致。

spring官方文档在这个链接https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html
中文文档:https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference
二、注解实现自动装配(用的最多,很重要)
就是通过@Autowire注解
直接在属性上使用即可,也可以在set方法上使用
使用@Autowire注解我们就可以不用编写Set方法了,前提是你这个自动装配的属性在IOC (Spring)容器中存在,且符合名字byname
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value=“xxx”)去配合@Autowired的使用,指定一个唯一的bean对象注入!

<?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></context:annotation-config>
    <bean id="cat" class="com.yuan.pojo.Cat"></bean>
    <bean id="dog" class="com.yuan.pojo.Dog"></bean>
    <bean id="people" class="com.yuan.pojo.People"/>

</beans>
public class People {
    @Autowired
    private Dog dog;
    @Autowired
    private Cat cat;
    private String name;

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "dog=" + dog +
                ", cat=" + cat +
                ", name='" + name + '\'' +
                '}';
    }
}

public class MyTest {
    @Test
    public void test01(){
        ApplicationContext context
                = new ClassPathXmlApplicationContext("beanPoJo2.xml");
        People people = context.getBean("people",People.class);
        people.getDog().shout();
        people.getCat().shout();
    }
}

在这里插入图片描述

2.4.4 Spring注解开发

@Autowired:自动装配通过类型。名字如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”)
@Nullable字段标记了这个注解,说明这个字段可以为null;
@Resource :自动装配通过名字。类型。
@Component:组件,放在类上,说明这个类被Spring管理了,就是bean!

<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:component-scan base-package="com.yuan.pojo"></context:component-scan>
    <context:annotation-config></context:annotation-config>

</beans>
@Component("user")
// 相当于配置文件中 <bean id="user" class="当前注解的类"/>
public class User {
   @Value("秦疆")
   // 相当于配置文件中 <property name="name" value="秦疆"/>
   public String name;
}

衍生注解
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
@Component三个衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

@Controller:web层

@Service:service层

@Repository:dao层

写上这些注解,就相当于将这个类交给Spring管理装配了!

小结

XML与注解比较:

XML可以适用任何场景 ,结构清晰,维护方便

注解不是自己提供的类使用不了,开发简单方便

xml与注解整合开发 :推荐最佳实践

1、xml管理Bean

2、注解完成属性注入

3、使用过程中, 可以不用扫描,扫描是为了类上的注解

Logo

Authing 是一款以开发者为中心的全场景身份云产品,集成了所有主流身份认证协议,为企业和开发者提供完善安全的用户认证和访问管理服务

更多推荐