Spring+SpringMVC的知识总结

一:技术体系架构二:SpringFramework介绍三:Spring loC容器和核心概念3.1 组件和组件管理的概念3.1.1什么是组件:3.1.2:我们的期待3.1.3Spring充当组件管理角色(IOC)3.1.4 Spring优势3.2 Spring Ioc容器和容器实现3.2.1普通和复杂容器3.2.2 SpringIOC的容器介绍3.2.3 Spring IOC具体的接口和实现类3.2.4 SpringIOC容器配置方式3.3 Spring Ioc/DI 概念总结3.3.1 IOC容器3.3.2 IOC(inversion of Control)控制反转3.3.3 DI(Dependency Injection)依赖注入四:Spring Ioc的实践和应用4.1SpringIOC/DI实现步骤4.2基于XML配置方式组件管理4.2.1 实验一:组件(Bean)信息声明配置(IOC)1.目标:2.思路3.无参构造函数的声明方法4.静态工厂类5.非静态工厂模式如何创建6.静态工厂类和非静态类的区分4.2.2 实验二:组件(Bean)依赖注入配置(DI)1.目标2.思路3.基于构造函数的依赖注入(单个构造函数)4.基于构造函数的依赖注入(多个构造函数)5.基于Setter方法来依赖注入(重点中的重点)4.2.3 实验三:IOC容器的创建和使用A.IOC容器的创建B.IOC容器的使用4.2.4 实验四:高级特性: 组件(Bean)作用域和周期方法配置4.2.4.1.组件周期方法配置a.周期方法概念b.周期方法声明c.周期方法配置4.2.4.2.组件作用域配置a.Bean作用域b.作用域可选值:c.作用域的配置4.2.5 实验五:高级特性: FactoryBean特性和使用4.2.5.1.FactoryBean的认知4.2.5.2.FactoryBean运用4.2.5.3.FactoryBean实际情况4.2.6 实验六:基于XML方式整合三层架构组件4.3基于 注解 方式管理Bean4.3.1 实验一: Bean注解标记和扫描(IOC)4.3.1.1.注解是什么:4.3.1.2扫描理解4.3.1.3.准备Spring项目的组件:4.3.1.4.组件标记注解和区别:4.3.1.5.配置文件确定扫描范围A情况:基本扫描配置B情况:指定排除组件C情况:指定包含组件4.3.2 实验二: 组件(Bean)作用域和周期方法注解4.3.2.1组件周期方法的配置4.3.2.2组件作用域配置4.3.3 实验三: Bean属性赋值: 引用类型自动装配(DI)4.3.4 实验四: Bean属性赋值: 基本类型属性赋值(DI)4.3.5 实验五: 基于注解+XML方式 整合三层架构组件4.4基于 配置类 方式管理Bean4.4.1 完全注解开发理解4.4.2 实验一: 配置类和扫描注解4.4.3 实验二: @Bean定义组件4.4.4 实验三: 高级特性: @Bean注解细节4.4.5 实验四: 高级特性: @Import扩展4.4.6 实验五: 基于注解+配置类整合方式 整合三层架构组件4.5三种配置方式总结4.6整合Spring5-Test5搭建测试 环境五:SpringAOP面向切面编程5.1 场景设定和问题复现5.2 解决技术代理模式(AOP)1.代理模式2.静态代理技术3.动态代理技术(实际开发使用)5.3 面向切面编程思维5.4 Spring AOP框架介绍和关系梳理5.5 Spring AOP基于注解方式实现和细节5.5.1 Spring AOP底层技术组成5.5.2 初步实现5.5.3 获取通知细节信息'5.5.4 切点表达式语法5.5.5 重用(提取)切点表达式5.5.6 环绕通知5.5.7 切面优先级设置5.5.8 CGLib动态代理生效5.5.9 注解实现小结5.6 Spring AOP基于XML方式实现和准备工作5.7 SpringAOP对获取Bean的影响理解六:Spring声名式事务七:Spring核心掌握总结

一:技术体系架构

二:SpringFramework介绍

三:Spring loC容器和核心概念

3.1 组件和组件管理的概念

3.1.1什么是组件:

image-20240316092807876

3.1.2:我们的期待

  • 有人替我们创建 组件对象

  • 有人帮我们保存 组件对象

  • 有人帮我们自动组成

  • 有人替我们管理事务

  • 有人协助我们整合其他的框架

3.1.3Spring充当组件管理角色(IOC)

那么谁来帮我们完成这些期待呢?

是Spring框架来实现的

组件可以完全交给Spring框架来进行管理,Spring框架替代了程序员原有的new对象,和对象属性赋值的动作

Spring具体组件管理动作包含:

  • 组件的对象实例化

  • 组件属性属性赋值

  • 组件对象之间的引用

  • 组件对象的存活周期的管理

    我们只需要编写 元数据(配置文件->xml/注解配置/java类来配置) 告知spring哪些是需要它管理的

    组件:可以复用的java对象

    组件一定是对象,对象不一定是组件

3.1.4 Spring优势

  1. 降低组件之间的糅合性:Spring IOC通过依赖注入机制,将组件之间的管理依赖削弱,减少程序组件之间的耦合性

  2. 提高了代码的可重用性和可维护性:组件的实例化过程/依赖关系的管理/交给spring ioc去处理,使得组件代码更加模块化,可重用,更易于维护

  3. 方便了配置和管理:Spring IOC通过xml文件或者注解来对组件进行配置和管理,将组件的切换,替代操作更加便捷

  4. 交给Spring管理的对象(组件),可以享受享受Spring框架的其他功能(AOP事务管理)

3.2 Spring Ioc容器和容器实现

3.2.1普通和复杂容器

普通容器:普通容器只能储存

程序中的普通容器:

  • 数组

  • 集合:List:元素有序放入,元素可以重复

  • 集合:Set:元素无序放入,元素不可重复,无索引->检索效率低,crud效率高

    名称特点原理
    HashSet无序,不重复,无索引底层是基于哈希表来储存的数据 JDK8以前,hashtable是由数组和链表组成的,在JDK8以后,是由数组+链表+红黑树组成的/哈希值:是jdk根据对象的地址,按照规则算出的int类型的数值->同一个对象,多次调用hashCode()方法返回的哈希值是相同的 String address = "岳阳市"; address.hashcode();获取到25299637(通过字符串的地址算出来的int类型的值)/哈希算法: 元素的哈希值和数组的长度求余数算出应该存入的位置,比如数组长度是 16,哈希值和16取余数,就一定是0到15之间的数字->JDK7新元素占用老元素的位置,并且新元素会指向老元素.JDK8以后:新元素挂载在老元素的后面
    LinkedHashSet有序,不重复,无索引在哈希表的原理基础上,为每一个元素又额外的多了一个双链表的机制记录储存的顺序
    TreeSet默认升序,不重复,无索引根据红黑树来实现的

复杂容器:复杂容器可以储存,还可以管理其中的对象

程序中的复杂容器:

Servlet容器可以管理Servlet(init/service/destory) Filter,Listener这样组件的一生,所以是一个复杂容器

名称时机次数
创建对象默认时机:接收到第一次请求一次
初始化操作创建对象之后一次
处理请求接收到请求多次
销毁操作Web应用卸载之前一次

