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下载
- 进入官网: https://spring.io/
- 进入Spring5(框架就是一系列jar包. 引入jar包, 就可以使用spring)
- 进入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 |
离线API | spring-framework-5.3.8\docs\javadoc-api\index.html |
💞Spring5
🍊内容介绍
Spring核心学习内容 IOC, AOP, jdbcTemplate, 声明式事务
- IOC: 控制反转, 可以管理java对象
- AOP: 切面编程
- JDBCTemplate: 是spring提供的一套访问数据库的技术. 应用性强, 相对好理解
- 声明式事务: 基于ioc/aop实现事务管理
- IOC, AOP 是重点同时是难点, 需要时间理解
🍊重要概念
-
Spring可以整合其它的框架(解读: Spring是管理框架的框架)
-
Spring有两个核心的概念: IOC 和 AOP
-
IOC [Inversion Of Control 反转控制]
-
传统的开发模式[JDbcUtils / 反射], 程序------>环境 //程序读取环境配置, 然后自己创建对象
以连接到数据库为例
程序员编写程序, 在程序中读取配置信息
创建对象, 使用对象完成任务 -
Spring方式
Spring根据配置文件xml / 注解, 创建对象, 并放入到容器(ConcurrentHashMap). 并且可以完成对象之间的依赖
当需要使用某个对象实例的时候, 就直接从容器中获取即可
这样程序员可以更加关注如何使用对象完成相应的业务(以前是new -> 现在是注解 / 配置) -
DI - Dependency Injection依赖注入, 可以理解成是IOC的别称
Spring最大的价值是 通过配置, 给程序员提供需要使用的对象web层[Servlet (Action/Controller)/ Service / Dao / JavaBean(entity)]对象
这是核心价值所在, 也是ioc的具体体现, 实现解耦
💞快速入门
🍊Spring操作演示
需求: 通过Spring的方式[配置文件], 获取JavaBean-Monster的对象, 并给该对象的属性赋值, 输出该对象的信息
- 下载Spring5开发包, Spring5开发包资源博主已上传
- 创建Java工程, Spring5
- 新建lib目录, 引入开发Spring5的基本包
- 创建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()
}
- 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>
- 测试
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配置程序
需求说明
- 自己写一个简单的Spring容器, 通过读取beans.xml, 获取第1个JavaBean: Monster的对象, 并给该对象的属性赋值, 放入到容器中, 并输出该对象信息
- 也就是说, 不使用Spring原生框架, 我们自己简单模拟实现
- 了解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对象.
- 不会报错, 会正常运行
- 系统会默认分配id. 分配id的规则是: 全类名#0, 全类名#1 这样的规则来分配id的. 例如 com.zzw.spring.bean.Monster#0, com.zzw.spring.bean.Monster#1
- 通过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类, 要求
- 创建ioc容器文件(配置文件), 并配置一个Car对象(bean).
- 通过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();}
}
🍊对集合数组属性进行配置
引用/注入 集合/数据类型
- 主要掌握List / Map / Properties 三种集合的使用
- Properties是Hashtable的子类, 是key-value的形式
- 这里的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创建的顺序是什么? 并分析执行流程
- 先创建 id=memberDao
- 再创建 id=memberService
- 调用 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创建的顺序是什么? 并分析执行流程
- 先创建 id=memberService
- 再创建 id=memberDao
- 调用 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完成的, 然后执行如下方法
- 执行构造器
- 执行set相关方法
- 调用bean的初始化方法(需要配置)
- 使用bean
- 当容器关闭的时候, 调用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的安装与使用
文章目录 💞 官方资料🍊Spring5下载🍊文档介绍 💞Spring5🍊内容介绍🍊重要概念 💞快速入门🍊Spring操作演示🍊类加载路径🍊Debug配置🍊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" (后面可以直接托文件到终端&#…...

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

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

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

【iOS】动态链接器dyld
参考:认识 dyld :动态链接器 dyld简介 dyld(Dynamic Linker)是 macOS 和 iOS 系统中的动态链接器,它是负责在运行时加载和链接动态共享库(dylib)或可执行文件的组件。在 macOS 系统中…...

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插件分享简书地址我的个人博客 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。 一、前言 字符串string的比较有很多方法,比如: …...

