当前位置: 首页 > news >正文

Spring系列一:spring的安装与使用

文章目录

    • 💞 官方资料
      • 🍊Spring5下载
      • 🍊文档介绍
    • 💞Spring5
      • 🍊内容介绍
      • 🍊重要概念
    • 💞快速入门
      • 🍊Spring操作演示
      • 🍊类加载路径
      • 🍊Debug配置
      • 🍊Spring容器结构剖析
    • 💞实现简单基于XML配置程序
      • 🍊Spring原生容器结构梳理
      • 🍊作业布置
    • 💞基于XML配置Bean
      • 🍊通过类型获取bean
      • 🍊通过指定构造器配置bean
      • 🍊通过p名称空间配置bean
      • 🍊通过ref配置bean
      • 🍊通过内部bean配置属性
      • 🍊对集合数组属性进行配置
      • 🍊使用utillist进行配置
      • 🍊属性级联赋值配置
      • 🍊通过静态工厂获取bean
      • 🍊bean配置信息重用
      • 🍊bean创建顺序
      • 🍊bean的单例和多实例
      • 🍊bean的生命周期
      • 🍊配置bean后置处理器
      • 🍊通过属性文件配置bean
      • 🍊基于XML的bean的自动装配
      • 🍊Spring El 表达式配置Bean

💞 官方资料

在这里插入图片描述
在这里插入图片描述

🍊Spring5下载

  1. 进入官网: https://spring.io/
  2. 进入Spring5(框架就是一系列jar包. 引入jar包, 就可以使用spring)
    在这里插入图片描述
  3. 进入Spring5的github(Spring本身也是GitHub的开源项目)
    在这里插入图片描述下拉找到Access to Binaries, 进入Spring Framework Artifacts

在这里插入图片描述进入到Spring的仓库(这里有Spring的各个版本的jar包)
在这里插入图片描述具体路径 snapshot->org->springframework->spring
在这里插入图片描述下载网址 https://repo.spring.io/artifactory/snapshot/org/springframework/spring/
在这里插入图片描述在这里插入图片描述资源已上传, 如下
在这里插入图片描述

🍊文档介绍

在线文档https://docs.spring.io/spring-framework/reference/
离线文档spring-framework-5.3.8\docs\reference\html\index.html
离线APIspring-framework-5.3.8\docs\javadoc-api\index.html

💞Spring5

🍊内容介绍

Spring核心学习内容 IOC, AOP, jdbcTemplate, 声明式事务

  1. IOC: 控制反转, 可以管理java对象
  2. AOP: 切面编程
  3. JDBCTemplate: 是spring提供的一套访问数据库的技术. 应用性强, 相对好理解
  4. 声明式事务: 基于ioc/aop实现事务管理
  5. IOC, AOP 是重点同时是难点, 需要时间理解

🍊重要概念

  1. Spring可以整合其它的框架(解读: Spring是管理框架的框架)

  2. Spring有两个核心的概念: IOC 和 AOP

  3. IOC [Inversion Of Control 反转控制]

  4. 传统的开发模式[JDbcUtils / 反射], 程序------>环境 //程序读取环境配置, 然后自己创建对象
    以连接到数据库为例
    程序员编写程序, 在程序中读取配置信息
    创建对象, 使用对象完成任务

  5. Spring方式
    Spring根据配置文件xml / 注解, 创建对象, 并放入到容器(ConcurrentHashMap). 并且可以完成对象之间的依赖
    当需要使用某个对象实例的时候, 就直接从容器中获取即可
    这样程序员可以更加关注如何使用对象完成相应的业务(以前是new -> 现在是注解 / 配置)

  6. DI - Dependency Injection依赖注入, 可以理解成是IOC的别称
    Spring最大的价值是 通过配置, 给程序员提供需要使用的对象web层[Servlet (Action/Controller)/ Service / Dao / JavaBean(entity)]对象
    这是核心价值所在, 也是ioc的具体体现, 实现解耦

💞快速入门

🍊Spring操作演示

需求: 通过Spring的方式[配置文件], 获取JavaBean-Monster的对象, 并给该对象的属性赋值, 输出该对象的信息

  1. 下载Spring5开发包, Spring5开发包资源博主已上传
  2. 创建Java工程, Spring5
    在这里插入图片描述
  3. 新建lib目录, 引入开发Spring5的基本包
    在这里插入图片描述
  4. 创建JavaBean, 一定要有无参构造器. Spring底层反射创建对象时, 需要使用
package com.zzw.spring.bean;
public class Monster {private String monsterId;private String name;private String skill;//无参构造器: Spring底层反射创建对象时, 需要使用public Monster() {}//有参构造器, setter, getter, toString()
}
  1. src目录下: 新建一个容器配置文件beans.xml
    在这里插入图片描述
    创建好之后, 右上角进行配置, 默认的就行
    在这里插入图片描述

xmlns表示xml namespace, 即xml命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--1.配置monster对象/javabean2.在beans中可以配置多个bean3.bean表示一个java对象4.class是用于指定类的全路径->Spring底层使用反射创建(所以要有无参构造器)5.id属性表示该java对象在spring容器中的id, 通过id可以获取到该对象6.<property name="monsterId" value="100"/> 用于给该对象的属性赋值, String没有赋值就是null--><bean class="com.zzw.spring.bean.Monster" id="monster01"><property name="monsterId" value="100"/><property name="name" value="美猴王"/><property name="skill" value="金箍棒"/></bean>
</beans>
  1. 测试