我们将要学习的SpringIOC容器是一个复杂容器,它不仅会负责创建组件的对象,储存组件的对象,而且负责调用组件的方法让它们工作,最终在特定情况下销毁组件

总结:Spring管理的容器:就是一个复杂组件,不仅储存组件,而且可以管理组件之间的依赖关系,并且可以创建和销毁组件

3.2.2 SpringIOC的容器介绍

image-20240316101558408

3.2.3 Spring IOC具体的接口和实现类

A.SpringIOC接口:

BeanFactory接口提供了高级配置机制:可以管理任何类型的对象

ApplicationContextBeanfactory子接口,扩展了如下功能:

  • 更容易与Spring的AOP功能集成

  • 资源消息处理

  • 特定于应用程序给予这个接口的实现,例如Web应用程序的WebApplicationContext

BeanFactory提供了配置框架和基本功能,而 ApplicationContext添加更多特定于企业的功能.ApplicationContextBeanFactory的超集

B.ApplicationContext实现类:

类型名简介
ClassPathXmlApplicationContext通过读取类路径下的XML格式的配置文件来创建IOC的容器对象
FileSystemXmlApplicationContext通过文件系统路径,来读取XML格式的配置文件创建IOC容器对象
AnnotationConfigApplicationContext通过读取Java的配置类创建IOC的容器对象
WebApplicationContext专门为Web应用准备,基于Web环境,常见IOC容器对象,并且将其存入 ServletContext

image-20240316105824559

我们主推的是 注解+配置类的方式:迎合Springboot不用Xml,并且xml这种配置方式逐渐被淘汰了

3.2.4 SpringIOC容器配置方式

A.xml配置

B.注解配置

C.java的配置类

3.3 Spring Ioc/DI 概念总结

3.3.1 IOC容器

Spring IOC容器:负责实例化,配置和组装bean(组件).容器通过读取配置元数据来获取有关重要实例化,配置和组装组件的指令

3.3.2 IOC(inversion of Control)控制反转

IOC主要是针对对象的创建和调用来说的,也就是说,当程序需要使用一个对象的时候,不再是应用程序直接创建该对象,而是让IOC容器来创建和管理对象,也就是说控制权从应用程序转移到了IOC容器中,也就是"反转了"控制权,这种方法一般上是通过依赖查找的方式实现的,也就是说IOC容器维护着构成应用程序的对象,并且负责创建这些对象

3.3.3 DI(Dependency Injection)依赖注入

DI是指在组件之间传递依赖关系的过程中,将依赖关系在容器内部处理,这样就不必在应用程序代码中硬编码对象之间的依赖关系,实现了对象之间的解耦合,在Spring中,DI是通过XML配置文件或注解的方式实现的,它提供了三种形式的依赖注入:构造函数注入,Setter方法注入,接口注入

四:Spring Ioc的实践和应用

image-20240316161128017

4.1SpringIOC/DI实现步骤

1.配置元数据(配置)

<?xml version="1.0" encoding="UTF-8"?>
//此处添加一些约束
<beans xmlns=""
       xnlns:xs1:""
       xsi:schemaLocation=""></beans>
<bean id="" class=""></bean>
//一个bean就是一个属性信息 id是组件对象的标识 class是你要实例化的类

2.实例化IOC容器

提供给ApplicationContext构造函数的路径是资源字符串地址,允许容器从外部资源(本地文件系统/Java class/)加载文件数据

我们应该选择一个合适的容器实现类,来进行Ioc的实例化工作

//实例化ioc容器,读取外部配置文件,最终在容器内进行ioc和di动作
ApplicationContext context = 
    new ClassPathXmlApplicationContext("services.xml","daos".xml);
//接口+实现类来实现多态
​

3.获取组件

ApplicationContext是一个高级工厂的接口,可以维护不同的bean以及依赖项的注册表,通过使用方法 T getBean(Stringname,Class<T>requriedType),您可以检索bean的实例

//创建ioc的容器对象,指定配置文件,ioc也开始实例组件对象
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml","daos.xml");
//获取ioc容器的组件对象
PetStoreService service = context.getBean("petStore",PetStoreService.class);
//使用组件对象
List<String> userList = service.getUsernameList();

4.2基于XML配置方式组件管理

4.2.1 实验一:组件(Bean)信息声明配置(IOC)

1.目标:

SpringIOC容器管理一个或多个Bean,这些Bean是使用配置文件创建的

我们学习,如何定义XML配置文件,声明组件类信息,交给SpringIOC的容器进行组件管理

2.思路

image-20240316165515420

实例化一个类的方案:

实例化的类型细节分布
构造函数实例化无参数构造函数/有参数构造函数实例化
工厂模式实例化静态工厂/非静态工厂

不同的实例化方式对象和组件ioc配置方式是不同的

image-20240316170446609

3.无参构造函数的声明方法
package com.atguigu.ioc_01;
​
public class HappyComponent {
    public void doWork(){
        System.out.println("HappyComponent doWork");
    }
}
​
<?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:组件的类的权限定符 >
     下面实际是将一个组件声明了两个组件信息
     因为默认会单例模式,因此会实例化两个组件对象
     相当于就是new了两个对象
     -->
    <bean id="happyComponent" class="com.atguigu.ioc_01.HappyComponent">
​
    </bean>
    <bean id="happyComponent2" class="com.atguigu.ioc_01.HappyComponent"></bean>
</beans>
4.静态工厂类
package com.atguigu.ioc_01;
​
public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService(){};
    public static ClientService createInstance(){
        return clientService;
    }
    //因为静态方法可以直接调用 不需要实例化
}
​
<?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">
​
    <!-- 2.静态工厂类如何声明工厂方法进行ioc的配置
     id=
     class="工厂类的全限定符"
     factory-method="工厂类中的静态方法名"
    -->
    <bean id="clientService" class="com.atguigu.ioc_01.ClientService" factory-method="createInstance">
​
    </bean>
</beans>
5.非静态工厂模式如何创建
package com.atguigu.ioc_01;
​
public class DefaultServiceLocator {
    private static clientServiceImpl clientService = new clientServiceImpl();
    public clientServiceImpl createServiceInstance(){
        return clientService;
    }
}
<?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">
    <!--3.非静态工厂如何声明ioc配置-->
    <!--3.1配置工厂类的组件信息-->
    <bean id="defaultServiceLocator" class="com.atguigu.ioc_01.DefaultServiceLocator"></bean>
    <!--3.2通过指定非静态工厂对象和方法名来配置生成的ioc信息-->
    <bean id="clientService2" factory-bean="defaultServiceLocator" factory-method="createServiceInstance"></bean>
</beans>
6.静态工厂类和非静态类的区分
设计模式->工厂模式特点
静态工厂1.不需要实例化工厂类 2.类的方法用static修饰
实例工厂1.需要实例化工厂类 2.类的方法不需要static修饰
public class Car {
    private String brand;

    private Car(String brand) {
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public static Car createCar(String brand) {
        return new Car(brand);
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = Car.createCar("Toyota");
        System.out.println("My car brand is: " + myCar.getBrand());
    }
}
/*上方是静态工厂 下方是实例工厂*/
public class CarFactory {
    private String brand;

    public CarFactory(String brand) {
        this.brand = brand;
    }