vue3+ts+element-plus 之使用node.js对接mysql进行表格数据展示
vue3tselement-plus axiosnode.jsmysql开发管理系统之表格展示 ✏️ 1. 新建一个node项目* 初始化node* 安装可能用到的依赖* 配置文件目录* 添加路由router1. 添加router.js文件,添加一个test目录2. 修改app.js ,引入router📒 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的相互转换
这种方法只能解决非常简单的转换,更难的SMILES之间应该是无法直接转换,我可能很多人都使用神经网络解决 ,暂时还没仔细看,后面再仔细看吧... 简单的转换: import urllib.error import urllib.parse import urllib.re…...

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

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

基于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没细致理解过的术语整理一下,常看常新( 定义 (Definition): 定义是指给一个实体分配内存空间,以便在程序中使用。在C和Python中,这个实体可以是变量、函数或类。在C中,定义通常是在声…...

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

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

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

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

【RS】基于规则的面向对象分类
ENVI使用最多的工具就是分类,这也是很多卫星影像的用途。在ENVI中有很多分类工具,如最基础的监督分类(最大似然法、最小距离、支持向量机、随机森林)、非监督分类(K-means、IsoData),还有面向对…...

SWF格式视频怎么转换成AVI格式?简单的转换方法分享
当你想要在不同的设备上播放视频时,将SWF格式视频转换成AVI格式是非常有用的。因为SWF格式通常只能在特定的软件或网页上播放,而AVI格式则可以在更广泛的设备上播放,包括智能手机,平板电脑和电视机等。那么我们怎么将SWF转换成AVI…...

Hive数据仓库
数据仓库概念与起源发展由来 数仓概念 数据仓库(英语:Data Warehouse,简称数仓、DW),是一个用于存储、分析、报告的数据系统。数据仓库的目的是构建面相分析的集成化数据环境,分析结果为企业提供决策支持…...

公网访问的Linux CentOS本地Web站点搭建指南
文章目录 前言1. 本地搭建web站点2. 测试局域网访问3. 公开本地web网站3.1 安装cpolar内网穿透3.2 创建http隧道,指向本地80端口3.3 配置后台服务 4. 配置固定二级子域名5. 测试使用固定二级子域名访问本地web站点 前言 在web项目中,部署的web站点需要被外部访问,则…...

ChatGPT:人机交互新境界,AI智能引领未来
一、ChatGPT:智能交流的新标杆 ChatGPT是基于GPT技术的最新版本,拥有深度学习模型的基因。它通过在大量数据上进行预训练,可以理解和生成自然语言,从而实现了与人类更加自然流畅的对话和交流。 二、ChatGPT的技术背景和工作原理 …...

微信小程序值相同的数据,一个数据setDate修改后,另一个值相同的数据也会修改
在js中一个基础类型可以直接赋值,引用类型直接赋值会指向同一个值(原理是浅拷贝和深拷贝) 解决问题代码:JSON.parse(JSON.stringify(json)) ↓ let json {0: [false, false],1: [true, false] } this.setData({timeList: JSON.…...

Spring5学习笔记 — IOC
✅作者简介:大家好,我是Cisyam,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Cisyam-Shark的博客 💞当前专栏: Spring专栏 ✨特色专栏&a…...

DevOps自动化平台开发之 Shell脚本执行的封装
基础知识 基于如下技术栈开发DevOps平台 Spring Boot Shell Ansible Git Gitlab Docker K8S Vue 1、spring boot starter的封装使用 2、Shell脚本的编写 3、Ansible 脚本的编写 4、Docker 的使用与封装设计 本篇介绍如何使用Java封装Linux命令和Shell脚本的使用 将其设计成…...

STM32CubeIDE(I2C)
目录 一、IIC轮询模式 1.1 配置 1.2 编写AHT20驱动 1.2.1 aht20.h 1.2.2 aht20.c 二、I2C中断 2.1 打开中断 2.2 分离读取流程 2.3 在主函数中重新编写读取流程 2.4 在i2c.c中重新定义stm32f1xx_hal_i2c.h中的两个函数 三、I2CDMA 3.1 配置DMA通道 3.2 代码的修改 一…...

http 请求报文响应报文的格式以及Token cookie session 区别
面试必备 http 请求报文响应报文的格式Token cookie session 区别 http 请求报文响应报文的格式 HTTP 请求报文和响应报文的格式如下: HTTP 请求报文格式: <方法> <路径> <协议版本> <请求头部字段1>: <值1> <请求头…...