package com.zzw.spring.test;public class SpringBeanTest {@Testpublic void getMonster() {//解读//1.创建容器 ApplicationContext//2.该容器和容器配置文件关联//3.习惯用接口的形式接收ApplicationContext ioc =new ClassPathXmlApplicationContext("beans.xml");//3.通过getBean获取对应的对象//  默认返回的是Object, 但是运行类型是Monster//Object monster01 = ioc.getBean("monster01");Monster monster01 = (Monster) ioc.getBean("monster01");//4.输出System.out.println("monster01" + monster01 + ", monster01运行类型" + monster01.getClass());System.out.println("monster01" + monster01 + ", 属性name=" + monster01.getName() + ", monsterId="+ monster01.getMonsterId());//5.也可以在获取的时候, 直接指定Class类型, 可以再次获取Monster monster011 = ioc.getBean("monster01", Monster.class);System.out.println("monster011=" + monster011);System.out.println("monster011.name=" + monster011.getName());System.out.println("ok~~~");}
}

🍊类加载路径

解释类加载路径
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext(“beans.xml”);

//验证类加载路径
@Test
public void classPath() {File file = new File(this.getClass().getResource("/").getPath());//看到类的加载路径System.out.println("file=" + file);
}

在这里插入图片描述

🍊Debug配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

🍊Spring容器结构剖析

判断是否是懒加载: 是事先创建好, 还是等到用户使用的时候再创建.
lazyInit: false. 说明beans.xml中对象的创建不是懒加载.

用Debug的方式, 看一下Spring容器的处理机制
在这里插入图片描述
ioc->beanFactory->beanDefinitionMap
在这里插入图片描述
beanDefinitionMap / table
在这里插入图片描述
index=217
在这里插入图片描述
table / propertyValues
在这里插入图片描述

beanFactory->singletonObjects
在这里插入图片描述
singletonObjects / table
在这里插入图片描述

beanFactory / beanDefinitionNames
在这里插入图片描述

题目: 查看容器注入了哪些bean对象, 输出bean的id

String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {System.out.println("beanDefinitionName=" + beanDefinitionName);
}

💞实现简单基于XML配置程序

需求说明

  1. 自己写一个简单的Spring容器, 通过读取beans.xml, 获取第1个JavaBean: Monster的对象, 并给该对象的属性赋值, 放入到容器中, 并输出该对象信息
  2. 也就是说, 不使用Spring原生框架, 我们自己简单模拟实现
  3. 了解Spring容器的简单机制

思路分析
在这里插入图片描述

实现
引入dom4j-1.6.1.jar包
ZzwApplicationContext.java

package com.zzw.spring.zzwapplicationcontext;/*** @author 赵志伟* @version 1.0* 1.这个程序用于实现Spring的一个简单容器机制* 2.后面还会详细实现* 3.这里我们实现如何将beans.xml文件进行解析, 并生成对象, 放入容器中* 4.提供一个方法 getBean(id) 返回对应的对象* 5.这里就是一个开胃小点心, 理解Spring容器的机制*/
@SuppressWarnings({"all"})
public class ZzwApplicationContext {private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();//构造器//接收一个容器的配置文件 比如 beans.xml, 该文件默认在src目录下public ZzwApplicationContext(String iocBeanXmlFile) throws Exception {//1.得到类加载路径:// /D:/idea_project/zzw_spring/spring/out/production/spring/String path = this.getClass().getResource("/").getPath();//2.创建解析器SAXReader reader = new SAXReader();//3.得到document对象Document document = reader.read(new File(path + iocBeanXmlFile));//4.获取rootElementElement rootElement = document.getRootElement();//5.得到第1个bean-monster01Element bean = (Element) rootElement.elements("bean").get(0);//6.获取第一个bean-monster01的相关属性 => beanDefinitionMapString id = bean.attributeValue("id");String ClassFullPath = bean.attributeValue("class");List<Element> properties = bean.elements("property");//这里不再遍历, 直接获取Integer monsterId = Integer.parseInt(properties.get(0).attributeValue("value"));String name = properties.get(1).attributeValue("value");String skill = properties.get(2).attributeValue("value");//7.使用反射创建对象 => 回顾反射机制Class<?> aClass = Class.forName(ClassFullPath);//这里instance就是Monster对象Monster o = (Monster) aClass.newInstance();//给o对象通过反射来赋值 => 这里先简化o.setMonsterId(monsterId);o.setName(name);o.setSkill(skill);//8.将创建好的对象放入到singletonObjectssingletonObjects.put(id, o);}public Object getBean(String id) {//这里可以再处理一下return singletonObjects.get(id);}
}

测试 ZzwApplicationContextTest

package com.zzw.spring.zzwapplicationcontext;public class ZzwApplicationContextTest {public static void main(String[] args) throws Exception {ZzwApplicationContext ioc = new ZzwApplicationContext("beans.xml");Monster monster01 = (Monster) ioc.getBean("monster01");System.out.println("monster01=" + monster01);System.out.println("monster01.name=" + monster01.getName());System.out.println("ok~");}
}

🍊Spring原生容器结构梳理

在这里插入图片描述

🍊作业布置

在beans.xml中, 注入两个Monster对象, 但是不指定id, 运行会不会报错?
如果不会报错, 如果知道id, 并获取Monster对象.

  1. 不会报错, 会正常运行
  2. 系统会默认分配id. 分配id的规则是: 全类名#0, 全类名#1 这样的规则来分配id的. 例如 com.zzw.spring.bean.Monster#0, com.zzw.spring.bean.Monster#1
  3. 通过debug方式来查看
    在这里插入图片描述
public class homework01 {@Testpublic void getMonster() {//1.创建容器, 习惯用接口的形式接收ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Monster monster1 = ioc.getBean("com.zzw.spring.bean.Monster#0", Monster.class);System.out.println("monster1=" + monster1);Monster monster2 = ioc.getBean("com.zzw.spring.bean.Monster#1", Monster.class);System.out.println("monster2=" + monster2);System.out.println("ok~");}
}

创建一个Car类, 要求

  1. 创建ioc容器文件(配置文件), 并配置一个Car对象(bean).
  2. 通过java程序到ioc容器获取该bean对象, 并输出
public class Car {private Integer id;private String name;private Double price;public Car() {System.out.println("car对象 无参构造器被执行");}//有参构造器, setter, getter, toString()

beans1.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--配置carbean--><bean class="com.zzw.spring.bean.Car" id="car01"><property name="id" value="100"/><property name="name" value="奔驰"/><property name="price" value="120000.00"/></bean>
</beans>
public class homework02 {public static void main(String[] args) {//1.创建容器对象ApplicationContext ioc = new ClassPathXmlApplicationContext("beans1.xml");Car car01 = ioc.getBean("car01", Car.class);System.out.println("car01=" + car01);System.out.println("car01.name=" + car01.getName());System.out.println("ok~");}
}

💞基于XML配置Bean

Bean管理包括两方面: 创建bean对象, 给bean注入属性

🍊通过类型获取bean

案例: 通过spring的ioc容器, 获取一个bean对象, 获取方式: 按类型.

<!--配置Monster, 通过类型获取-->
<bean class="com.zzw.spring.bean.Monster"><!--解读1.当我们给某个bean对象设置属性的时候2.底层是使用对应的setter方法完成的, 比如setName()3.如果没有这个方法, 就会报错--><property name="monsterId" value="100"/><property name="name" value="孙悟空"/><property name="skill" value="火眼金睛"/>
</bean>

演示通过bean的类型获取对象

@Test
public void getBeanByType() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");//直接传入class对象/类型Monster bean = ioc.getBean(Monster.class);System.out.println("bean=" + bean);
}

细节
按照类型获取bean, 要求ioc容器中的同一个类的bean只能有一个, 否则会抛出异常 NoUniqueBeanDefinationException

这种方式的应用场景: 比如XxxAction / Servlet / Controller, 或XxxService在一个线程中只需要一个对象实例(单例)的情况

在容器配置文件(比如beans.xml)中给属性赋值. 底层是通过setter方法完成的. 所以需要提供setter方法.

🍊通过指定构造器配置bean

<!--配置Monster对象, 并且指定构造器-->
<!--
解读
1.constructor-arg标签可以指定使用构造器的参数
2.index表示构造器的第几个参数, 从0开始计算的
3.除了可以通过index, 还可以通过name / type来指定参数方式
4.解除大家的疑惑: 类的构造器, 不能有完全相同类型和顺序的构造器, 所以可以通过type来指定一个类中的两个构造器, 参数的类型和顺序不能完全相同可以类型相同, 但顺序不同
-->
<bean class="com.zzw.spring.bean.Monster" id="monster03"><constructor-arg value="100" index="0"/><constructor-arg value="齐天大圣" index="1"/><constructor-arg value="如意金箍棒" index="2"/>
</bean><bean class="com.zzw.spring.bean.Monster" id="monster04"><constructor-arg value="200" name="monsterId"/><constructor-arg value="斗战胜佛" name="name"/><constructor-arg value="无法无天" name="skill"/>
</bean><bean class="com.zzw.spring.bean.Monster" name="monster05"><constructor-arg value="300" type="java.lang.Integer"/><constructor-arg value="猪悟能" type="java.lang.String"/><constructor-arg value="追嫦娥~" type="java.lang.String"/>
</bean>

演示通过构造器来设置属性

@Test
public void setBeanByConstructor() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Monster monster03 = ioc.getBean("monster03", Monster.class);System.out.println("monster03=" + monster03);
}

在这里插入图片描述
在这里插入图片描述
通过index属性来区分是第几个参数;
通过type属性来区分是什么类型(按照顺序, 这是可以的)

🍊通过p名称空间配置bean

xmlns:p=“http://www.springframework.org/schema/p”

<!--通过p名称空间来配置bean将光标放在p这个位置, 输入alt+enter, 就会自动的添加xmlns. 有时需要多来几次, 有个识别的过程
-->
<bean class="com.zzw.spring.bean.Monster" id="monster06"p:monsterId="400"p:name="天蓬元帅"p:skill="掌管十万天军"
/>

演示通过p名称空间来设置属性

public class SpringBeanTest {@Testpublic void setBeanByP() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Monster monster06 = ioc.getBean("monster06", Monster.class);System.out.println("monster06=" + monster06);}
}

🍊通过ref配置bean

引用注入其它bean对象

在spring的ioc容器, 可以通过ref来实现bean对象的相互引用[ref全称: reference]

<!--配置MemberDaoImpl对象-->
<bean class="com.zzw.spring.dao.MemberDaoImpl" id="memberDao"/>
<!--配置MemberServiceImpl对象1.ref="memberDao"表示 MemberServiceImpl对象属性memberDao引用的对象是id="memberDao"的对象2.这里就体现出spring容器的依赖注入3.注意: 在spring容器中, 它是作为一个整体来执行的, 即如果引用到了一个bean对象, 对配置的顺序没有要求4.建议还是按顺序. 好处是在阅读的时候, 比较方便
-->
<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService"><property name="memberDao" ref="memberDao"/>
</bean>
package com.zzw.spring.service;public class MemberServiceImpl {private MemberDaoImpl memberDao;public MemberDaoImpl getMemberDao() {return memberDao;}public void setMemberDao(MemberDaoImpl memberDao) {this.memberDao = memberDao;}public void add() {System.out.println("MemberServiceImpl add方法被调用...");memberDao.add();}
}
package com.zzw.spring.dao;public class MemberDaoImpl {public MemberDaoImpl() {System.out.println("MemberDaoImpl 构造器...");}public void add() {System.out.println("MemberDaoImpl add方法被执行");}
}

通过ref来设置bean属性

public class SpringBeanTest {@Testpublic void setBeanByRef() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");MemberServiceImpl memberService = ioc.getBean("memberService", MemberServiceImpl.class);memberService.add();}
}

在这里插入图片描述

🍊通过内部bean配置属性

引用/注入内部bean对象

在spring的ioc容器, 可以直接配置内部bean对象

<!--配置MemberServiceImpl对象-使用内部bean-->
<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService2"><!--自己配置一个内部bean--><property name="memberDao"><bean class="com.zzw.spring.dao.MemberDaoImpl"/></property>
</bean>

通过内部bean, 设置属性

public class SpringBeanTest {@Testpublic void setBeanByPro() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");MemberServiceImpl memberService2 = ioc.getBean("memberService2", MemberServiceImpl.class);memberService2.add();}
}

🍊对集合数组属性进行配置

引用/注入 集合/数据类型

  1. 主要掌握List / Map / Properties 三种集合的使用
  2. Properties是Hashtable的子类, 是key-value的形式
  3. 这里的properties的k-v, 都是String类型

在spring的ioc容器中, 如何给bean对象的 集合/数组 类型的属性赋值

public class Master {private String name;//主人名字private List<Monster> monsterList;private Map<String, Monster> monsterMap;private Set<Monster> monsterSet;//数组private String[] monsterName;//Java基础//这个Properties 是HashMap的子类, 是key-value的存放形式//这里Properties key和value 都是Stringprivate Properties properties;//getter, setter方法
}

给集合/数组属性进行赋值

public class SpringBeanTest {@Testpublic void setBeanByCollection() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Master master = ioc.getBean("master", Master.class);System.out.println("master=" + master);}
}