    public Car createCar() {
        return new Car(brand);
    }
}

public class Main {
    public static void main(String[] args) {
        CarFactory factory = new CarFactory("Toyota");
        Car myCar = factory.createCar();
        System.out.println("My car brand is: " + myCar.getBrand());
    }
}

4.2.2 实验二:组件(Bean)依赖注入配置(DI)

1.目标

通过配置文件,实现IOC容器中Bean之间的引用(依赖注入DI配置)

主要涉及的注入场景:基于构造函数的依赖注入和基于Setter的依赖注入

2.思路

image-20240316184402730

3.基于构造函数的依赖注入(单个构造函数)

a.介绍:

基于构造函数的DI是通过容器调用具有多个参数的构造函数来完成的,每一个参数就是一个依赖项,下面事例演示一个只能通过构造函数注入进行依赖注入的类

b.准备组件类

package com.atguigu.ioc_02;

public class UserDao {
}
package com.atguigu.ioc_02;

public class UserService {
    private UserDao userDao;
    public UserService(UserDao userDao){
        this.userDao = userDao;
    }
}
<?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">
<!--引用和被引用的组件 必须全部都在ioc容器中-->
    <!--SpringIOC是一个高级容器,内部会有缓存动作,线创建对象ioc-->
    <!--1.单个构造参数注入-->
    <!--步骤1.将它们都放在ioc容器中-->
    <bean id="userDao" class="com.atguigu.ioc_02.UserDao"></bean>
    <!--<constructor-arg
    构造参数传值
    value = 直接属性值 String name="二狗子" int age =18
    ref = 引用其他bean 其他bean的id值
    -->
    <bean id="userService" class="com.atguigu.ioc_02.UserService">
        <constructor-arg ref="userDao"></constructor-arg>
    </bean>
</beans>

4.基于构造函数的依赖注入(多个构造函数)

a.介绍:

基于构造函数的DI是通过容器调用具有多个参数的构造函数来完成的 每个参数表示一个依赖项

b.准备组件类

package com.atguigu.ioc_02;

public class UserService {
    private UserDao userDao;
    private int age;
    private String name;

    public UserService(int age,String name,UserDao userDao){
        this.userDao = userDao;
        this.age=age;
        this.name=name;
    }
}
package com.atguigu.ioc_02;

public class UserDao {
}
<?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">
<!--引用和被引用的组件 必须全部都在ioc容器中-->
    <!--SpringIOC是一个高级容器,内部会有缓存动作,线创建对象ioc-->
    <!--2.多个构造参数注入-->
    <bean id="userService1" class="com.atguigu.ioc_02.UserService">
        <!--方案1:value是直接赋值 ref是引用 这里是按顺序来的-->
        <constructor-arg value="18"/>
        <constructor-arg value="张三"/>
        <constructor-arg ref="userDao"/>
    </bean>
    <bean id="userService2" class="com.atguigu.ioc_02.UserService">
        <!--方案2推荐:value是直接赋值 ref是引用 构造参数的名字注明-->
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="18"/>
        <constructor-arg ref="userDao"/>
    </bean>
    <bean id="userService3" class="com.atguigu.ioc_02.UserService">
        <!--方案3:value是直接赋值 ref是引用 参数的下角标从左到右从0开始
        age=0 name=1 userDao=2-->
        <constructor-arg index="1" value="张三"/>
        <constructor-arg index="0" value="18"/>
        <constructor-arg index="2" ref="userDao"/>
    </bean>
</beans>

5.基于Setter方法来依赖注入(重点中的重点)
package com.atguigu.ioc_02;

public class SimpleMovieLister {
    private movieFinder movieFinder;
    private String moiveName;
    public void setMoiveFinder(movieFinder movieFinder){
        this.movieFinder=movieFinder;
    }
    public void setMoiveName(String moiveName){
        this.moiveName=moiveName;
    }
}
package com.atguigu.ioc_02;

public class movieFinder {
}
<?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">
<!--引用和被引用的组件 必须全部都在ioc容器中-->
    <!--SpringIOC是一个高级容器,内部会有缓存动作,线创建对象ioc-->
    <!-- 3.触发Set方法进行注入-->
    <bean id="movieFinder" class="com.atguigu.ioc_02.movieFinder"></bean>
    <bean id="simpleMovieLister" class="com.atguigu.ioc_02.SimpleMovieLister">
        <property name="moiveName" value="消失的她"/>
        <property name="moiveFinder" ref="movieFinder"></property>
    </bean>
    <!--
    name->属性名 setter方法 去set和首字母小写的值!
    setMovieFinder -> movieFinder
    values和ref是二选一的-->
</beans>

4.2.3 实验三:IOC容器的创建和使用

A.IOC容器的创建
<?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="HappyComponent" class="com.atguigu.ioc_03.HappyComponent"></bean>
</beans>
package com.atguigu.test;

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

public class SpringIoCtest {
    //讲解如何创建Ioc容器并且读取配置文件
    /*
     * 接口:
     *   BeanFactory
     *   ApplicationContext
     * 实现类:
     * ClassPathXmlApplicationContext 读取类路径下的xml配置方式 读class文件
     * FileSystemXmlApplicationContext 读取指定文件位置的xml配置方式
     * AnnotationConfigApplicationContext  读配置类
     * WebApplicationContext 读取Web项目专属的配置ioc容器
     * 可以通过构造函数实例化
     * */
    public void createIoc(){
        //ioc和di
        //方案1:
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-03.xml");

        //方案2:先创建ioc创建,再指定配置文件,再刷新
        //创建容器 和配置文件指定分开
        ClassPathXmlApplicationContext applicationContext1 = new ClassPathXmlApplicationContext();
        applicationContext1.setConfigLocations("spring-03.xml");
        applicationContext1.refresh();
    }
    public void getBeanFromIOC(){
        //讲解如何在Ioc容器中获取组件
    }
}

B.IOC容器的使用
package com.atguigu.test;

import com.atguigu.ioc_03.HappyComponent;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringIoCtest {
    //讲解如何创建Ioc容器并且读取配置文件
    /*
     * 接口:
     *   BeanFactory
     *   ApplicationContext
     * 实现类:
     * ClassPathXmlApplicationContext 读取类路径下的xml配置方式 读class文件
     * FileSystemXmlApplicationContext 读取指定文件位置的xml配置方式
     * AnnotationConfigApplicationContext  读配置类
     * WebApplicationContext 读取Web项目专属的配置ioc容器
     * 可以通过构造函数实例化
     * */
    public void createIoc(){
        //ioc和di
        //方案1:
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-03" +
                ".xml");

        //方案2:先创建ioc荣建,再指定配置文件,再刷新
        //创建容器 和配置文件指定分开
        ClassPathXmlApplicationContext applicationContext1 = new ClassPathXmlApplicationContext();
        applicationContext1.setConfigLocations("spring-03.xml");
        applicationContext1.refresh();
    }
    @Test
    public void getBeanFromIOC(){
        //讲解如何在Ioc容器中获取组件

        //1.创建ioc容器
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
        applicationContext.setConfigLocations("spring-03.xml");
        applicationContext.refresh();
        //2.读取ioc容器的组件
        //方案1.直接根据beanId获取(需要强转 不推荐)
        HappyComponent happyComponent = (HappyComponent) applicationContext.getBean("HappyComponent");
        //方案2:根据beanId,同时指定bean的类型 Class
        HappyComponent happyComponent1 = applicationContext.getBean("HappyComponent",HappyComponent.class);
        //方案3:根据Bean的类型获取
        //TODO 根据bean的类型获取,同一个类型,在ioc容器中只有一个bean
        //TODO 如果ioc容器存在多个同类型的bean,会出现NoUniqueDefinitionException
        //TODO ioc的配置一定是实现类,但是可以根据接口来获取值 getBeans
        HappyComponent happyComponent3 = applicationContext.getBean(HappyComponent.class);
        System.out.println(happyComponent3==happyComponent1);
    }
}

