(一)Spring工厂的底层实现原理(简易版)&理解Spring三大核心思想之一:IOC思想及使用

简介: Spring工厂的底层实现原理(简易版)&理解Spring三大核心思想之一:IOC思想及使用🍅 作者:程序员小王🍅 程序员小王的博客:https://www.wolai.com/wnaghengjie/ahNwvAUPG2Hb1Sy7Z8waaF🍅 扫描主页左侧二维码,加我微信 一起学习、一起进步🍅 欢迎点赞 👍 收藏 ⭐留言 📝🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕🍅java自学的学习路线:https://blog.csdn.net/weixin_44385486/article/details/121241079

0.png

一、Spring引言

1、EJB(Enterprise Java Beans)技术

(1)EJB简介

EJB是Enterprise Java Beans技术的简称, 又被称为企业Java Beans。


EJB可以说像是一个Web Service,但也不完全是,比如EJB将编写好的业务组件放置在EJB容器上,然后提供接口给客户端访问;但是功能不仅限如此,EJB标准中提供了很多规范等,而这些规范只有在EJB容器才能正常运行。还可以说是RPC(Remote Procedure Call远程过程调用)。


EJB提供了一种组件模式,该模式可以让开发人员仅关注系统业务方面的开发,而忽略中间件需求,比如组件、事务管理、持久化操作、安全性、资源池、线程、分发、远程处理等。开发人员可以非常容易地在任何时候将中间件需求的服务添加到系统中。


(2)EJB存在的问题

运行环境苛刻,造价高昂,对服务器要求高( 需要运行在EJB容器中,服务器有:Weblogic,WebSphere)

1.png


代码移植性差

2.png


总结:EJB是重量级的框架


2、什么是Spring

Spring(春天),诞生2002年,是一个开源的,轻量级的项目管理框架,JavaEE解决方案,整合众多优秀的设计模式


spring核心技术 ioc , aop 。能实现模块之间,类之间的解耦合。**


开源的,轻量级的项目管理框架

# 1. 对运行环境没有额外的要求
  开源服务器 tomcat resion jetty
  收费服务器 webLogic WebSphere
# 2. 代码移植性高
     不需要实现额外接口
# 3.轻量级 
    学习使用简单,内存资源占用较少,方便维护扩展
# 4.项目管理框架
   Struts替换Servlet充当控制器  (负责某一层次)
   Mybatis替换JDBC 完成数据库访问 (负责某一层次)
   Spring不是替换某一层次的技术替换,而是统筹有全局,将当前的技术整合进行整合管理,柔和在一起


致力于javaEE(企业级)轻量级解决方案

# 轻量级解决方案
  提供一个以简单的,统一的,高效的方式构造整个应用,并且可以将单层框架
   以最佳的组合柔和在一起建立一个连贯的体系,Struts2+Spring(中间件 中介)+Mybatis


3.png

3.png


整合设计模式

1. 工厂
2. 代理
3. 模板
4. 策略
5. 单例


Spring总结思路图

4.png


3、Spring如何对项目进行管理?

核心作用:用Spring来管理组件,负责组件的创建,管理,销毁


Spring框架用来管理(创建,使用,销毁)组件 ,由于Spring框架可以帮我们生成项目中组件对象,因此Spring是一个工厂/容器


5.png


注意:Spring一般不管理实体类对象(entity)


传统的使用JVM进行垃圾回收销毁,Spring自动进行销毁


6.png


二、工厂设计模式手写一个Spring

设计模式

1. 广义概念
面向对象设计中,解决特定问题的经典代码
2. 狭义概念
GOF4人帮定义的23种设计模式:工厂、适配器、装饰器、门面、代理、模板...


1、什么是工厂设计模式

1. 概念:通过工厂类,创建对象
        User user = new User();
        UserDAO userDAO = new UserDAOImpl();
2. 好处:解耦合
   耦合:指定是代码间的强关联关系,一方的改变会影响到另一方
   问题:不利于代码维护
   简单:把接口的实现类,硬编码在程序中
        UserService userService = new UserServiceImpl();


2、简单的工厂设计

原始的方法:硬编码,耦合

7.png