🍊对List属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入
-->
<bean class="com.zzw.spring.bean.Master" id="master"><property name="name" value="太上老君"/><!--给list属性赋值--><property name="monsterList"><list><!--引用的方式加入的--><ref bean="monster03"/><ref bean="monster04"/><!--内部bean, 不再建议id--><bean class="com.zzw.spring.bean.Monster"p:monsterId="300"p:name="狮驼岭"p:skill="紫金葫芦"/></list></property>
</bean>

🍊对Map属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master"><property name="name" value="太上老君"/><!--给map属性赋值--><property name="monsterMap"><map><entry><key><value>monster04</value></key><!--这里使用的是外部的bean, 引入--><ref bean="monster04"/></entry><entry><key><value>monster03</value></key><!--内部bean, 不再建议id--><bean class="com.zzw.spring.bean.Monster"p:monsterId="300"p:name="狮驼岭"p:skill="紫金葫芦~"/></entry></map></property>
</bean>

🍊对Set属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master"><property name="name" value="太上老君"/><!--给set属性赋值--><property name="monsterSet"><set><!--这里使用的是外部的bean, 引入--><ref bean="monster05"/><ref bean="monster06"/><!--内部bean, 不再建议id--><bean class="com.zzw.spring.bean.Monster"p:monsterId="300"p:name="狮驼岭"p:skill="紫金葫芦~"/></set></property>
</bean>