4.2.4 实验四:高级特性: 组件(Bean)作用域和周期方法配置

image-20240316215546375

4.2.4.1.组件周期方法配置
a.周期方法概念

我们可以在组件内定义方法,然后当IOC容器实例化和销毁对象组件的时候调用,这两个方法是我们成为生命周期方法

类似于Servlet的Init/destory方法

b.周期方法声明
package com.atguigu.ioc_04;

public class JavaBean {
    /*

    必须是public/必须是void/必须是无参数/命名随意
    初始化方法->初始化业务逻辑
    void是为了方便反射
    */
    public void init(){
        System.out.println("JavaBean.init");
    }
    public void clear(){
        System.out.println("JavaBean clear");
    }
}

@Test
    public void test_04(){
        //创建IOC容器
        ClassPathXmlApplicationContext test04 = new ClassPathXmlApplicationContext("spring-04.xml");
        //ioc 容器去调用destroy
        //ioc会立刻释放 死了

        //2.正常结束ioc容器

        test04.close();
    }
}
c.周期方法配置
<?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">
    <!--
    init-method= "初始化方法名"
    destory-method="销毁方法名"
    spring ioc容器就会在对应的时间节点回调对应的方法
    我们在其中些对应的业务就可以了

    -->
    <bean id="javaBean" class="com.atguigu.ioc_04.JavaBean"
    init-method="init" destroy-method="clear"></bean>
</beans>
4.2.4.2.组件作用域配置
a.Bean作用域

<Bean 标签只是声明Bean 只是将Bean的信息配置给Springioc容器

在ioc容器中,这些<bean标签就会转化为Spring内部的BeanDefinition对象,在Beandefinition对象中,就包含了定义的信息,比如id class等等

这意味着,BeanDefinition与类的概念一样,SpringIOC容器可以根据BeanDefinition对象去反射创建多个Bean对象实例

具体创建多少个Bean的对象实例,由Scope属性指定

b.作用域可选值:
取值含义创建对象的时机默认值
singleton在IOC容器中,这个bean对象始终为单实例IOC容器初始化时
prototype这个bean在IOC容器中有多个实例获取bean的时候
取值含义创建对象的时机默认值
requrest请求范围内有效的实例每次请求
session会话范围内有效的实例每次会话
c.作用域的配置

其实就是修改xml中bean的scope

<?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">
    <!--
    init-method= "初始化方法名"
    destory-method="销毁方法名"
    spring ioc容器就会在对应的时间节点回调对应的方法
    我们在其中些对应的业务就可以了

    -->
    <bean id="javaBean" class="com.atguigu.ioc_04.JavaBean"
    init-method="init" destroy-method="clear"></bean>
    <!--声明一个组件信息!默认就是单例模式 一个bean对应一个beanDefinition-->
    <bean id="javaBean2" class="com.atguigu.ioc_04.JavaBean2" scope="prototype"></bean>


</beans>

 @Test
    public void test_04(){
        //创建IOC容器
        ClassPathXmlApplicationContext test04 = new ClassPathXmlApplicationContext("spring-04.xml");
        //ioc 容器去调用destroy
        //ioc会立刻释放 死了

        //2.正常结束ioc容器
         JavaBean2 bean1 = test04.getBean(JavaBean2.class);
        JavaBean2 bean2 = test04.getBean(JavaBean2.class);
        System.out.println(bean1==bean2);//这里是在判断是否为单例模式,如果是单例模式 bean1和bean2是完全一样的

    }
}

4.2.5 实验五:高级特性: FactoryBean特性和使用

image-20240317174911832

4.2.5.1.FactoryBean的认知

FactoryBean用于配置复杂的Bean对象,可以将创建过程储存在FactoryBean的getObject方法中

FactoryBean<T>提供三种方法

  • T getObject();返回此工厂创建对象的实例,这个返回值会被储存到IOC容器

  • boolean isSingleton()l如果返回单例,则返回true,否则返回false.默认实现返回true

  • Class<?>getObjectType();返回getObject()方法返回的对象类型,如果事先不知道类型,则返回Null

4.2.5.2.FactoryBean运用

a.代理类的创建

b.第三方框架整合:Mybatis的内容

c.复杂对象实例化

4.2.5.3.FactoryBean实际情况
package com.atguigu.ioc_05;

public class JavaBean {
    private String getName;

    public JavaBean() {
    }

    public JavaBean(String getName) {
        this.getName = getName;
    }

    /**
     * 获取
     * @return getName
     */
    public String getGetName() {
        return getName;
    }

    /**
     * 设置
     * @param getName
     */
    public void setGetName(String getName) {
        this.getName = getName;
    }

    public String toString() {
        return "JavaBean{getName = " + getName + "}";
    }
}
package com.atguigu.ioc_05;

import org.springframework.beans.factory.FactoryBean;
/*
* 步骤1:实现FactoryBean接口<返回值类型>
*
*
*
*
* */
public class JavaBeanFactoryBean implements FactoryBean<JavaBean> {


    @Override
    public JavaBean getObject() throws Exception {
        //使用你自己的方式实例化对象
        JavaBean javaBean = new JavaBean();
        return javaBean;
    }

    @Override
    public Class<?> getObjectType() {
        return JavaBean.class;
    }
}

<?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">

    <!--
    id - > getObject方法返回的对象标识
    Class->FactoryBean的工厂类


    -->
    <bean id="javaBean" class="com.atguigu.ioc_05.JavaBeanFactoryBean"></bean>
</beans>
    @Test
    public void test_05(){
        //1创建IOC容器
        ClassPathXmlApplicationContext test05 = new ClassPathXmlApplicationContext("spring-05/.xml");
        //2.读取组件
        JavaBean Javabean = test05.getBean("Javabean",JavaBean.class);
        System.out.println("JavaBean="+Javabean);
        //TODO FactoryBean工厂也会加入到IOC容器中
        Object bean = test05.getBean("&JavaBean");
        System.out.println("bean"+bean);
    }
}

4.2.6 实验六:基于XML方式整合三层架构组件

image-20240317181531945

CREATE TABLE students(
    id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    gender VARCHAR(10) NOT NULL,
    age INT,
    class VARCHAR(50)
);


drop table students;