对象的创建方式:

     对象的创建方式:
     1. 直接调用构造方法 创建对象  UserService userService = new UserServiceImpl();
     2. 通过反射的形式 创建对象 解耦合
     Class clazz = Class.forName("com.tjcu.factory.service.UserService");
     UserService userService = (UserService)clazz.newInstance();

new创建对象

/**
 * @author 王恒杰
 * @version 1.0
 * @date 2021/11/9 13:49
 * @email 1078993387@qq.com
 * @Address 天津
 * @Description: 直接调用构造方法 创建对象 
 */
public class BeanFactory {
    public static UserService getUserService(){
        return new UserServiceImpl();
    }



通过反射创建

 public static UserService getUserService(){
        UserService userService =null;
        try {
            Class clazz = Class.forName("com.tjcu.factory.service.impl.UserServiceImpl");
           userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return userService;
    }


优化反射的方式

1.创建application.properties


2.application.properties文件加载进工厂里面

8.png



/**
 * @author 王恒杰
 * @version 1.0
 * @date 2021/11/9 13:49
 * @email 1078993387@qq.com
 * @Address 天津
 * @Description:通过反射的形式 创建对象 解耦合
 */
public class BeanFactory {
    private static Properties properties = new Properties();
    static {
        //第一步 获得IO输入流
        InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
        //第二步 文件内容 封装Properties集合中key=UserService ,value=com.tjcu.factory.service.impl.UserServiceImpl
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 对象的创建方式:
     * 1. 直接调用构造方法 创建对象  UserService userService = new UserServiceImpl();
     * 2. 通过反射的形式 创建对象 解耦合
     * Class clazz = Class.forName("com.tjcu.factory.service.UserService");
     * UserService userService = (UserService)clazz.newInstance();
     */
    public static UserService getUserService() {
        UserService userService = null;
        try {
            Class clazz = Class.forName(properties.getProperty("userService"));
            userService = (UserService) clazz.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return userService;
    }
}


测试

9.png


3、通用工厂的设计

问题:简单工厂会存在大量的代码冗余

10.png


通用工厂代码

/**
 * @author 王恒杰
 * @version 1.0
 * @date 2021/11/9 13:49
 * @email 1078993387@qq.com
 * @Address 天津
 * @Description:通过反射的形式 创建对象 解耦合
 */
public class BeanFactory {
    private static Properties properties = new Properties();
    static {
        //第一步 获得IO输入流
        InputStream inputStream = BeanFactory.class.getResourceAsStream("/application.properties");
        //第二步 文件内容 封装Properties集合中key=UserService ,value=com.tjcu.factory.service.impl.UserServiceImpl
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 对象的创建方式:
     * 1. 直接调用构造方法 创建对象  UserService userService = new UserServiceImpl();
     * 2. 通过反射的形式 创建对象 解耦合
     * Class clazz = Class.forName("com.tjcu.factory.service.UserService");
     * UserService userService = (UserService)clazz.newInstance();
     */
   public static Object getBean(String key){
       Object o=null;
       try {
           Class  clazz= Class.forName(properties.getProperty(key));
           o= clazz.newInstance();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (InstantiationException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       }
  return o;
   }
}

测试

 

    /**
     * 用来测试工厂解耦合的操作
     */
    @Test
    public void loginTest(){
        //UserServiceImpl userService = new UserServiceImpl();
        UserService userService = (UserService) BeanFactory.getBean("userService");
        User user = new User();
        user.setUsername("王恒杰");
        user.setPassword("123456");
        User login = userService.login(user.getUsername(), user.getPassword());
        System.out.println(login);
    }
}

4、通用工厂的使用方式

1. 定义类型 (类)
2. 通过配置文件的配置告知工厂(applicationContext.properties)
   key = value
3. 通过工厂获得类的对象
   Object ret = BeanFactory.getBean("key")


5、工厂总结

Spring本质:工厂 ApplicationContext(应用程序上下文) (applicationContext.xml)


三、第一个Spring程序

1、软件版本

1. JDK1.8+
2. Maven3.5+
3. IDEA2018+
4. SpringFramework 5.1.4 
   官方网站 www.spring.io


2、环境搭建

Spring的jar包

#设置pom 依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.4.RELEASE</version>
</dependency>


Spring相关依赖

 

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.2.RELEASE</version>
  </dependency>

 


3、Spring配置文件创建

11.png


1. bean标签负责组件对象的管理,一个bean标签只负责一个组件的管理,
2. class:要管理的组件,java类的全限定名 包名.类名
3. id: 组件对象在工厂中的唯一标识
     建议命名规则:
    (1)存在接口: 接口首字母小写
    (2)没有接口:类名首字母小写
   <!--
    1. bean标签负责组件对象的管理,一个bean标签只负责一个组件的管理,
    2. class:要管理的组件,java类的全限定名 包名.类名
    3. id: 组件对象在工厂中的唯一标识
         建议命名规则:
        (1)存在接口: 接口首字母小写
        (2)没有接口:类名首字母小写
    -->
    <bean class="com.tjcu.dao.UserDaoImpl" id="userDao"></bean>

 

  4、测试(所有错误:从下往上看)

# 通过工厂获取组件对象
//1.启动工厂 参数:工厂Spring配置文件的位置 路径 文件路径用/
Application ctx=new ClassPathXmlApplicationContext("init/spring.xml");
//2、获取组件对象 参数:组件对象在工厂中的唯一标识
UserDao userDao=(UserDao)ctx.getBean("aa");
//3.调用方法
userDao.add("王恒杰");

5、Spring核心API之ApplicationContext

ApplicationContext

作用:Spring提供的ApplicationContext这个⼯⼚,⽤于对象的创建
好处:解耦合

ApplicationContext接口类型

接⼝:屏蔽实现的差异
⾮web环境 : ClassPathXmlApplicationContext (main junit)
web环境 :   XmlWebApplicationContext


12.png12.png

12.png


重量级资源

ApplicationContext⼯⼚的对象占⽤⼤量内存。
不会频繁的创建对象 : ⼀个应⽤只会创建⼀个⼯⼚对象。
ApplicationContext⼯⼚:⼀定是线程安全的(多线程并发访问)

四、Spring的核心思想之IOC

1、Spring细节分析

名词解释

Spring⼯⼚创建的对象,叫做bean或者组件(componet)

Spring⼯⼚的相关的⽅法

//通过这种⽅式获得对象,就不需要强制类型转换
Person person = ctx.getBean("person", Person.class);
System.out.println("person = " + person);
//当前Spring的配置⽂件中 只能有⼀个<bean class是Person类型
Person person = ctx.getBean(Person.class);
System.out.println("person = " + person);
//获取的是 Spring⼯⼚配置⽂件中所有bean标签的id值 person person1
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
 System.out.println("beanDefinitionName = " +beanDefinitionName);
}
//根据类型获得Spring配置⽂件中对应的id值
String[] beanNamesForType = ctx.getBeanNamesForType(Person.class);
for (String id : beanNamesForType) {
 System.out.println("id = " + id);
}
//⽤于判断是否存在指定id值得bean
if (ctx.containsBeanDefinition("a")) {
 System.out.println("true = " + true);
}else{
 System.out.println("false = " + false);
}
//⽤于判断是否存在指定id值得bean
if (ctx.containsBean("person")) {
 System.out.println("true = " + true);
}else{
 System.out.println("false = " + false);
} 

Spring的核心思想

#1. IOC:控制反转|翻转控制
    把对象的创建,赋值,管理工作都交给代码之外的容器实现, 
    也就是对象的创建是有其它外部资源完成。
#2. AOP 面向切面编程


2、IOC 思想:翻转控制

(1)什么是IOC控制反转

IOC: inversion of Controll 翻转控制,控制反转


控制反转:控制权力的反转


将原有手工通过new关键字创建对象的权力,反转给Spring负责,由Spring负责对象的创建


1. 控制: 创建对象,对象的属性赋值,对象之间的关系管理。
2. 反转: 把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现。 
         由容器代替开发人员管理对象。创建对象,给属性赋值。
3. 正转:由开发人员在代码中,使用new 构造方法创建对象, 开发人员主动管理对象。
       public static void main(String args[]){
       // 在代码中, 创建对象。--正转。
            Student student = new Student(); 
     }
4.容器:是一个服务器软件, 一个框架(spring)
5.问题:未来在开发过程中,是不是所有的对象,都会交给Spring⼯⼚来创建呢?
回答:理论上 是的,但是有特例 :实体对象(entity)是不会交给Spring创建,它是由持久层
框架进⾏创建。


(2)为什么要使用 ioc ?

 目的就是减少对代码的改动, 也能实现不同的功能。 实现解耦合。 

(3)java中创建对象的方式有哪些?

  1. 构造方法 , new Student()
  2. 反射
  3. 序列化
  4. 克隆
  5. ioc :容器创建对象
  6. 动态代理


4)案例

UserDao

public interface UserDao {
    public void add(String name);
}

UserDaoImpl

public class UserDaoImpl implements UserDao{
    @Override
    public void add(String name) {
        System.out.println(name+"被添加进数据库了!");
    }
}


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">
    <!--
    1. bean标签负责组件对象的管理,一个bean标签只负责一个组件的管理,
    2. class:要管理的组件,java类的全限定名 包名.类名
    3. id: 组件对象在工厂中的唯一标识
         建议命名规则:
        (1)存在接口: 接口首字母小写
        (2)没有接口:类名首字母小写
    -->
    <bean class="com.tjcu.dao.UserDaoImpl" id="userDao"></bean>
</beans>

测试类

  /**
     * IOC 思想:翻转控制 测试类
     */
    @Test
    public void add(){
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/init/Spring.xml");
        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.add("王恒杰");
    }


(5)为什么使用DI(依赖注入)

不通过new创建对象的容器除了Spring还有

servlet  
1: 创建类继承HttpServelt 
2:  在web.xml 注册servlet , 使用
<servlet-name> myservlet </servlet-name>
<servelt-class>com.bjpwernode.controller.MyServlet1</servlet-class>
3. 没有创建 Servlet对象, 没有 MyServlet myservlet = new MyServlet()
4. Servlet 是Tomcat服务器它能你创建的。 Tomcat也称为容器
   Tomcat作为容器:里面存放的有Servlet对象, Listener , Filter对象


👨‍💻注意 :因为ioc不是Spring独有(通过手工new创建对象交给Spring创建对象),所以提出新的概念:DI(依赖注入)


1. 将原来手工new  创建对象交给Spring创建对象
2. 将另外一个组件作为当前组件的成员变量,进行依赖注入

3、DI:依赖注入

  • spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象。
  • spring-context: 是ioc功能的,创建对象的。
  • 基于IOC提出的思想:DI (dependency injection 依赖注入 )
  • 依赖的概念: 在一个组件需要另外一个组件,将另外一个组件作为这个组件的成员变量(没有注入


13.png


注入:因为将另外一个组件作为这个组件的成员变量,但是这个成员变量是空的,我们将所依赖的成员变量赋值,就是注入 (提供set方法),在工厂中进行注入

14.png


为依赖的成员变量进行注入(赋值)

name:成员变量名字
赋值:依赖的组件是工厂中另外一个组件,需要使用ref进行引用
ref:引用 值:依赖组件的唯一标识
<property name="xxxDao" ref=""></property>

【案例】

UserDao

public interface UserDao {
    public void add(String name);
}


UserDaoImpl

public class UserDaoImpl implements UserDao {
    @Override
    public void add(String name) {
        System.out.println(name+"Dao层被添加进数据库了!");
    }
}


UserService

public interface UserService {
    public void add(String name);
}

UserServiceImpl【重点】

/**
 * @author 王恒杰
 * @version 1.0
 * @date 2021/11/10 14:27
 * @email 1078993387@qq.com
 * @Address 天津
 * @Description:
 */
public class UserServiceImpl implements UserService {
    /**
     * 在UserService组件需要UserDAO组件,我们可以将UserDao组件当做成员变量
     */
  private UserDao userDao;
    @Override
    public void add(String name) {
        System.out.println(name+"实现了IOC:翻转控制,原先手工new创建对象现在交给Spring创建对象了");
        userDao.add(name);
    }
    /**
     * 为userdao提供set方法用于依赖注入
     * @param userDao
     */
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}


Spring配置文件

    <!--
    1. bean标签负责组件对象的管理,一个bean标签只负责一个组件的管理,
    2. class:要管理的组件,java类的全限定名 包名.类名
    3. id: 组件对象在工厂中的唯一标识
         建议命名规则:
        (1)存在接口: 接口首字母小写
        (2)没有接口:类名首字母小写
    -->
    <bean class="com.tjcu.dao.UserDaoImpl" id="userDao"></bean>
    <!--
    UserService
    -->
    <bean id="userService" class="com.tjcu.Service.UserServiceImpl">
        <!--
          DI:dependency injection 依赖注入
          name:成员变量名字
          赋值:依赖的组件是工厂中另外一个组件,需要使用ref进行引用
          ref:引用 值:依赖组件的唯一标识
        -->
        <property name="userDao" ref="userDao"></property>
    </bean>


测试

  /**
     * DI:dependency  injection 依赖注册 测试类
     */
    @Test
    public void AddByDI(){
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/init/Spring.xml");
        UserService userService = (UserService) ctx.getBean("userService");
        userService.add("王恒杰");
    }


五、Spring中注入

1、Spring中的注入方式

1. SET方式注入【重点】
2. 构造注入
3. 自动注入

2、Set方式注入

通过成员变量 提供set方法

  1. 依赖 定义成员变量 提供set方法
  2. 注入 在Spring 的配置文件中通过标签进行赋值

(1)注入对象类型的数据 ref

    <!--
    1. bean标签负责组件对象的管理,一个bean标签只负责一个组件的管理,
    2. class:要管理的组件,java类的全限定名 包名.类名
    3. id: 组件对象在工厂中的唯一标识
         建议命名规则:
        (1)存在接口: 接口首字母小写
        (2)没有接口:类名首字母小写
    -->
    <bean class="com.tjcu.dao.UserDaoImpl" id="userDao"></bean>
    <!--
    UserService
    -->
    <bean id="userService" class="com.tjcu.Service.UserServiceImpl">
        <!--
          DI:dependency injection 依赖注入
          name:成员变量名字
          赋值:依赖的组件是工厂中另外一个组件,需要使用ref进行引用
          ref:引用 值:依赖组件的唯一标识
        -->
        <property name="userDao" ref="userDao"></property>
    </bean>

 

(2)八种基本数据类型+字符串+日期 value

private int id;
private String name;
private Date birthday
private  Double score;
提供对应的set方法

八种基本数据类型+字符串+日期 value注入

     <!--注入八种基本数据类型+字符串+日期 -->
        <property name="id" value="110" />
        <property name="name" value="王恒杰" />
        <property name="birthday" value="1999/12/03" />
        <property name="score" value="100.0" />

(3)数组类型

数组类型

private int[] ids;

数组类型注入

      <!--数组类型-->
        <property name="ids">
            <array>
                <value>123</value>
                <value>223</value>
                <value>323</value>
                <value>423</value>
            </array>
        </property>

(4)集合类型之list

a、元素是基本类型


list类型

/

 //lsit集合
    private List<String> names;

list类型注入

 

    <!--list注入-->
        <property name="names">
            <list>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
                <value>王恒杰</value>
            </list>
        </property>

b、元素是对象类型的数据

   <property name="maps">
            <map>
                <entry key="1" value-ref="empDAO" />
                <entry key="2" value-ref="empDAO" />
                <entry key="3" value-ref="empDAO" />
            </map>
        </property>


(5)集合类型之set

set类型

//Set集合
    private Set<String> sets;

set类型注入

 <!--注入  Set集合-->
        <property name="sets">
            <set>
                <value>xixi</value>
                <value>haha</value>
                <value>hehe</value>
            </set>
        </property>

(6)集合类型之Map

1️⃣a、元素是基本类型


map类型

    //map
    private Map<String,String>  js;
    //map键值遍历 
        for(Map.Entry entry:js.entrySet()){
            System.out.println(entry.getKey()+":"+entry.getValue());
        }


map类型注入

 <!--map-->
        <property name="js">
            <map>
                <entry key="一号技师" value-ref="吴泓旭"></entry>
                <entry key="二号技师" value="张希"></entry>
                <entry key="三号技师" value="mm"></entry>
            </map>
        </property>


2️⃣b、元素是对象类型的数据


map类型

15.png


map类型注入

16.png


(7)集合类型之properties

properties概念:

 properties是Map的子实现类 非范型集合 键值都是String类型


properties类型

 //properties集合
    private Properties properties;
   //properties集合遍历
        for(Map.Entry entry:properties.entrySet()){
            System.out.println(entry.getKey()+":"+entry.getValue());
        }


properties类型注入

 

<property name="properties">
            <props>
                <prop key="key1">value1</prop>
                <prop key="key2">value2</prop>
                <prop key="key3">value3</prop>
                <prop key="key4">value4</prop>
            </props>
        </property>

(8)Set的总结

17.png

18.png



3、构造注入(onstructor)

19.png


构造方法

 public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

构造注入

 <!--构造注入-->
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>

     


20.png

20.png


21.png


面试题:set注入和构造注入有什么区别

1. set注入:通过set方法进行赋值 先创建对象再赋值
2. 构造注入:通过构造方法进行赋值,创建对象的同时进行赋值,强制注入
现实开发中set注⼊更多
 1. 构造注⼊麻烦 (重载)
 2. Spring框架底层 ⼤量应⽤了 set注⼊


23.png

23.png


4、自动注入

概念:由Spring工厂自动为成员变量赋值


底层:使用set注入


语法:

  1. 依赖:将依赖的组件作为本主键的成员变量,提供公开set方法
  2. 注入 在bean标签中使用autowire属性完成自动注入


<bean id="" class="" autowire="byName|byType">
byName:spring工厂根据成员变量的名字匹配工厂中的组件
         (在工厂中找bean的id是成员变量名字的组件)
byType:spring工厂根据成员变量的类型匹配工厂中相同类型的组件,如果有赋值,没有不赋值

六、Spring工厂特性

1、Spring工厂创建对象的特性

spring创建对象默认使用单列模式


singleton:单例 默认


   在工厂中全局唯一,只创建一次


  • prototype: 多例

全局不唯一,每次使用都会创建一个新的对象


 

<bean id="" class="xxxx.userAction" scope="prototype|singleton">
    service,dao    ----->  singleton(单例)
    struts2 action -----> prototype(原型,多例,每次都创建一个新的对象)

注意:在项目开发中service,dao组件单例,struts2的Action必须为:多例


prototype:多例 地址不一样

24.png


2、Spring工厂创建对象的底层原理 反射+无参构造

Class.forName("bean标签class属性值").new Instances();

3、工厂创建对象的生命周期

何时创建 init-method方法监听,创建时自动调用方法

   随着工厂启动, 所有单例bean随之创建 非单例的bean,每次使用时创建


何时销毁 destroy-method方法监听,销毁时自动调用方法

   工厂关闭,所有bean随之销毁( 注意: spring对多例bean管理松散,不会负责多例bean的销毁)


25.png


单例模式下(饿汉式) Servlet属于懒汉式

   创建:启动工厂创建对象


   销毁:工厂关闭时组件会自动销毁


26.png

27.png



多例模式下:


创建:在使用时创建组件对象


销毁:Spring工厂不负责多例组件的销毁


4、bean工厂创建对象的好处

使用配置文件管理java类,再生产环境中更换类的实现时不需要重新部署,修改文件即可


spring默认使用单例的模式创建bean,减少内存的占用


通过依赖注入建立了类与类之间的关系(使java之间关系更为清晰,方便了维护与管理)


七、Spring⼯⼚的底层实现原理(简易版)

28.png


相关文章
|
3天前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
12 0
|
18天前
|
XML 缓存 Java
搞透 IOC、Spring IOC ,看这篇就够了!
本文详细解析了Spring框架的核心内容——IOC(控制反转)及其依赖注入(DI)的实现原理,帮助读者理解如何通过IOC实现组件解耦,提高程序的灵活性和可维护性。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
|
10天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
22 0
|
1月前
|
Java Spring 容器
Spring底层原理大致脉络
Spring底层原理大致脉络
|
30天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
65 0
|
1月前
|
XML Java 数据格式
Spring的IOC和AOP
Spring的IOC和AOP
45 0
|
1月前
|
XML 前端开发 Java
拼多多1面:聊聊Spring MVC的工作原理!
本文详细剖析了Spring MVC的工作原理,涵盖其架构、工作流程及核心组件。Spring MVC采用MVC设计模式,通过DispatcherServlet、HandlerMapping、Controller和ViewResolver等组件高效处理Web请求。文章还探讨了DispatcherServlet的初始化和请求处理流程,以及HandlerMapping和Controller的角色。通过理解这些核心概念,开发者能更好地构建可维护、可扩展的Web应用。适合面试准备和技术深挖
42 0
|
1月前
|
负载均衡 Java API
Spring Cloud原理详解
Spring Cloud原理详解
68 0
|
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