🍊对Array属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master"><property name="name" value="太上老君"/><!--给数组属性赋值补充: array标签中使用 value 还是 bean, ref ...要根据业务来决定这里的monsterName是字符串--><property name="monsterName"><array><value>六耳猕猴</value><value>东海龙王</value><value>红孩儿</value></array></property>
</bean>

🍊对Properties属性进行配置

<!--配置Master对象
体会spring容器配置的特点 依赖注入 非常灵活
-->
<bean class="com.zzw.spring.bean.Master" id="master"><property name="name" value="太上老君"/><!--对properties属性进行赋值 结构k(String)-v(String) --><property name="properties"><props><prop key="username">root</prop><prop key="password">123456</prop><prop key="email">978964140@qq.com</prop></props></property>
</bean>

🍊使用utillist进行配置

spring的ioc容器, 可以通过util名称空间来创建list集合

public class BookStore {//书private List<String> bookList;//无参构造器, 如果没有其它的构造器, 该无参构造器可以不写//如果有其它的构造器, 则必须显示地定义一下无参构造器public BookStore() {}//getter, setter方法
}

beans.xml

<!--定义一个util:list, 并且指定了id 可以达到数据复用
说明: 在使用util:list 名称空间的时候, 需要引入相应的标签, 一般来说通过alt+enter会自动加入
, 如果没有就手动添加一下
-->
<util:list id="myBookList"><value>三体</value><value>时间简史</value><value>梦的解析</value><value>福尔摩斯探案集</value>
</util:list><!--配置BookStore对象-->
<bean class="com.zzw.spring.bean.BookStore" id="bookStore"><property name="bookList" ref="myBookList"/>
</bean>

使用util:list名称空间给属性赋值

public class SpringBeanTest {@Testpublic void setBeanByUtilList() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");BookStore bookStore = ioc.getBean("bookStore", BookStore.class);System.out.println("bookStore=" + bookStore);}
}

🍊属性级联赋值配置

spring的ioc容器, 可以直接给对象属性的属性赋值, 即级联属性赋值

部门

public class Dept {private String name;public Dept() {}//getter, setter方法

员工

public class Employee {private String name;private Dept dept;public Employee() {}//getter, setter方法
}

beans.xml

<!--配置Dept对象-->
<bean class="com.zzw.spring.bean.Dept" id="dept"/>
<!--配置Employee对象-->
<bean class="com.zzw.spring.bean.Employee" id="employee"><property name="name" value="tom"/><property name="dept" ref="dept"/><!--这里我希望给dept的name属性指定值[级联属性赋值]--><property name="dept.name" value="java开发"/>
</bean>

给属性进行级联赋值

public class SpringBeanTest {@Testpublic void setBeanByRelation() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Employee employee = ioc.getBean("employee", Employee.class);System.out.println("employee=" + employee);}
}

🍊通过静态工厂获取bean

在spring的ioc容器, 可以通过静态工厂获取bean对象

这是一个静态工厂类-可以返回Monster对象

package com.zzw.spring.factory;public class MyStaticFactory {private static Map<String, Monster> monsterMap;//使用static代码块进行初始化 - java基础static {monsterMap = new HashMap<>();monsterMap.put("monster01", new Monster(100, "齐天大圣", "如意金箍棒"));monsterMap.put("monster02", new Monster(200, "天蓬元帅", "九齿钉耙"));}//提供一个方法, 返回Monster对象public static Monster getMonster(String key) {return monsterMap.get(key);}
}
<!--配置Monster对象, 通过静态工厂获取
解读
1.通过静态工厂获取bean
2.class 是静态工厂类的全路径
3.factory-method 表示是指定静态工厂类的哪个方法返回对象
4.constructor-arg value="monster02" value是指定要返回静态工厂的哪一个对象
-->
<bean class="com.zzw.spring.factory.MyStaticFactory" id="myMonster01"factory-method="getMonster"><constructor-arg value="monster02"/>
</bean>

通过静态工厂获取bean

public class SpringBeanTest {@Testpublic void getBeanByStaticFactory() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Monster myMonster01 = ioc.getBean("myMonster01", Monster.class);Monster myMonster02 = ioc.getBean("myMonster01", Monster.class);System.out.println("myMonster01=" + myMonster01);System.out.println(myMonster01 == myMonster02);//true. myMonster01和myMonster02是同一个对象}
}

🍊bean配置信息重用

在spring的ioc容器, 提供了一种继承的方式来实现bean配置信息的重用

<!--配置Monster对象-->
<bean class="com.zzw.spring.bean.Monster" id="monster10"p:monsterId="10"p:name="蜘蛛侠"p:skill="吐丝"
/>
<!--1.配置Monster对象,2.但是这个对象的属性值和id="monster10"对象的属性值一样3.parent="monster10" 指定当前这个配置的对象的属性值从 id="monster10"的对象来
-->
<bean class="com.zzw.spring.bean.Monster" id="monster11" parent="monster10"/><!--配置Monster对象
1.如果bean指定了 abstract=true, 表示该bean对象, 是用于被继承
2.本身这个bean就不能被获取/实例化
-->
<bean class="com.zzw.spring.bean.Monster" id="monster12" abstract="true"p:monsterId="12"p:name="蜘蛛侠~"p:skill="吐丝~"
/>
<bean id="monster13" class="com.zzw.spring.bean.Monster" parent="monster12"/>

通过继承, 配置bean