INSERT INTO students (id, name, gender, age, class) VALUES (1, 'Alice Smith', 'Female', 22, 'Class A');
INSERT INTO students (id, name, gender, age, class) VALUES (2, 'Bob Johnson', 'Male', 21, 'Class B');
INSERT INTO students (id, name, gender, age, class) VALUES (3, 'Cathy Brown', 'Female', 23, 'Class C');
INSERT INTO students (id, name, gender, age, class) VALUES (4, 'David Wilson', 'Male', 20, 'Class A');
INSERT INTO students (id, name, gender, age, class) VALUES (5, 'Eva Davis', 'Female', 22, 'Class B');
INSERT INTO students (id, name, gender, age, class) VALUES (6, 'Frank White', 'Male', 21, 'Class C');
INSERT INTO students (id, name, gender, age, class) VALUES (7, 'Grace Lee', 'Female', 23, 'Class A');
INSERT INTO students (id, name, gender, age, class) VALUES (8, 'Henry Clark', 'Male', 20, 'Class B');
<?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/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!--druid-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${atguigu.url}"></property>
        <property name="driverClassName" value="${atguigu.driver}"></property>
        <property name="username" value="${atguigu.username}"/>
        <property name="password" value="${atguigu.password}"></property>
    </bean>
    <!--jdbcTemplate-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>

    </bean>
    <!--dao配置di jdbcTemplate-->
    <bean id="studentDao" class="com.atguigu.dao.impl.StudentDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>"
    </bean>
    <!--service配置di dao-->
    <bean id="studentService" class="com.atguigu.service.impl.StudentServiceImpl">
    <property name="studentDao" ref="studentDao" />
    </bean>
    <!--controller配置di service-->
    <bean id="studentController" class="com.atguigu.controller.StudentController">
    <property name="studentService" ref="studentService"></property>
    </bean>


</beans>

image-20240318111017518

4.3基于 注解 方式管理Bean

4.3.1 实验一: Bean注解标记和扫描(IOC)
4.3.1.1.注解是什么:

和XML配置文件一样,注解本身不能执行,注解只是提供一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来进行具体操作

本质上:一切的操作都是由Java代码来完成的,XML和注解只是告诉框架中的Java代码,如何去运行

举例:元旦联欢会要布置教室,蓝色的地方要贴上元旦快乐,红色的地方贴上拉花,黄色的地方贴上气球.班长做了所有的标记,同学们来完成具体工作,墙上的标记就相当于我们做的注解,同学们做的工作,就是框架执行的内容

4.3.1.2扫描理解

Spring为了知道程序员在哪些地方做了哪些注解,就需要通过扫描功能来实现

image-20240318124338395

4.3.1.3.准备Spring项目的组件:
4.3.1.4.组件标记注解和区别:
注解说明
@Component该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在任何层次,比如Service层,Dao层.使用时只需要将该注解标注在相应类上即可
@Repository该注解用于将数据访问层(Dao层)的类标识为Spring中的Bean,其功能与@Component相同
@Service此注解通常作用在业务层(Service层)用于将业务层的类标识为Spring中的Bean,其功能与Component相同
@Controller此注解通常作用在控制层(如SpringMVC中的controller)用于将控制层的类标识为Spring中的Bean,其功能与@Component相同

常用的配置Spring的xml文档

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-xml-practice-02</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <!-- Spring的核心工具包-->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>

        <!--在基础IOC功能上提供扩展服务,还提供许多企业级服务的支持,有邮件服务、 任务调度、远程访问、缓存以及多种视图层框架的支持-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>


        <!-- Spring IOC的基础实现,包含访问配置文件、创建和管理bean等 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>

        <!-- Spring context的扩展支持,用于MVC方面 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>
        <!-- Spring表达式语言 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>
        <!-- Java注解包提供@Resource注解 -->
        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.8.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

    </dependencies>


</project>

image-20240318134918901

实质上:Controller/Service/Repository的本质就是Component注解基础上起了三个新的名字

组件深层解析:对于Spring使用IOC容器管理这些组件,其实没有本质区别,也就是在语法层面上不存在区别.所以说@Controller,@Service,@Repository三个注解本质是给开发人员看的,让我们能便于分辨组件的使用

//@Component == <bean id="" class="CommonComponent"></bean>
//我们不难发现 @Component组件是为了简化Xml操作的,实际上底层还是用的Xml操作

//1.标记注解 @Component
//2.配置xml来指定包
4.3.1.5.配置文件确定扫描范围
A情况:基本扫描配置
<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
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 这里使用了正确的 context 命名空间 -->
    <!--1.普通配置包扫描-->
    <!--base-package 指定ioc容器去哪些包下查找注解类
        可以是单个包或者多个包 com.atguigu,com.atguigu.xxx 包,包
        指定包:指定包中的所有类
        指定包及其子包:指定包及其子包中的所有类-->
    <context:component-scan base-package="com.atguigu"/>

    <!-- 其他的bean配置 -->

    <!-- 更多的bean配置 -->

</beans>

B情况:指定排除组件
<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
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--2.指定包排除注解-->
    <!--
         我们有三层架构:Controller Service Repository
         webioc会储存Controller 例如com.atguigu.controller
         rootioc会储存Service和Repository
         所以rootioc可以排除@Controller注解,因为这个ioc容器里面不会放和web相关的内容
         我们为了节约内存,所以需要排除包
         
          <context:exclude-filter type= expression= >
          就是用于排除的方法

    -->
    <context:component-scan base-package="com.atguigu">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

C情况:指定包含组件
<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
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    <!--3.指定包一定包含注解-->
    <!--
         basePackage->包下全部都成立
         但是include->只包含,因此我们要关闭默认的过滤器 我们2.中就是在默认过滤器的基础上,去选择不扫描Repository和Controller
         但是在3中,我们是只要,因此我们就关闭默认的过滤器,然后把Repository设定为我们要包含的组件标签

    -->
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
</beans>

4.3.2 实验二: 组件(Bean)作用域和周期方法注解
4.3.2.1组件周期方法的配置

a.周期方法的概念

我们可以在组件类中定义方法,然后当ioc容器实例化和销毁组件对象时候进行调用,这两个方法我们称为声明周期方法

b.周期方法的声明

public class BeanOne{
    //生命周期方法要求:命名随意的 但是要求必须是public void的无参列表
    @PostConstruct //初始化方法注解
    public void init(){
    //初始化逻辑
    }
    }
public class BeanTwo{
    @PreDestroy//注解指定销毁方法
    public void cleanup(){
        //释放资源逻辑
    }
}
//相较于纯xml配置,你不必在spring-ioc.xml这类文件中写<bean>来声明
4.3.2.2组件作用域配置

a.Bean作用域的概念:

<bean标签声明Bean,只是将Bean的信息传递给SpringIOC容器

在IOC容器中,这些<bean标签对应的信息,会转化成BeanDefinition对象,而在BeanDefinition对象中,包含定义的信息(id class)

这意味着,BeanDefinition就和类概念一样,SpringIOC容器可以根据BeanDefinition对象反射创建多个Bean对象实例

具体创建多少个Bean,由Bean作用域Scope决定

b.作用域可选值

取值含义创建对象的时机默认值
singleton在IOC容器中,bean的对象始终为单实例IOC容器初始化的时候
prototype这个Bean在IOC容器中有多个实例获取Bean的时候

如果在WebApplicationContext下,会有另外两个作用域(不常用)

取值含义创建对象的时机默认值
request请求范围内有效的实例每次请求
session会话范围内有效的实例每次对话

c.作用域配置

@Scope(ScopeName= ConfigurableBeanFactory.SCOPE_SINGLETON)//单例默认值
@Scope(ScopeName= ConfigurableBeanFactory.SCOPE.PROTOTYPE)//多例 二选一
public class BeanOne{
    //周期方法要求:命名随意,但是方法一定是返回值为空的public方法
    @PostConstruct
    public void init(){
        //初始化逻辑
    }
}

4.3.3 实验三: Bean属性赋值: 引用类型自动装配(DI)
@Controller
public class UserController {
    /**
     * 复习使用xml方式插入注解
     注意 property这个成立的前提是name指的那个set方法存在,并且name值为set方法去掉set和余下首字母小写的结果
     ref是引用类型 value是值类型,引用类型填的是已经声明的bean的id 
     * <bean id="UserService" class="class地址"></bean>
     * <bean id="UserController" class="class地址">
     *     <property name="userService(set方法的名字去掉set和首字母小写)" ref="UserService"></property>
     *     </bean>
     *我们用@AutoWwired实际上就是替代了上述的操作 简化了xml操作 实现了自动化的di
     *
     * */
    @Autowired//这里等价于<property userService ->对应类型的bean装配
    //所以说 autowired叫做注解的自动装配
    private UserService userService;
    public void show(){
        //调用业务层的show方法
    }
}

@Autowired注解细节:

a.标记位置:

1.成员变量:

这也是主要的使用方式 与xml进行bean ref不同, 使用@Autowired不必有set方法

@Service("smallDog")
public class SoldierService{
    @Autowired
    private SoldierDao soldierDao;
    public void getMessage(){
        soldierDao.getMessage();
    }
}

2.构造器:

@Controller(value="tianDog")
public class SoldierController{
    private SoldierService soldierService;
    @Autowired
    public SoldierController(SoldierService soldierService){
        this.soldierService = soldierService;
    }
}

3.setXxx方法

@Controller(value="tiangou")
public class SoldierController{
    private SoldierService soldierService;
    @Autowired
    public void setSoldierService(SoldierService soldierService){
        this.soldierService = soldierService;
    }
}

b.工作流程

image-20240319115225879

  • 首先根据所需要的组件类型在IOC容器中寻找

    • 能找到唯一的bean:直接执行装配

    • 如果完全找不到匹配的这个bean:装配失败

    • 和所需类型匹配的bean不止一个

      • 没有@Qualifier注解: 根据@Autowired标记位置成员变量名作为bean的id进行匹配

        • 能找到:执行装配

        • 找不到:装配失败

      • 有@Qualifier注解:根据@Qualifier注解中指定的名称作为bean的id进行匹配

        • 能找到:执行装配

        • 找不到:装配失败

package com.atguigu.ioc_03;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    @Qualifier("userServiceImpl")
    /*
    * 1.Qualifier对Autowired是依赖的
    * 在 Spring 中,@Qualifier 注解用于指定具体要注入的 Bean,
    * 解决自动装配时的歧义性。当一个接口有多个实现类时,
    * Spring 无法确定要注入哪个 Bean,这
    * 时就可以使用 @Qualifier 注解来指定具体要注入的 Bean。
    * */
    private UserService userService;

    public void show() {
        // 调用业务层的show方法
        userService.show();
    }
}

4.3.4 实验四: Bean属性赋值: 基本类型属性赋值(DI)

@Value通常用于注入外部化属性

声明外部配置

application.properties

catalog.name=MovieCatalog

xml引入外部配置

<context:property-placeholder location="application.properties"></context:property-placeholder>

@Value注解读取配置

@Component
public class CommonComponent{
    @Value(${catalog:hahaha})//这个:之后是默认值
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name=name;
    }
}

4.3.5 实验五: 基于注解+XML方式 整合三层架构组件

4.4基于 配置类 方式管理Bean

4.4.1 完全注解开发理解

image-20240319141737835

image-20240319144233058

4.4.2 实验一: 配置类和扫描注解

package com.atguigu.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * @program: spring-ioc-java-06
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 14:25
 * 1.包扫描注解配置
 * 2.引用外部的配置文件
 * 3.声明第三方依赖的bean组件
 * 步骤:
 * 1.添加@Configuration 代表我们是配置类
 * 2.实现上述功能注解
 **/
@ComponentScan(value="com.atguigu.ioc_01")
@PropertySource(value="classpath:jdbc.properties")
@Configuration//证明你是配置类
public class JavaConfiguration {

}


4.4.3 实验二: @Bean定义组件

/**
 * @program: spring-ioc-java-06
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 14:25
 * 1.包扫描注解配置
 * 2.引用外部的配置文件
 * 3.声明第三方依赖的bean组件
 * 步骤:
 * 1.添加@Configuration 代表我们是配置类
 * 2.实现上述功能注解
 **/
@ComponentScan(value="com.atguigu.ioc_01")
@PropertySource(value="classpath:jdbc.properties")
@Configuration//证明你是配置类
public class JavaConfiguration {
    @Value("$atguigu.url")
    private String url;
    @Value("$atguigu.driver")

    private String driver;
    @Value("$atguigu.username")

    private String uesename;
    @Value("$atguigu.password")

    private String password;
    @Bean//证明其是一个添加第三方变量的bean组件
    /*
    * 这里实际上与
    * <bean id class =>
    <property name = "" value=;
    *
    * </bean>
    * 效果是一致的,只是避免了Xml的繁琐配置,精简为配置类实现
    *
    * */
    public DruidDataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(uesename);
        dataSource.setPassword(password);
        return dataSource;
    }
}

4.4.4 实验三: 高级特性: @Bean注解细节

问题1:BeanName的问题->默认是方法名 指定:name/value属性来起名 覆盖方法名

问题2:周期方法如何指定->原有解决方案:PostConstruct+PreDestroy注解指定

->Bean注解指定:initMethod/destoryMethod指定

问题3:作用域:

还有用 @Scope指定,只是默认单例

@Scope(scopeName=ConfigurableBeanFanctory.SCOPE.SINGLETON)
@Bean(name="ergouzi1",initMethod = "",destroyMethod = "")

4.4.5 实验四: 高级特性: @Import扩展

@Import注释允许从另一个配置类中加载@Bean定义

@Configuration 
public class ConfigA{
    @Bean
    public A a(){
        return new A();
    }
}

@Configuration
@Import(ConfigA.class)
public class ConfigB{
    @Bean
    public B b(){
        return new B();
    }
}

现在,实例化上下文时不需要同时指定ConfigA.class与ConfigB.class 只需要显式提供ConfigB

package com.atguigu.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class JavaConfigurationB {
}
/**
 * @program: spring-ioc-java-06
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 16:20
 **/
package com.atguigu.config;

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

@Import( value = JavaConfigurationB.class)
@Configuration
public class JavaConfigurationA {
}
/**
 * @program: spring-ioc-java-06
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 16:19
 **/

image-20240319163400934

4.4.6 实验五: 基于注解+配置类整合方式 整合三层架构组件

4.5三种配置方式总结

4.5.1 XML方式配置总结

1.所有内容都写到xml格式配置文件中

2.声明bean通过<bean标签

3.<bean标签包含基本信息(id,class)和属性信息<property name value/ref>