public class SpringBeanTest {@Testpublic void getBeanByExtends() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Monster monster11 = ioc.getBean("monster11", Monster.class);System.out.println("monster11=" + monster11);Monster monster13 = ioc.getBean("monster13", Monster.class);System.out.println("monster13=" + monster13);}
}

🍊bean创建顺序

在spring的ioc容器, 默认是按照配置的顺序创建bean对象

测试bean创建顺序

public class SpringBeanTest {@Testpublic void testBeanCreateOrder() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");System.out.println("ok~");}
}

实验1

public class Department {public Department() {System.out.println("Department构造器 被执行");}
}
public class Student {public Student() {System.out.println("Student构造器 被执行");}
}

※会先创建student01这个bean对象, 然后创建department01这个bean对象
执行结果:
Student构造器 被执行
Department构造器 被执行
ok~

<!--测试bean对象的创建顺序
1.在默认情况下, bean创建的顺序是按照配置顺序来的
2.但是如果我们增加了 depends-on="department01" 这时就会先创建id=department01这个对象
-->
<bean class="com.zzw.spring.bean.Student" id="student01"/>
<bean class="com.zzw.spring.bean.Department" id="department01"/>

※如果这样配置, 会先创建department01对象, 再创建student01对象
执行结果:
Department构造器 被执行
Student构造器 被执行
ok~

<!--测试bean对象的创建顺序
1.在默认情况下, bean创建的顺序是按照配置顺序来的
2.但是如果我们增加了 depends-on="department01" 这时就会先创建id=department01这个对象
-->
<bean class="com.zzw.spring.bean.Student" id="student01" depends-on="department01"/>
<bean class="com.zzw.spring.bean.Department" id="department01"/>

实验2
1.先看下面的配置, 请问两个bean创建的顺序是什么? 并分析执行流程

  1. 先创建 id=memberDao
  2. 再创建 id=memberService
  3. 调用 memberService.setMemberDao() 完成引用

运行结果:
MemberDaoImpl 构造器…
MemberServiceImpl 构造器被执行
setMemberDao()…

<!--配置MemberDaoImpl对象-->
<bean class="com.zzw.spring.dao.MemberDaoImpl" id="memberDao"/><bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService"><property name="memberDao" ref="memberDao"/>
</bean>

2.先看下面的配置, 请问两个bean创建的顺序是什么? 并分析执行流程

  1. 先创建 id=memberService
  2. 再创建 id=memberDao
  3. 调用 memberService.setMemberDao() 完成引用

运行结果:
MemberServiceImpl 构造器被执行
MemberDaoImpl 构造器…
setMemberDao()…

<bean class="com.zzw.spring.service.MemberServiceImpl" id="memberService"><property name="memberDao" ref="memberDao"/>
</bean><!--配置MemberDaoImpl对象-->
<bean class="com.zzw.spring.dao.MemberDaoImpl" id="memberDao"/>

🍊bean的单例和多实例

在spring的ioc容器中, 默认情况下是按照单例创建的. 即配置一个bean对象后, ioc容器只会创建一个bean对象
如果我们希望ioc容器配置的某个bean对象, 是以多个实例形式创建的. 则可以通过配置 scope=“prototype” 来指定

public class Cat {private Integer id;private String name;public Cat() {//getter, setter方法
}
<!--配置Cat对象
1.在默认情况下, scope属性是 scope="singleton"
2.在ioc容器中, 只会有一个这样的bean对象
3.当程序员执行getBean时, 返回的是同一个对象
4.如果我们希望每次返回一个新的bean对象, 则可以这样配置 scope="prototype"
5.如果bean的配置是 scope="singleton" lazy-init="true" 这时, ioc容器就不会提前创建该对象, 而是当执行getBean方法的时候, 才会创建对象
-->
<bean class="com.zzw.spring.bean.Cat" id="cat" scope="prototype" lazy-init="true"><property name="id" value="100"/><property name="name" value="花喵"/>
</bean>

测试Scope

@Test
public void testBeanScope() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");Cat cat1 = ioc.getBean("cat", Cat.class);Cat cat2 = ioc.getBean("cat", Cat.class);Cat cat3 = ioc.getBean("cat", Cat.class);System.out.println("cat1=" + cat1);System.out.println("cat2=" + cat2);System.out.println("cat3=" + cat3);
}

使用细节
1)bean默认是单例singleton; 在启动容器时, bean默认就会创建, 并放入到singletonObjects
2) 当<bean scope=“prototype”>设置为多实例机制后, 该bean是在getBean()时被创建
3) 如果是单例singleton, 同时希望在getBean时才创建, 可以指定懒加载 lazy-init="true"(注意默认是false)
4) 通常情况下, lazy-init 就使用默认值false. 在开发看来, 空间换时间是值得的, 除非有特殊要求
5) 如果scope=“prototype”, 这时你的lazy-init 属性的值不管是true还是false, 都是在getBean的时候才创建这个对象

🍊bean的生命周期

bean对象创建是由JVM完成的, 然后执行如下方法

  1. 执行构造器
  2. 执行set相关方法
  3. 调用bean的初始化方法(需要配置)
  4. 使用bean
  5. 当容器关闭的时候, 调用bean的销毁方法(需要配置)
public class House {private String name;public House() {System.out.println("House构造器 被执行...");}public void setName(String name) {System.out.println("House setName()=" + name);this.name = name;}//解读//1.这个方法是由程序员来编写的//2.根据自己的业务逻辑来写.//3.名字也不是固定的public void init() {System.out.println("House init()....");}//解读//1.这个方法是由程序员来编写的//2.根据自己的业务逻辑来写.//3.名字也不是固定的public void destroy() {System.out.println("House destroy()...");}
}
<!--配置House对象, 演示整个bean的生命周期
解读
1.init-method="init" 指定bean的初始化方法, 在setter方法后执行
2.init方法执行的时机, 由spring容器控制
3.destroy-method="destroy" 指定bean的销毁方法, 在容器关闭的时候执行
4.destroy方法执行的时机, 由spring容器控制
-->
<bean class="com.zzw.spring.bean.House" id="house"init-method="init" destroy-method="destroy"><property name="name" value="上海豪宅"/>
</bean>

测试bean的生命周期

public class SpringBeanTest {@Testpublic void testBeanLife() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");House house = ioc.getBean("house", House.class);System.out.println("house=" + house);//关闭容器//1.ioc的编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext//2.因为ClassPathXmlApplicationContext 实现了 ConfigurableApplicationContext//3.ClassPathXmlApplicationContext 是由close()//4.将ioc 转成ClassPathXmlApplicationContext, 再调用close()//ioc.close()//5.关闭ioc容器((ClassPathXmlApplicationContext) ioc).close();}
}