4.引入外部的properties文件可以通过<context:property-placeholder

5.IOC具体容器实现选择ClassPathXmlApplicationContext对象

4.5.2 XML+注解方式配置总结

1.注解负责标记IOC的类和进行属性装配

2.xml文件依然重要,需要通过<context:component-scan标签来指定注解范围

3.标记IOC注解 @Component @Service @Controller @Repository

4.标记DI注解 @Autowired @Qualifier @Resource @Value

5.具体容器选择ClassPathXmlApplicationContext对象

4.5.3完全注解方式配置总结

1.完全注解方式是指去掉xml文件,使用配置类+注解来实现

2.xml文件替换成使用Configuration注解标记的类

3.标记IOC注解:@Component @Service @Controller @Repository

4.标记DI注解:@Autowired @Qualifier @Resource @Value

5.<context:component-scan 标记指定注解范围用

@ComponentScan替代

6.<context:property-placeholder 引入外部配置文件

7.<bean标签可以用@bean替代

8.IOC具体容器选择AnnotationApplicationContext对象

4.6整合Spring5-Test5搭建测试 环境

五:SpringAOP面向切面编程

5.1 场景设定和问题复现

package com.atguigu;

public interface Calculator {
    int add(int i,int j);
    int sub(int i,int j);
    int mul(int i,int j);
    int div(int i,int j);
}
/**
 * @program: Spring-aop-annotation-09
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 21:30
 **/
package com.atguigu;

public class CalculatirPureImpl implements Calculator{
    @Override
    public int add(int i,int j){
        System.out.println("i = " + i + ", j = " + j);
        int result = i+j;

        System.out.println("result = " + result);
        return result;
    }

    @Override
    public int sub(int i,int j){
        System.out.println("i = " + i + ", j = " + j);
        int result = i-j;
        System.out.println("result = " + result);
        
        return j;
    }
    @Override
    public int mul(int i,int j){
        System.out.println("i = " + i + ", j = " + j);
        int result = i*j;
        System.out.println("result = " + result);
        return result;
    }
    @Override
    public int div(int i,int j){
        System.out.println("i = " + i + ", j = " + j);
        int result = i/j;
        System.out.println("result = " + result);
        return result;
    }
}
/**
 * @program: Spring-aop-annotation-09
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 21:31
 **/

代码问题分析:

a.代码缺陷:

  • 对核心业务功能有干扰,程序员在开发核心人物功能时分散了精力

  • 附加功能代码重复,分散在各个业务功能方法中,冗余并且不方便统一维护

b.解决思路:

核心是:解耦:我们需要把附加功能从业务功能代码中抽取出来

将重复的代码统一提取,并且[动态插入]到每个业务方法中

c.技术困难:

解决问题的困难:提取重复的附加功能到一个类中可以实现

但是如何将代码插入到各个方法中,我们不会的,我们需要新的技术->AOP技术

image-20240319215816869

5.2 解决技术代理模式(AOP)

1.代理模式

二十三中设计模式中的一种,属于结构型模式.它的作用是通过提供一个代理类,让我们在调用目标方法时,不再直接对目标方法进行调用,而是通过代理类间接调用.让不属于目标方法核心逻辑的代码从目标方法中抽离出来--解耦,调用目标方法时,先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起,也有利于统一维护

image-20240319220053429

image-20240319220129033

image-20240319220340699

2.静态代理技术

image-20240319220623548

代理类(中介):

package com.atguigu.statics;

import com.atguigu.Calculator;

public class StaticProxyCalculator implements Calculator {

    private Calculator calculator;
    public StaticProxyCalculator(Calculator calculator){
        this.calculator = calculator;
    }
    @Override
    public int add(int i, int j) {
        //使用构造函数传入的信息
        System.out.println("i = " + i + ", j = " + j);
        //调用目标
        int result = calculator.add(1, 1);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        return 0;
    }

    @Override
    public int mul(int i, int j) {
        return 0;
    }

    @Override
    public int div(int i, int j) {
        return 0;
    }
}
/**
 * @program: Spring-aop-annotation-09
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 22:11
 **/

核心逻辑(房东):

package com.atguigu;

public interface Calculator {
    int add(int i,int j);
    int sub(int i,int j);
    int mul(int i,int j);
    int div(int i,int j);
}
/**
 * @program: Spring-aop-annotation-09
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 21:30
 **/
package com.atguigu;

public class CalculatirPureImpl implements Calculator{
    @Override
    public int add(int i,int j){

        int result = i+j;


        return result;
    }

    @Override
    public int sub(int i,int j){

        int result = i-j;

        
        return j;
    }
    @Override
    public int mul(int i,int j){

        int result = i*j;

        return result;
    }
    @Override
    public int div(int i,int j){

        int result = i/j;

        return result;
    }
}
/**
 * @program: Spring-aop-annotation-09
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 21:31
 **/

使用AOP:

package com.atguigu;

import com.atguigu.statics.StaticProxyCalculator;

public class UseAOP {

    public static void main(String[] args){
        //房东 目标
        Calculator target = new CalculatirPureImpl();
        //中介 代理
        Calculator proxy = new StaticProxyCalculator(target);
        //调用中介方法
        proxy.add(1,2);
    }
}
/**
 * @program: Spring-aop-annotation-09
 * @description:
 * @author: XiaoYongCai
 * @Goal:
 * @create: 2024-03-19 22:15
 **/

3.动态代理技术(实际开发使用)

image-20240319220712448

动态代理技术分类:

  • JDK动态代理:JDK原生的实现方式,需要被代理的目标类必须要实现接口,他会基于目标类的接口自动生成一个代理对象,代理对象和目标对象有相同的接口(拜把子)

  • cglib:通过继承被代理的目标类来实现代理,所以不需要目标类来实现接口(认干爹)

  • image-20240319224259744

5.3 面向切面编程思维

image-20240322192951077

5.4 Spring AOP框架介绍和关系梳理

1.AOP是一种区别于OOP编程思维,用来完善和解决OOP的非核心代码冗余和不方便统一维护问题

2.代理技术(动态代理|静态代理)是实现AOP思维编程的具体技术,但是自己用动态代理实现代码比较繁琐

3.Spring AOP框架,基于AOP思维,封装了动态代理技术,简化了动态代理技术实现的框架!Spring AOP内部帮助我们实现动态代理,我们只需要写少量的配置,指定生效范围.即可完成面向切面思维编程实现

5.5 Spring AOP基于注解方式实现和细节

5.5.1 Spring AOP底层技术组成

image-20240322195838947

动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口,因为这个技术要求代理对象和目标对象实现同样的接口(拜把子模式)

cglib:通过继承被代理的目标类,实现代理,不需要目标类的实现类

AspectU:早期的AOP实现的框架,SpringAOP借用了AspectJ中的AOP注解

无非是借用AspectU提供的注解,但是由动态代理和cglib实现,这个是历史问题,因为程序员已经习惯使用AspectJ的注解来开发了,所以SpringAOP直接用了AspectJ的注解

5.5.2 初步实现

1.加入依赖

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>6.1.4</version>
</dependency>
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.6</version>

</dependency>

2.准备接口

3.

5.5.3 获取通知细节信息'

5.5.4 切点表达式语法