输出

House构造器 被执行...
House setName()=上海豪宅
House init()....
setMemberDao()...
house=com.zzw.spring.bean.House@327bcebd
House destroy()...

使用细节
1.初始化init方法和destroy方法, 由程序员来指定
2.销毁方法就是当关闭容器时, 才会被调用

🍊配置bean后置处理器

1在spring的ioc容器, 可以配置bean的后置处理器
2.该 处理器/对象 会在bean初始化方法调用前和初始化方法调用后被调用
3.程序员可以在后置处理器中编写自己的代码

package com.zzw.spring.bean;//ctrl+h 可以查看类的继承关系
//这是一个后置处理器, 需要实现 BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {/*** 什么时候被调用: 在Bean的init方法前被调用* @param bean     传入在IOC容器中 创建/配置 的bean* @param beanName 传入在IOC容器中 创建/配置 的bean的id* @return Object 是程序员对传入的bean进行修改/处理[如果有需要的话], 返回* @throws BeansException*/@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization()... bean="+ bean + " beanName=" + beanName);return bean;}/*** 什么时候被调用: 在Bean的init方法后被调用* @param bean     传入在IOC容器中 创建/配置 的bean* @param beanName 传入在IOC容器中 创建/配置 的bean的id* @return Object 是程序员对传入的bean进行修改/处理[如果有需要的话], 返回* @throws BeansException*/@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization()... bean="+ bean + " beanName=" + beanName);return bean;}
}

新建beans02.xml配置文件

<!--配置House对象-->
<bean class="com.zzw.spring.bean.House" id="house"init-method="init"destroy-method="destroy"><property name="name" value="大豪宅"/>
</bean><!--配置后置处理器对象
解读:
1.当我们在beans02.xml 容器配置文件, 配置了MyBeanPostProcessor
2.这时后置处理器对象, 就会作用在该容器的创建的bean对象
-->
<bean class="com.zzw.spring.bean.MyBeanPostProcessor" id="beanPostProcessor"/>

测试

package com.zzw.spring.test;public class SpringBeanTest {@Testpublic void testBeanPostProcessor() {ApplicationContext ioc =new ClassPathXmlApplicationContext("beans02.xml");House house = ioc.getBean("house", House.class);System.out.println("使用house=" + house);//关闭容器//ioc不能调用子类的特有的成员//因为在编译阶段, 能调用哪些成员, 是由编译类型来决定的//ioc编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext((ClassPathXmlApplicationContext) ioc).close();//向下转型}
}

其它说明
1.怎么执行到这个方法? => 使用AOP(反射+动态代理+IO+容器+注解)
2.有什么用? => 可以对IOC容器中所有的对象进行统一处理, 比如日志处理/权限校验/安全验证/事务管理.
-初步体验案例: 如果类型是House的同意改成 上海豪宅
3.针对容器的所有对象吗? 是的=>切面编程
4.后面我们会自己实现这个底层机制
5.这是一个比较难以理解的知识点.

<!--配置House对象-->
<bean class="com.zzw.spring.bean.House" id="house"init-method="init"destroy-method="destroy"><property name="name" value="大豪宅"/>
</bean><bean class="com.zzw.spring.bean.House" id="house02"init-method="init"destroy-method="destroy"><property name="name" value="宫殿"/>
</bean><!--配置后置处理器对象
解读:
1.当我们在beans02.xml 容器配置文件, 配置了MyBeanPostProcessor
2.这时后置处理器对象, 就会作用在该容器的创建的bean对象
3.已经是针对所有对象编程->切面编程AOP
-->
<bean class="com.zzw.spring.bean.MyBeanPostProcessor" id="beanPostProcessor"/>
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessBeforeInitialization()... bean="+ bean + " beanName=" + beanName);//对多个对象进行处理/编程=>切面编程if (bean instanceof House) {((House) bean).setName("上海豪宅~");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("postProcessAfterInitialization()... bean="+ bean + " beanName=" + beanName);return bean;}
}
public class SpringBeanTest {@Testpublic void testBeanPostProcessor() {ApplicationContext ioc =new ClassPathXmlApplicationContext("beans02.xml");House house = ioc.getBean("house", House.class);House house02 = ioc.getBean("house02", House.class);System.out.println("使用house=" + house);System.out.println("使用house=" + house02);//关闭容器//ioc不能调用子类的特有的成员//因为在编译阶段, 能调用哪些成员, 是由编译类型来决定的//ioc编译类型 ApplicationContext, 运行类型 ClassPathXmlApplicationContext((ClassPathXmlApplicationContext) ioc).close();//向下转型}
}

测试结果

House构造器 被执行...
House setName()=大豪宅
postProcessBeforeInitialization()... bean=House{name='大豪宅'} beanName=house
House setName()=上海豪宅~
House init()....
postProcessAfterInitialization()... bean=House{name='上海豪宅~'} beanName=house
House构造器 被执行...
House setName()=宫殿
postProcessBeforeInitialization()... bean=House{name='宫殿'} beanName=house02
House setName()=上海豪宅~
House init()....
postProcessAfterInitialization()... bean=House{name='上海豪宅~'} beanName=house02
使用house=House{name='上海豪宅~'}
使用house=House{name='上海豪宅~'}
House destroy()...
House destroy()...

🍊通过属性文件配置bean

在spring的ioc容器, 通过属性文件给bean注入值

在src目录下, 新建配置文件my.properties [配置文件都要写在src目录下]

monsterId=1000
name=\u5343\u5e74\u9f9f 
skill=\u65cb\u8f6c\u6253\u51fb

解决中文乱码问题
在这里插入图片描述

<!--指定属性文件
说明
1.先把文件修改成提示All Problem
2.提示错误, 将光标放在context 输入alt+enter, 就会自动引入namespace
3.location="classpath:my.properties" 表示指定属性文件的位置
4.提示, 需要带上 classpath
-->
<context:property-placeholder location="classpath:my.properties"/><!--配置monster对象
1.通过属性文件给monster对象的属性赋值
2.这时我们的属性值, 通过${属性名}
3.这里说的 属性名, 就是 my.properties文件中的 k=v 的k
-->
<bean class="com.zzw.spring.bean.Monster" id="monster100"><property name="monsterId" value="${monsterId}"/><property name="name" value="${name}"/><property name="skill" value="${skill}"/>
</bean>
public class SpringBeanTest {//通过属性文件给bean属性赋值@Testpublic void setBeanByFile() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans03.xml");Monster monster100 = ioc.getBean("monster100", Monster.class);System.out.println("monster100=" + monster100);}
}

🍊基于XML的bean的自动装配

在spring的ioc容器, 可以实现自动装配bean

这里说的Action就是我们前面学习过的Servlet -> 充当Controller
Dao

package com.zzw.spring.dao;public class OrderDao { //DAO类public void saveOrder() {System.out.println("保存一个订单....");}
}

Service

package com.zzw.spring.service;public class OrderService { //Service类//OrderDao属性private OrderDao orderDao;//getter方法public OrderDao getOrderDao() {return orderDao;}//setter方法public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}
}

Action

package com.zzw.spring.web;public class OrderAction { //Servlet就是Controller//OrderService属性private OrderService orderService;//getter方法public OrderService getOrderService() {return orderService;}//setter方法public void setOrderService(OrderService orderService) {this.orderService = orderService;}
}

bean03.xml

<!--配置OrderDao对象-->
<bean class="com.zzw.spring.dao.OrderDao" id="orderDao"/>
<!--配置OrderService对象
解读:
1.autowire="byType" 表示 在创建orderService时,通过类型的方式给对象的属性 自动完成赋值/引用
2.比如OrderService对象有 private OrderDao orderDao
3.就会在容器中去找有没有 OrderDao类型对象
4.如果有, 就会自动地装配. 提示: 如果是按照 byType 方式来装配, 这个容器中不能有两个OrderDao类型的对象
5.如果你的对象没有属性, autowire就没有必要写
6.其它类推...
-->
<bean autowire="byType" class="com.zzw.spring.service.OrderService"id="orderService"/>
<!--配置OrderAction对象-->
<bean autowire="byType" class="com.zzw.spring.web.OrderAction" id="orderAction"/>

通过自动装配来对属性赋值

//通过自动装配来对属性赋值
public class SpringBeanTest {@Testpublic void setBeanByAutowire() {ApplicationContext ioc =new ClassPathXmlApplicationContext("beans03.xml");OrderAction orderAction = ioc.getBean("orderAction", OrderAction.class);//验证是否自动装配上OrderServiceSystem.out.println(orderAction.getOrderService());//验证是否自动装配上OrderDaoSystem.out.println(orderAction.getOrderService().getOrderDao());}
}

byName方式讲解

<!--
7.如果我们设置的是 autowire="byName" 表示通过名字完成自动装配
8.比如下面的 autowire="byName" class="com.zzw.spring.service.OrderService"1) 先看 OrderService 属性 private OrderDao orderDao;2) 再根据这个属性的setXxx()方法的 xxx 来找对象id3) public void setOrderDao() 就会找 id=orderDao对象来进行自动装配4) 如果没有就装配失败
-->
<bean autowire="byName" class="com.zzw.spring.service.OrderService"id="orderService"/>
<!--配置OrderAction对象-->
<bean autowire="byName" class="com.zzw.spring.web.OrderAction"id="orderAction"/>