5.5.5 重用(提取)切点表达式

5.5.6 环绕通知

5.5.7 切面优先级设置

5.5.8 CGLib动态代理生效

5.5.9 注解实现小结

5.6 Spring AOP基于XML方式实现和准备工作

5.7 SpringAOP对获取Bean的影响理解

六:Spring声名式事务

七:Spring核心掌握总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/543919.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

L1-027 出租

下面是新浪微博上曾经很火的一张图&#xff1a; 一时间网上一片求救声&#xff0c;急问这个怎么破。其实这段代码很简单&#xff0c;index数组就是arr数组的下标&#xff0c;index[0]2 对应 arr[2]1&#xff0c;index[1]0 对应 arr[0]8&#xff0c;index[2]3 对应 arr[3]0&…

30、链表-两两交换链表

思路&#xff1a; 放入集合中两两交换&#xff0c;然后再重新构建链表可以解决。但是不是最优方案 第二种方式如下&#xff1a; 代码如下&#xff1a; public ListNode swapPairs(ListNode head) {if (headnull||head.nextnull){return head;}ListNode dummy new ListNode(…

麒麟服务器操作系统安装DHCP服务02

原文链接&#xff1a;麒麟服务器操作系统安装DHCP服务02 Hello&#xff0c;大家好啊&#xff01;继昨天介绍了在麒麟服务器操作系统上部署DHCP服务并演示了终端自动获取IP地址的过程之后&#xff0c;今天我们将进一步探讨如何通过绑定终端的MAC地址来为其分配固定的IP地址。这种…

第四十八周:文献阅读

目录 摘要 Abstract 文献阅读&#xff1a;时间序列预测的傅里叶图卷积网络 现有问题 提出方法 方法论 傅里叶级数 图信号的傅里叶变换 论文方法&#xff1a;F-GCN&#xff08;傅立叶图卷积网络&#xff09; 数据构建 傅立叶嵌入模块 时空ChebyNet层 框架伪代码 研…

七、Yocto使用systemd设置开机自启动程序

文章目录 Yocto使用systemd设置开机自启动程序一、 systemd介绍及service设置二、yocto集成 Yocto使用systemd设置开机自启动程序 本篇文章为基于raspberrypi 4B单板的yocto实战系列的第七篇文章&#xff1a; 一、yocto 编译raspberrypi 4B并启动 二、yocto 集成ros2(基于rasp…

人工智能轨道交通行业周刊-第77期(2024.4.1-4.14)

本期关键词&#xff1a;货车巡检机器人、铁路安全技防、车辆换长、阿里千问、大模型创业 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道世界…

宝妈如何在家创造收入?五种兼职工作让你轻松赚钱!

许多宝妈为了陪伴孩子成长&#xff0c;毅然选择了全职妈妈的角色&#xff0c;然而&#xff0c;她们内心仍希望能有一份收入&#xff0c;实现经济独立。于是&#xff0c;寻找既能照顾家庭又能赚钱的工作成了她们的迫切需求。 然而&#xff0c;这样的需求也往往让宝妈们成为一些…

鸿蒙语言TypeScript学习第16天:【类】

1、TypeScript 类 TypeScript 是面向对象的 JavaScript。 类描述了所创建的对象共同的属性和方法。 TypeScript 支持面向对象的所有特性&#xff0c;比如 类、接口等。 TypeScript 类定义方式如下&#xff1a; class class_name { // 类作用域 }定义类的关键字为 class&am…

《自动机理论、语言和计算导论》阅读笔记:p139-p171

《自动机理论、语言和计算导论》学习第 7 天&#xff0c;p139-p171总结&#xff0c;总计 33 页。 一、技术总结 1.reversal p139, The reversal of a string a1a2…an is the string written backwards, that is anan-1…a1. 2.homomorphism A string homomorphism is a f…

原理图添加封装

双击器件选中》右边弹出Properties》点击添加封装Footprint 找到你想要的封装&#xff0c;确定即可。

算法设计与分析实验报告c++实现(生命游戏、带锁的门、三壶谜题、串匹配问题、交替放置的碟子)

一、实验目的 1&#xff0e;加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、 编…

Java多线程学习总结

在Java中&#xff0c;多线程编程是一种重要的编程模型&#xff0c;它允许程序同时执行多个任务&#xff0c;从而提高了程序的执行效率和响应速度。 一、基本概念 进程与线程&#xff1a;进程是系统分配资源的基本单位&#xff0c;它包含了程序执行所需的资源&#xff0c;如代码…

Django第三方功能的使用

Django第三方功能的使用 Django REST framework前言1、Django--Restframework--coreapi版文档BUG:AssertionError: coreapi must be installed for schema support.How to run Django with Uvicorn webserver?2、序列化类 Serializer的使用模型序列化类 ModelSerializer的使用…

2024年阿里云优惠券领取攻略

阿里云作为国内领先的云计算服务提供商&#xff0c;以其稳定、高效、安全的服务赢得了众多用户的青睐。为了吸引用户上云&#xff0c;阿里云经常推出各种优惠活动&#xff0c;其中就包括阿里云优惠券。本文将为大家详细解读2024年阿里云优惠券的领券攻略&#xff0c;帮助大家轻…

DDR3的使用(非AXI4总线)

参考小梅哥视频&#xff1a;https://www.bilibili.com/video/BV1va411c7Dz/?p48&spm_id_frompageDriver&vd_sourceaedd69dc9740e91cdd85c0dfaf25304b 一、DDR3的MIG配置 找到MIG的IP核 AXI4 interface不用勾选 不需要兼容以下的FPGA就不用勾选 选择DDR3 1.1 三…

ARM v8 Cortex R52内核 04 时钟和复位 Clocking and Resets

ARM v8 Cortex R52内核 04 时钟和复位 Clocking and Resets 4.1 Clock and clock enables 时钟和时钟使能 Cortex-R52处理器具有一个单一的时钟&#xff0c;驱动着所有的触发器和RAM。各种输入&#xff0c;包括复位输入&#xff0c;都有同步逻辑使它们可以与处理器时钟异步操…

C语言—实现循序表的增删查改

一.正文 嗨嗨嗨&#xff01;大家好&#xff01;今天我为大家分享的是数据结构知识——顺序表。废话不多数&#xff0c;让我们开始今天的知识分享吧。 二.正文 1.1认识数据结构 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素…

【学习】软件测试人员使用Loadrunner进行性能测试的优势

在软件测试领域&#xff0c;性能测试是一项至关重要的环节&#xff0c;它关乎到软件系统的稳定性和用户体验。而在这其中&#xff0c;Loadrunner作为一款久经考验的性能测试工具&#xff0c;凭借其独特的优势&#xff0c;成为了众多企业和开发者眼中的“得力助手”。 首先&…

踩了一堆坑,终于掌握了postgreSQL主从流的精髓

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

spring-cloud-alibaba微服务Sentinel

Sentinel 官方网站 sentinel-dashboard-1.8.7.jar包下载地址 在window通过命令行启动&#xff08;java -Dserver.port8080 -Dproject.namesentinel-dashboard -jar sentinel-dashboard-1.8.7.jar&#xff09;&#xff0c;可以通过 -Dserver.port修改控制台的端口 使用的版本最好…