🍊Spring El 表达式配置Bean

1.Spring Expression Language, Spring表达式语言, 简称SpEL. 支持运行时查询并可以操作对象.
2.和EL表达式一样, SpEL根据JavaBean风格的getXxx(), setXxx()方法定义的属性访问对象
3.SpEL使用#{…}作为界定符, 所有在大括号中的字符都被认为是SpEL表达式
4.不是重点, 能看懂即可.

public class SpELBean {private String name;private Monster monster;private String monsterName;private String crySound;private String bookName;private Double reuslt;public SpELBean() {}//普通方法, 返回字符串public String cry(String crySound) {return "发出 " + " 的声音";}//静态方法 返回字符串public static String read(String bookName) {return "正在读" + bookName;}//getter方法, setter方法@Overridepublic String toString() {return "SpELBean{" +"name='" + name + '\'' +"\nmonster=" + monster +"\nmonsterName='" + monsterName + '\'' +"\ncrySound='" + crySound + '\'' +"\nbookName='" + bookName + '\'' +"\nreuslt=" + reuslt +'}';}
}

beans04.xml

<!--配置一个monster对象-->
<bean class="com.zzw.spring.bean.Monster" id="monster01"p:monsterId="001"p:name="齐天大圣"p:skill="金箍棒"
/><!--spring el 表达式使用
解读
1.通过spEl给bean的属性赋值
-->
<bean class="com.zzw.spring.bean.SpELBean" id="spELBean"><!--sp el 给字面量--><property name="name" value="#{'赵志伟'}"/><!--sp el 引用其它bean--><property name="monster" value="#{monster01}"/><!--sp el 引用其它bean的属性值--><property name="monsterName" value="#{monster01.name}"/><!--sp el 调用普通方法(返回值) 赋值--><property name="crySound" value="#{spELBean.cry('小猫')}"/><!--sp el 调用静态方法(返回值) 赋值--><property name="bookName" value="#{T(com.zzw.spring.bean.SpELBean).read('安乐传')}"/><!--sp el 通过运算赋值--><property name="reuslt" value="#{72+53*33.8}"/>
</bean>
//通过spring el 对属性赋值
public class SpringBeanTest {@Testpublic void setBeanBySpEl() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans04.xml");SpELBean spELBean = ioc.getBean("spELBean", SpELBean.class);System.out.println("spELBean=" + spELBean);}
}

测试结果

spELBean=SpELBean{name='赵志伟'
monster=Monster{monsterId='1', name='齐天大圣', skill='金箍棒'}
monsterName='齐天大圣'
crySound='发出 小猫 的声音'
bookName='正在读安乐传'
reuslt=1863.3999999999999}

在这里插入图片描述
下乘: Spring系列二:基于注解配置bean. 未完待续…

相关文章:

Spring系列一:spring的安装与使用

文章目录 &#x1f49e; 官方资料&#x1f34a;Spring5下载&#x1f34a;文档介绍 &#x1f49e;Spring5&#x1f34a;内容介绍&#x1f34a;重要概念 &#x1f49e;快速入门&#x1f34a;Spring操作演示&#x1f34a;类加载路径&#x1f34a;Debug配置&#x1f34a;Spring容器…...

Ubuntu--科研工具系列

翻译系列 pot-desktop github链接: https://github.com/pot-app/pot-desktop 下载deb Releases pot-app/pot-desktop GitHub 安装过程 在下载好的deb目录下打开终端(自动安装依赖) sudo apt install "XXX.deb" &#xff08;后面可以直接托文件到终端&#…...

【压测指南|压力测试核心性能指标及行业标准】

文章目录 压力测试核心性能指标及行业标准指标1&#xff1a;响应时间指标2&#xff1a;吞吐量&#xff08;TPS)指标3&#xff1a;失败率总结&#xff1a; 压力测试核心性能指标及行业标准 在做压力测试时&#xff0c;新手测试人员常常在看报告时倍感压力&#xff1a;这么多性能…...

spark-submit --files

一、原理 spark-submit --files通常用来加载外部资源文件&#xff0c;在driver和executor进程中进行访问 –files和–jars基本相同 二、使用步骤 2.1 添加文件 spark-submit --files file_paths 其中file_paths可为多种方式&#xff1a;file: | hdfs:// | http:// | ftp:// |…...

应该选云服务器还是物理服务器

应该选云服务器还是物理服务器 一、为什么需要云服务器或独立服务器取代共享主机 在最早之前&#xff0c;大多数的网站都是共享主机开始的&#xff0c;这里也包含了云虚拟机。这一类的站点还有其他站点都会共同托管在同一台服务器上。但是这种共享机只适用于小的网站&#xff…...

【iOS】动态链接器dyld

参考&#xff1a;认识 dyld &#xff1a;动态链接器 dyld简介 dyld&#xff08;Dynamic Linker&#xff09;是 macOS 和 iOS 系统中的动态链接器&#xff0c;它是负责在运行时加载和链接动态共享库&#xff08;dylib&#xff09;或可执行文件的组件。在 macOS 系统中&#xf…...

RocketMQ集成Springboot --Chapter1

RocketMQ集成Springboot 三种消息发送方式 生产者 引入依赖 <!--⽗⼯程--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.2.RELEASE</version><…...

【Unity3D日常开发】Unity3D中比较string字符串的常用方法

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 字符串string的比较有很多方法&#xff0c;比如&#xff1a; …...

vue3+ts+element-plus 之使用node.js对接mysql进行表格数据展示

vue3tselement-plus axiosnode.jsmysql开发管理系统之表格展示 ✏️ 1. 新建一个node项目* 初始化node* 安装可能用到的依赖* 配置文件目录* 添加路由router1. 添加router.js文件&#xff0c;添加一个test目录2. 修改app.js ,引入router&#x1f4d2; 3. 启动并在浏览器打开 * …...

华为eNSP:isis配置跨区域路由

一、拓扑图 二、路由器的配置 1、配置接口IP AR1: <Huawei>system-view [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei-GigabitEthernet0/0/0]q AR2: [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.2 24 [Huawe…...

IUPAC和SMILES的相互转换

这种方法只能解决非常简单的转换&#xff0c;更难的SMILES之间应该是无法直接转换&#xff0c;我可能很多人都使用神经网络解决 &#xff0c;暂时还没仔细看&#xff0c;后面再仔细看吧... 简单的转换&#xff1a; import urllib.error import urllib.parse import urllib.re…...

逻辑回归概述

逻辑回归介绍 1. 逻辑回归的应用场景 逻辑回归(Logistic Regression)是机器学习中的 一种分类模型 ,逻辑回归是一种分类算法,虽然名字中带有回归。由于算法的简单和高效,在实际中应用非常广泛 广告点击率是否为垃圾邮件是否患病信用卡账单是否会违约 逻辑回归就是解决二…...

React 框架下自己写一个braft编辑器,然后将编辑器内容展示在网页端

1.首先自己写一个编辑器 输入文字&#xff1b; 支持选择表情&#xff1b; 可添加小程序链接&#xff1b;可添加网页链接&#xff1b;并且可以编辑删除&#xff1b;效果如下 2.输入完毕后&#xff0c;点击文本输入框保存&#xff0c;将便携式内容回显&#xff0c; 渲染时…...

基于DNN深度学习网络的OFDM+QPSK信号检测算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ............................................................................. Transmitt…...

学生管理系统-05封装选项卡

一、选项卡的添加 1、在router/index.js修改之前的动态添加二级路由的代码 router.addRoute("homeName",{ path:routeObj.path, component:()=>import(`@/views${routeObj.permission}.vue`), meta:{ name:routeObj.title …...

关于一些C++、Qt、Python方面的术语

杂鱼之前纯粹用python没细致理解过的术语整理一下&#xff0c;常看常新&#xff08; 定义 (Definition)&#xff1a; 定义是指给一个实体分配内存空间&#xff0c;以便在程序中使用。在C和Python中&#xff0c;这个实体可以是变量、函数或类。在C中&#xff0c;定义通常是在声…...

k8s中强制删除pv

K8s 集群内有一个已经不再使用的 PV&#xff0c;虽然已经删除了与其关联的 Pod 及 PVC&#xff0c;并对其执行了删除命令&#xff0c;但仍无法正常删除&#xff0c;一直处于 Terminating 状态&#xff1a; 解决办法&#xff1a; 1. 获取pv信息 kubectl get pv 2. 解除pv锁定 …...

60寸透明屏的透明度怎么样?

60寸透明屏是一种新型的显示屏技术&#xff0c;它具有透明度高、色彩鲜艳、清晰度高等特点&#xff0c;可以广泛应用于商业展示、户外广告、智能家居等领域。 首先&#xff0c;60寸透明屏的透明度高。 透明屏采用了特殊的材料和技术&#xff0c;使得屏幕在显示内容的同时&…...

Python:使用openpyxl读取Excel文件转为json数据

文档 https://openpyxl.readthedocs.io/en/stable/https://pypi.org/project/openpyxl/ 安装 pip install openpyxl环境 $ python --version Python 3.7.0读取文件示例&#xff1a;将Excel文件读取为json数据 有如下一个文件 data.xlsx 实现代码 # -*- coding: utf-8 -…...

在Microsoft Excel中如何快速合并表格

在 Excel 中分析数据时&#xff0c;在一个工作表中收集所有必要信息的频率是多少&#xff1f;几乎从来没有&#xff01;当不同的数据分散在许多工作表和工作簿中时&#xff0c;这是一种非常常见的情况。幸运的是&#xff0c;有几种不同的方法可以将多个表中的数据组合成一个表&…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

Oracle查询表空间大小

1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...