【Spring6】| Spring对IoC的实现(核心重点)
目录
一:Spring对IoC的实现
1. IoC 控制反转
2. 依赖注入
2.1 set注入
2.2 构造注入
3. set注入专题
3.1 注入外部Bean
3.2 注入内部Bean
3.3 注入简单类型
3.4 级联属性赋值(了解)
3.5 注入数组
3.6 注入List集合和Set集合
3.7 注入Map和Properties集合
3.8 注入null和空字符串
3.9 注入的值中含有特殊符号
4. p命名空间注入
5. c命名空间注入
6. util命名空间
7. 基于XML的自动装配(byName & byType)
7.1 根据名称(byName)自动装配
7.2 根据类型(byType)自动装配
8. Spring引入外部属性配置文件(使用context命名空间)
一:Spring对IoC的实现
前面我们已经学会了如何用spring创建管理对象,接下来就要学习如何让对象和对象产生关系,使用依赖注入!
1. IoC 控制反转
(1)控制反转是一种思想,一种新型的设计模式!
(2)控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。
(3)控制反转,反转的是什么?
①将对象的创建权利交出去,交给第三方容器负责。
②将对象和对象之间关系的维护权交出去,交给第三方容器负责。
(4)控制反转这种思想如何实现呢?
DI(Dependency Injection):依赖注入
2. 依赖注入
依赖注入实现了控制反转的思想!
Spring通过依赖注入的方式来完成Bean管理的。Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。
依赖注入:
- 依赖指的是对象和对象之间的关联关系。
- 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。
依赖注入常见的实现方式包括两种:
- 第一种:set注入
- 第二种:构造注入
2.1 set注入
set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值;这种方式要求属性必须对外提供set方法!
pom.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bjpowernode</groupId><artifactId>spring6-002-dependency-injection</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><!--配置多个仓库--><repositories><!--spring6里程碑的仓库--><repository><id>repository.spring.milestone</id><name>Spring Milestone Repository</name><url>https://repo.spring.io/milestone</url></repository></repositories><dependencies><!--spring context依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>6.0.0-M2</version></dependency><!--单元测试依赖--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!--log4j2的依赖--><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.19.0</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.19.0</version></dependency></dependencies><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target></properties></project>
log4j2.xml日志配置
<?xml version="1.0" encoding="UTF-8"?><configuration><loggers><root level="DEBUG"><appender-ref ref="spring6log"/></root></loggers><appenders><console name="spring6log" target="SYSTEM_OUT"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/></console></appenders></configuration>
UserDao类:连接数据库的操作
package com.bjpowernode.spring6.dao;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class UserDao {// 一般声明为常量private static final Logger logger = LoggerFactory.getLogger(UserDao.class);// 使用日志进行打印,用System.out.println也可以public void insert(){logger.info("数据库正在保存用户信息!");}
}
UserService类:调用UserDao中的方法
①set注入的话,必须提供一个set方法;Spring容器会调用这个set方法,来给userDao属性赋值。
②这个set方法不符合javabean规范也可以,但是必须以set开头,例如:setUD也是可以的;这里我使用的是IDEA自动生成的符合javabean规范的。
package com.bjpowernode.spring6.service;import com.bjpowernode.spring6.dao.UserDao;public class UserService {private UserDao userDao;// set注入,必须提供一个set方法public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void saveUser(){// 调用UserDao保存用户信息userDao.insert();}
}
spring.xml配置
①配置userDaoBean和UserService,让spring管理这两个类。
②对于UserService,想让Spring调用对应的set方法,需要配置property标签:
name属性值:set方法的方法名,去掉set,然后把剩下的单词首字母变小写
ref属性值:翻译为引用,英语单词references,后面指定的是要注入的bean的id
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"><!--配置dao--><bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/><!--配置service--><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService"><property name="userDao" ref="userDaoBean" /></bean>
</beans>
③另外,对于property标签来说,ref属性也可以采用标签的方式,但使用ref属性是多数的:
<bean id="userServiceBean" class="com.powernode.spring6.service.UserService"><property name="userDao"><ref bean="userDaoBean"/></property>
</bean>
编写测试类
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class DITest {@Testpublic void testSetDI(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);userServiceBean.saveUser();}
}
执行结果:
正常输出日志信息了,说明两个问题:
①spring正常创建UserDao和UserService对象了!
②spring关联了对象与对象之间的关系了!
总结:set注入的核心实现原理是通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系。
2.2 构造注入
核心原理:通过调用构造方法来给属性赋值。
①set注入:是先创建对象,才能执行set方法,给属性赋值。
②构造注入:是在创建对象的同时,给属性赋值,时机是不同的。
在定义一个VipDao类
package com.bjpowernode.spring6.dao;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class VipDao {private static final Logger logger = LoggerFactory.getLogger(VipDao.class);public void delete(){logger.info("正在删除信息!");}
}
ConstructService类
构造方法注入,必须要提供一个构造方法!
package com.bjpowernode.spring6.service;import com.bjpowernode.spring6.dao.UserDao;
import com.bjpowernode.spring6.dao.VipDao;public class ConstructService {private UserDao userDao;private VipDao vipDao;// 构造注入,必须有构造方法public ConstructService(UserDao userDao, VipDao vipDao) {this.userDao = userDao;this.vipDao = vipDao;}public void save(){userDao.insert();vipDao.delete();}
}
bean.xml配置
访问的方式有三种:使用的是constructor-arg标签
①第一种方式是根据下标index的方式,下标的顺序是构造方法参数的顺序。
②第二种方式是根据构造方法参数的名字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"><bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/><bean id="vipDaoBean" class="com.bjpowernode.spring6.dao.VipDao"/><bean id="constructServiceBean" class="com.bjpowernode.spring6.service.ConstructService"><!--第一种方式--><constructor-arg index="0" ref="userDaoBean"/><constructor-arg index="1" ref="vipDaoBean" /><!--第二种方式--><constructor-arg name="userDao" ref="userDaoBean"/><constructor-arg name="vipDao" ref="vipDaoBean"/><!--第三种方式--><constructor-arg ref="userDaoBean"/><constructor-arg ref="vipDaoBean" /></bean></beans>
编写测试
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.service.ConstructService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class ConstructTest {@Testpublic void testConstructDI(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");ConstructService constructServiceBean = applicationContext.getBean("constructServiceBean", ConstructService.class);constructServiceBean.save();}
}
执行结果:
3. set注入专题
set注入和构造注入中,set注入用的比较多,所以下面就学习一下set注入的专题!
3.1 注入外部Bean
(1)在之前我们使用的案例一直就是注入外部Bean的方式!
(2)外部Bean的特点:bean定义到外面,在property标签中使用ref属性进行注入;通常这种方式是常用!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"><bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService"><property name="userDao" ref="userDaoBean" /></bean>
</beans>
3.2 注入内部Bean
内部Bean的方式:在bean标签中直接嵌套bean标签,不需要ref属性引入。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService"><property name="userDao"><bean class="com.bjpowernode.spring6.dao.UserDao"/></property></bean>
</beans>
3.3 注入简单类型
(1)之前在进行注入的时候,对象的属性都是另一个对象;那如果对象的属性是int类型呢?也可以通过set注入的方式给该属性赋值,实际上只要能够调用set方法就可以给属性赋值。
(2)重点:如果给简单类型赋值,就不能使用ref属性,需要使用value属性!
User类:定义了两个简单类型,写上set方法
package com.bjpowernode.spring6.bean;public class User {private String name;private int age;public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
set-di.xm配置
注:既可以使用value标签的方式,也可以使用value属性的方式(常用)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="userBean" class="com.bjpowernode.spring6.bean.User"><property name="age" value="18"/><property name="name" value="张三"/></bean>
</beans>
编写测试
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class SetDITest {@Testpublic void testSimpleTypeSet(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");User user = applicationContext.getBean("userBean", User.class);System.out.println(user);}
}
执行结果:默认会调用toString方法
需要特别注意:如果给简单类型赋值,使用value属性或value标签,而不是ref!
(3)那么简单类型包括哪些呢?可以通过Spring的源码来分析一下!
双击shift搜索BeanUtils类,ctrl+F12搜索isSimpleValueType方法,里面都是简单类型:
(4)这里重点说一下Date类型,如果硬要把Date类型当做简单类型,使用value赋值的话,这个日期的格式有要求:Thu Jan 12 21:05:49 CST 2023 ,所以在实际的开发中,我们一般采用ref属性的方式给Date类型的属性赋值!
(5)简单类型注入的经典案例:给数据源的属性注入值:
假设我们现在要自己手写一个数据源(能够提供Connection对象的),我们都知道所有的数据源都要实现javax.sql.DataSource接口,并且数据源中应该有连接数据库的信息,例如:driver、url、username、password等。
数据源MyDataSource
package com.bjpowernode.spring6.jdbc;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;public class MyDateSource implements DataSource {private String driver;private String url;private String username;private String password;public void setDriver(String driver) {this.driver = driver;}public void setUrl(String url) {this.url = url;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "MyDateSource{" +"driver='" + driver + '\'' +", url='" + url + '\'' +", username='" + username + '\'' +", password='" + password + '\'' +'}';}@Overridepublic Connection getConnection() throws SQLException {return null;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}
spring-datasource.xml:使用spring的依赖注入完成数据源对象的创建和属性的赋值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean name="myDataSource" class="com.bjpowernode.spring6.jdbc.MyDateSource"><property name="driver" value="com.mysql.jdbc.driver"/><property name="url" value="jdbc:mysql://localhost:3306/spring6"/><property name="username" value="root"/><property name="password" value="123"/></bean>
</beans>
编写测试
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.bean.User;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class SetDITest {@Testpublic void testMyDataSource(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-datasource.xml");MyDateSource myDataSource = applicationContext.getBean("myDataSource", MyDateSource.class);System.out.println(myDataSource);}}
测试结果:成功注入连接数据库的信息
3.4 级联属性赋值(了解)
我们先回顾一下原来使用的注入方式,然后在使用级联属性赋值,进行对比!
clazz班级类
package com.bjpowernode.spring6.bean;public class Clazz {// 班级名称private String name;public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Clazz{" +"name='" + name + '\'' +'}';}
}
Student学生类
package com.bjpowernode.spring6.bean;public class Student {// 学生姓名private String name;// 班级private Clazz clazz;public void setName(String name) {this.name = name;}public void setClazz(Clazz clazz) {this.clazz = clazz;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", clazz=" + clazz +'}';}
}
第一种:原来的注入方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean name="clazzBean" class="com.bjpowernode.spring6.bean.Clazz"><property name="name" value="高三一班"/></bean><bean name="studentBean" class="com.bjpowernode.spring6.bean.Student"><property name="name" value="张三"/><property name="clazz" ref="clazzBean"/></bean>
</beans>
第二种方式:级联注入方式
使用级联属性赋值需要注意两点:
①配置的顺序不能颠倒,先配置student在配置clazz
②clazz属性必须提供getClazz()方法(所以要在Student类当中要增加getter方法)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean name="studentBean" class="com.bjpowernode.spring6.bean.Student"><property name="name" value="张三"/><property name="clazz" ref="clazzBean"/><!--级联属性赋值--><property name="clazz.name" value="高三一班"/></bean><bean name="clazzBean" class="com.bjpowernode.spring6.bean.Clazz" />
</beans>
执行结果:
3.5 注入数组
这里主要学习两种情况:数组中的元素是简单类型和当数组中的元素是非简单类型!
Woman类,作为非简单类型
package com.bjpowernode.spring6.bean;public class Woman {private String name;@Overridepublic String toString() {return "Woman{" +"name='" + name + '\'' +'}';}public void setName(String name) {this.name = name;}
}
QY类,里面包含简单类型和非简单类型的数组属性
package com.bjpowernode.spring6.bean;import java.util.Arrays;public class QY {// 简单类型的数组private String[] loves;// 非简单类型的数组private Woman[] women;@Overridepublic String toString() {return "QY{" +"loves=" + Arrays.toString(loves) +", women=" + Arrays.toString(women) +'}';}public void setLoves(String[] loves) {this.loves = loves;}public void setWomen(Woman[] women) {this.women = women;}
}
spring-array.xml配置
当属性是数组时,需要先使用一下array标签,在array标签中再写value和ref标签进行赋值!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--准备好非简单类型数据--><bean id="w1" class="com.bjpowernode.spring6.bean.Woman"><property name="name" value="小花"/></bean><bean id="w2" class="com.bjpowernode.spring6.bean.Woman"><property name="name" value="小红"/></bean><!--简单类型--><bean id="yqBean" class="com.bjpowernode.spring6.bean.QY"><!-- 注入简单类型--><property name="loves"><array><value>抽烟</value><value>喝酒</value><value>烫头</value></array></property><!--注入非简单类型--><property name="women" ><array><ref bean="w1"/><ref bean="w2"/></array></property></bean></beans>
编写测试
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.bean.Clazz;
import com.bjpowernode.spring6.bean.QY;
import com.bjpowernode.spring6.bean.Student;
import com.bjpowernode.spring6.bean.User;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class SetDITest {@Testpublic void testArraySet(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");QY yqBean = applicationContext.getBean("yqBean", QY.class);System.out.println(yqBean);}}
执行结果:
要点:
如果数组中是简单类型,使用value标签。
如果数组中是非简单类型,使用ref标签。
3.6 注入List集合和Set集合
Person类
package com.bjpowernode.spring6.bean;import java.util.List;
import java.util.Set;public class Person {// 注入Listprivate List<String> names;// 注入Set集合private Set<String> addrs;@Overridepublic String toString() {return "Person{" +"names=" + names +", addrs=" + addrs +'}';}public void setNames(List<String> names) {this.names = names;}public void setAddrs(Set<String> addrs) {this.addrs = addrs;}
}
spring-collection.xml配置
如果是List集合或者Set集合的属性,需要先使用<list>标签和<set>标签,标签中再写value和ref标签进行赋值!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="personBean" class="com.bjpowernode.spring6.bean.Person"><!--List集合--><property name="names"><list><value>张三</value><value>李四</value><value>张三</value><value>王五</value></list></property><!--Set集合--><property name="addrs"><set><value>张三</value><value>李四</value><value>张三</value><value>王五</value></set></property></bean>
</beans>
编写测试
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.bean.*;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class SetDITest {@Testpublic void testCollectionSet(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");Person personBean = applicationContext.getBean("personBean", Person.class);System.out.println(personBean);}}
执行结果:
从执行结果上看,可以得出:List集合是有序可重复、Set集合是无序不可重复!
注意:注入List集合的时候使用list标签,注入Set集合的时候使用set标签,如果集合中是简单类型使用value标签,反之使用ref标签。
3.7 注入Map和Properties集合
Properties集合本质上也是一个Map集合,但是Properties集合的key和value只能是String类型,并且注入的方式也是与Map集合不同的!
Man类
package com.bjpowernode.spring6.bean;import java.util.Map;
import java.util.Properties;public class Man {// 注入Map集合private Map<String,Integer> phones;// 注入Propertiesprivate Properties properties;@Overridepublic String toString() {return "Man{" +"phones=" + phones +", properties=" + properties +'}';}public void setProperties(Properties properties) {this.properties = properties;}public void setPhones(Map<String, Integer> phones) {this.phones = phones;}
}
spring-collection.xml配置
如果是Map集合的属性,使用map标签嵌套entry子标签(不使用ref和value标签了)
如果是Map集合的属性,使用props标签嵌套pro标签
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="manBean" class="com.bjpowernode.spring6.bean.Man"><!--Map集合--><property name="phones"><map><entry key="张三" value="123"/><entry key="李四" value="456"/><entry key="王五" value="789"/></map></property><!-- Properties集合--><property name="properties"><props><prop key="driver">com.mysql.jdbc.driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring6</prop></props></property></bean></beans>
执行结果:
要点:
对于Map集合使用<map>标签,对于Properties使用<props>标签嵌套<prop>标签完成。
如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。
如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。
3.8 注入null和空字符串
Cat类
package com.bjpowernode.spring6.bean;public class Cat {private String name;private int age;@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +", age=" + age +'}';}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}
}
set-di.xml配置
①注入空字符串使用:<value/> 或者 value=""。
②注入null使用:<null/> 或者 不为该属性赋值。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="carBean" class="com.bjpowernode.spring6.bean.Cat"><!--注入null--><!--第一种方法:不为该属性赋值--><property name="name" value="张三"/><!--第二种方法:使用null标签,手动注入null--><property name="name"><null/></property><property name="age" value="18"/><!-- 注入空字符串--><!--第一种方法--><property name="name" value=""/><!--第二种方法--><property name="name"><value/></property><property name="age" value="20"/></bean></beans>
3.9 注入的值中含有特殊符号
(1)XML中有5个特殊字符,分别是:<、>、'、"、&
(2)以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。
Math类
package com.bjpowernode.spring6.bean;public class Math {private String result;@Overridepublic String toString() {return "Math{" +"result='" + result + '\'' +'}';}public void setResult(String result) {this.result = result;}
}
math.xml配置
解决方案包括两种:
第一种:特殊符号使用转义字符代替。
第二种:将含有特殊符号的字符串放到:<![CDATA[]]> 当中。因为放在CDATA区中的数据不会被XML文件解析器解析。
注:使用<![CDATA[]]>的方式只能使用value标签的形式,不能使用value属性!
注:<![CDATA[]]>是XML的语法,放在这里面的东西不会被XML解析器解析!
5个特殊字符对应的转义字符分别是:
特殊字符 | 转义字符 |
> | > |
< | < |
' | ' |
" | " |
& | & |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="mathBean" class="com.bjpowernode.spring6.bean.Math"><!--直接写2<3会报错--><!-- <property name="result" value="2<3"/>--><!--第一种解决方案:使用实体符号代替特殊符号--><property name="result" value="2 < 3"/><!--第二种解决方案:<![CDATA[]]>--><property name="result"><!--只能使用value标签--><value><![CDATA[2<3]]></value></property></bean>
</beans>
4. p命名空间注入
(1)p命名空间是简化set方法注入的。
(2)使用p命名空间注入的前提条件包括两个:
第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p="http://www.springframework.org/schema/p"
第二:p命名空间注入还是基于set注入的,只不过p命名空间注入可以让spring配置变的更加简单;所以需要对应的属性提供setter方法。
Dog类:提供了setter方法
package com.bjpowernode.spring6.bean;import java.util.Date;public class Dog {private String name;private int age;// 虽然简单类型,但是一般都是当做非简单类型对待private Date date;@Overridepublic String toString() {return "Dog{" +"name='" + name + '\'' +", age=" + age +", date=" + date +'}';}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setDate(Date date) {this.date = date;}
}
spring-p.xml配置
①在spring的配置文件头部添加p命名空间。
②使用:在<bean>标签中的class属性后面直接使用,对于简单类型属性赋值 p:属性名 = "属性值";对于非简单类型属性赋值p:属性名-ref = "属性值"。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--原来注入的方式--><bean id="dogBean" class="com.bjpowernode.spring6.bean.Dog"><property name="name" value="大黄"/><property name="age" value="3"/><property name="date" ref="nowDate"/></bean><!--p命名注入方式--><bean id="dogBean" class="com.bjpowernode.spring6.bean.Dog" p:name="大黄" p:age="3" p:date-ref="nowDate"/><bean id="nowDate" class="java.util.Date"/>
</beans>
测试程序
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.bean.Dog;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class PTest {@Testpublic void testPTest(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");Object dogBean = applicationContext.getBean("dogBean", Dog.class);System.out.println(dogBean);}
}
执行结果:
如果把setter方法注释掉,会报错
5. c命名空间注入
(1)c命名空间是简化构造方法注入的。
(2)使用c命名空间的两个前提条件:
①第一:需要在xml配置文件头部添加信息: xmlns:c="http://www.springframework.org/schema/c"
②第二:需要提供构造方法。
MyTime类:提供了构造方法
package com.bjpowernode.spring6.bean;public class MyTime {private int year;private int month;private int day;public MyTime(int year, int month, int day) {this.year = year;this.month = month;this.day = day;}@Overridepublic String toString() {return "MyTime{" +"year=" + year +", month=" + month +", day=" + day +'}';}
}
spring-c.xml配置
①在spring的配置文件头部添加c命名空间。
②使用:c:_0 下标方式或者c:name 参数名方式。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:c="http://www.springframework.org/schema/c"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--原来注入的方式--><bean id="myTimeBean" class="com.bjpowernode.spring6.bean.MyTime"><constructor-arg index="0" value="2022"/><constructor-arg index="1" value="1"/><constructor-arg index="2" value="14"/></bean><!--c命名注入方式--><bean id="myTimeBean" class="com.bjpowernode.spring6.bean.MyTime" c:_0="2022" c:_1="1" c:_2="14" /></beans>
测试程序
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.bean.MyTime;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class CTest {@Testpublic void testCDI(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");MyTime myTimeBean = applicationContext.getBean("myTimeBean", MyTime.class);System.out.println(myTimeBean);}
}
执行结果:
如果把构造方法注释掉
注意:不管是p命名空间还是c命名空间,注入的时候都可以注入简单类型以及非简单类型。
6. util命名空间
(1)使用util命名空间可以让配置复用。
(2)使用util命名空间的前提是:在spring配置文件头部添加配置信息。如下:
(3)假设系统集成不同厂家的连接池,这里用自己写的数据源来代替;里面的连接数据库的配置实际上是相同的,所以我们就可以使用util命名空间进行配置复用!
数据源MyDataSource1
package com.bjpowernode.spring6.jdbc;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.logging.Logger;public class MyDateSource1 implements DataSource {// 连接数据库的信息,放到成员变量里/*private String driver;private String url;private String username;private String password;*/// 当然也可以放到一个Properties集合当中private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}@Overridepublic String toString() {return "MyDateSource1{" +"properties=" + properties +'}';}@Overridepublic Connection getConnection() throws SQLException {return null;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}
spring-util.xml配置:未使用util命名空间
<?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 id="ds1" class="com.bjpowernode.spring6.jdbc.MyDateSource1"><property name="properties"><props><prop key="dirver">com.mysql.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring6</prop><prop key="username">root</prop><prop key="password">123456</prop></props></property></bean><!--数据源2--><bean id="ds2" class="com.bjpowernode.spring6.jdbc.MyDateSource2"><property name="properties"><props><prop key="dirver">com.mysql.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring6</prop><prop key="username">root</prop><prop key="password">123456</prop></props></property></bean>
</beans>
spring-util.xml配置:使用util命名空间,把公共的配置使用util命名
使用util命名空间后,把重复的配置放到util:properties标签里面,并设置唯一标识id;后面如果想使用,直接使用ref属性直接引入id即可。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:util="http://www.springframework.org/schema/util"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"><!--使用util命名--><util:properties id="prop"><prop key="dirver">com.mysql.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring6</prop><prop key="username">root</prop><prop key="password">123456</prop></util:properties><!--数据源1--><bean id="ds1" class="com.bjpowernode.spring6.jdbc.MyDateSource1"><property name="properties" ref="prop" /></bean><!--数据源2--><bean id="ds2" class="com.bjpowernode.spring6.jdbc.MyDateSource2"><property name="properties" ref="prop"/></bean>
</beans>
测试代码
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.jdbc.MyDateSource1;
import com.bjpowernode.spring6.jdbc.MyDateSource2;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class UtilTest {@Testpublic void testUtilTest(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");MyDateSource1 ds1 = applicationContext.getBean("ds1", MyDateSource1.class);MyDateSource2 ds2 = applicationContext.getBean("ds2", MyDateSource2.class);System.out.println(ds1);System.out.println(ds2);}
}
执行结果:
实际上util命名空间主要是针对集合的:
7. 基于XML的自动装配(byName & byType)
Spring还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字(byName)进行自动装配,也可以根据类型(byType)进行自动装配。
UserDao类
package com.bjpowernode.spring6.dao;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class UserDao {private static final Logger logger = LoggerFactory.getLogger(UserDao.class);public void insert(){logger.info("数据库正在保存用户信息!");}
}
UserDaoService类
package com.bjpowernode.spring6.service;import com.bjpowernode.spring6.dao.UserDao;public class UserService {private UserDao userDao;public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void saveUser(){// 调用UserDao保存用户信息userDao.insert();}
}
7.1 根据名称(byName)自动装配
下面这个配置起到关键作用:
(1)UserService Bean中需要添加autowire="byName",表示通过名称进行装配。
(2)如果是正常的装配,UserDao的id随便写,只要和上面ref的值对应着就行!
(3)如果是自动装配,UserDao的id必须是UserService类中的UserDao属性对应的setUserDao(set方法)方法去掉前面的set,后面首字母变成小写的值:userDao!
(4)所以根据名称自动配置本质上也是set注入!
spring-autowire.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"><!--正常的装配--><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService"><property name="userDao" ref="userDaoBean"/></bean><bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/><!--根据名称自动装配--><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService" autowire="byName"/><bean id="userDao" class="com.bjpowernode.spring6.dao.UserDao"/>
</beans>
编写测试
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class AutowireTest {@Testpublic void testAutowireTest(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);userServiceBean.saveUser();}
}
执行结果:
正常执行,说明如果根据名称装配(byName),底层会调用set方法进行注入!例如:setAge() 对应的名字是age,setPassword()对应的名字是password,setEmail()对应的名字是email。
7.2 根据类型(byType)自动装配
(1)其实无论是根据名称自动装备byName还是根据类型制动装备byType,在装配的时候都是基于set方法的,所以set方法是必须要提供的!
(2)根据byType自动装配时,对于被注入的对象,只需要使用bean标签指定要注入的类型,不需要再指定id。
spring-autowire.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"><!--根据类型自动装备--><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService" autowire="byType"/><bean class="com.bjpowernode.spring6.dao.UserDao"/>
</beans>
执行结果:
如果byType根据类型装配时,如果配置文件中有两个类型一样的bean会出现什么问题呢?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--两个类型一样的bean--><bean id="x" class="com.bjpowernode.spring6.dao.UserDao"/><bean id="y" class="com.bjpowernode.spring6.dao.UserDao"/><bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService" autowire="byType"/>
</beans>
执行结果:
测试结果说明了,当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个!
8. Spring引入外部属性配置文件(使用context命名空间)
我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver、url、username password等信息。这些信息可以单独写到一个属性配置文件中吗?这样用户修改起来会更加的方便,当然是可以的,使用context命名空间!
第一步:写一个数据源类,提供相关属性
package com.bjpowernode.spring6.jdbc;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;public class MyDateSource implements DataSource {private String driver;private String url;private String username;private String password;public void setDriver(String driver) {this.driver = driver;}public void setUrl(String url) {this.url = url;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "MyDateSource{" +"driver='" + driver + '\'' +", url='" + url + '\'' +", username='" + username + '\'' +", password='" + password + '\'' +'}';}@Overridepublic Connection getConnection() throws SQLException {return null;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}
}
第二步:在类路径下新建jdbc.properties文件,并配置信息
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring6
username=root
password=123456
第三步:在spring-properties.xml配置文件中引入context命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"></beans>
第四步:在spring中配置使用jdbc.properties文件
第一步:引入context命名空间,前面已经引过了。
第二步:使用<context:property-placeholder>标签的location属性来指定属性配置文件的路径。 location默认从类的根路径下开始加载资源。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--引入外部的properties文件--><context:property-placeholder location="jdbc.properties"/><bean id="dataSource" class="com.bjpowernode.spring6.jdbc.MyDateSource"><!--使用$元符号,${key}--><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></bean>
</beans>
测试程序:
package com.bjpowernode.spring6.test;import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class JDBCPropertiesTest {@Testpublic void testProperties(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");MyDateSource dataSource = applicationContext.getBean("dataSource", MyDateSource.class);System.out.println(dataSource);}
}
执行结果:
这里username怎么不是我们配置文件里的?spring通过${}加载,默认是是先加载windows系统的环境变量!
怎么解决?一般在所有配置前面加上jdbc前缀
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=123456
执行结果:
相关文章:
【Spring6】| Spring对IoC的实现(核心重点)
目录 一:Spring对IoC的实现 1. IoC 控制反转 2. 依赖注入 2.1 set注入 2.2 构造注入 3. set注入专题 3.1 注入外部Bean 3.2 注入内部Bean 3.3 注入简单类型 3.4 级联属性赋值(了解) 3.5 注入数组 3.6 注入List集合和Set集合 3.7…...
部门来了个测试工程师,听说是00后,实在是太卷了.....
都说00后躺平了,但是有一说一,该卷的还是卷。 这不,前段时间我们部门来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。…...
冲冲冲,力扣javascript刷题——数组总结
力扣javascript刷题——数组总结冲冲冲,力扣刷题——数组总结1.二分查找力扣704题:二分查找35.搜索插入位置34.在排序数组中查找元素的第一个和最后一个位置69.x 的平方根367. 有效的完全平方数2.双指针法27. 移除元素26. 删除有序数组中的重复项283.移动零844. 比较…...
使用kotlin编写html dsl框架
前排提醒,这个框架就是我写着玩的,如果您已经会使用vue或其他前端框架,这篇文章可能对您没有什么意义。即使您不会如上提到的框架,也不要对该框架报有过高的期待,该框架更多的是,我自己的自娱自乐。 这里还…...
【谷粒学院】MybatisPlus(1~17)
1.项目介绍 2.项目背景介绍 3.项目商业模式介绍 4.项目功能模块介绍 5.项目技术点介绍 6.项目技术点-MybatisPlus介绍 官网:http://mp.baomidou.com/ MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做…...
C++的输入输出
目录 一、基本的输入输出 二、I/O库头文件 三、标准输出流(cout) 四、标准输入流(cin) 五、标准错误流(cerr) 六、标准日志流(clog) 一、基本的输入输出 C 标准库提供了一组丰…...
RNN相关知识总结
目录RNN结构与原理1.模型总览2.反向传播LSTM结构与原理1.模型总览2.如何解决RNN梯度消失/爆炸问题?GRU结构及原理1.模型总览LSTM与GRU的区别RNN结构与原理 1.模型总览 上图是RNN的展开结构图,由输入层、隐藏层和输出层组成。当前时间步t 的隐藏状态hth_…...
2. 应用C/C++编写程序
2.1 一个完整的C++源程序 例题是参考书《C++程序设计--基础,编程抽象与算法策略》第一章的PowersOfTwo.cpp。当运行程序PowersOfTow时,计算机要询问指数是多少,即2的多少次方。例如,输入8,程序会产生2的0到8次方的值。 /* File: PowersOfTwo.cpp *程序注释 …...
Spring Boot 统一功能处理(用户登录权限效验-拦截器、异常处理、数据格式返回)
文章目录1. 统一用户登录权限效验1.1 最初用户登录权限效验1.2 Spring AOP 统一用户登录验证1.3 Spring 拦截器1.4 练习:登录拦截器1.5 拦截器实现原理1.6 统一访问前缀添加2. 统一异常处理3. 统一数据格式返回3.1 统一数据格式返回的实现3.2 ControllerAdvice 源码…...
oracle存储过程的使用
文章目录oracle存储过程的使用基本结构管理存储过程调用存储过程的方法存储过程参数关键词: IN 和outin/out测试案例调用in/out测试案例存储过程语法DECLARE声明关键词赋值使用in/out将值作为子程序的参数分配给变量,看上面的案例为布尔变量赋值表达式串…...
一些无线通信系统模型的概念
一些无线通信系统模型的概念 扩频通信,指的是系统的带宽WWW远大于其信息传输速率R(bits/s)R(bits/s)R(bits/s), 定义展频带因子BeWRB_e \frac{W}{R}BeRW, 易知在扩频通信系统中,BeB_eBe远大于1. 在频率上产生如此大的冗余度,主要是为了减轻无线通信或卫星通信中经常产生…...
GAIDC 2023盛会迎来大模型论坛“主场”,百度飞桨护航大模型产业发展
2月25日-26日,2023全球人工智能开发者先锋大会(GAIDC)在上海临港举行,大会以“向光而行的AI开发者”为主题,汇聚了当前科技和产业革命中的开发者先锋力量。百度深度参与本次大会,飞桨联合上海市人工…...
Python编写GUI界面案例:实现免费下载器
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 本次网站: 本文所有模块\环境\源码\教程皆可点击文章下方名片获取此处跳转 开发环境: python 3.8 运行代码 pycharm 2022.3 辅助敲代码 模块使用: import parsel >>> pip install parsel…...
我的 System Verilog 学习记录(6)
引言 本文简单介绍 SystemVerilog 语言的 线程。 前文链接: 我的 System Verilog 学习记录(1) 我的 System Verilog 学习记录(2) 我的 System Verilog 学习记录(3) 我的 System Verilog 学…...
SAP 常见问题大全及问题解决大全
1.A:在公司代码分配折旧表时报错? 在公司代码分配折旧表时报错,提示是“3000 的公司代码分录不完全-参见长文本” 希望各位大侠帮我看看。 3000 的公司代码分录不完全-参见长文本 R: a.你把零进项税的代码分配给这个公司代码就可以了 …...
10.Quartz实现定时打分 热帖排行
1.Spring Quartz(1)简介核心组件scheduler 接口:核心调度工具,所有任务由这一接口调用job:定义任务,重写execute方法JobDetail接口:配置描述Trigger接口:什么时候运行,以什么样的频率运行(2)Spr…...
pandas 读取Excel 批量转换时间戳
一、安装 pip install pandas 如果出报错,不能运行,可以安装 pip install xlrd 二、 代码如下 import pandas as pd import time,datetimefile_path rC:\Users\Administrator\Desktop\携号转网测试\admin_log.xls df pd.read_excel(file_path, sheet_n…...
绕过检测之Executor内存马浅析(内存马系列篇五)
写在前面 前面已经从代码层面讲解了Tomcat的架构,这是内存马系列文章的第五篇,带来的是Tomcat Executor类型的内存马实现。有了前面第四篇中的了解,才能更好的看懂内存马的构造。 前置 什么是Executor Executor是一种可以在Tomcat组件之间…...
《C++模板进阶》
致前行的人: 要努力,但不要着急,繁花锦簇,硕果累累都需要过程! 目录 前言: 1.非类型模板参数 1.1.概念: 1.2.使用注意事项 2.模板特化 2.1函数模板特化 2.2类模板特化 3.模板的分离编译 3.1什么…...
【项目管理】项目进度管理中的逻辑关系
项目的进度管理是项目核心管理之一,通过合理的进度安排,制定出科学可行的分项工期表,并条理清晰的显示出项目进度之间的逻辑关系。 1、目标是计划的灵魂 进度计划必须按照确定的项目总进度要求进行编制,了解项目总目标和整体安…...
ARM的汇编指令集
一、汇编指令 1.1 指令与伪指令 汇编的指令 指令是CPU机器指令的助记符,编译后会得到一串二进制机器码,由CPU执行 汇编的伪指令 伪指令本质上不是指令,它是编译器环境提供用来指导编译过程,编译后伪指令不会生成机器码 伪指令…...
@font-face用法超详细讲解
文章目录font-face是什么font-face基本语法urlTTFOTFEOTWOFFSVGformatfont-face用法示例font字体下载ttf-to-eot 字体转换器https://blog.csdn.net/qq_37417446/article/details/106728725 https://developer.mozilla.org/zh-CN/docs/Web/CSS/font-face font-face是什么 font-…...
[oeasy]python0095_乔布斯求职_雅达利_atari_breakout_打砖块_布什内尔_游戏机_Jobs
编码进化 回忆上次内容 上次 我们回顾了 电子游戏的历史 从 电子游戏鼻祖 双人网球到 视频游戏 PingPong再到 街机游戏 Pong 雅达利 公司 来了 嬉皮士 捣乱?🤔 布什内尔 会如何 应对 呢?🤔 布什内尔 布什内尔 本身就有点 …...
全景极简印度史
转自:印度简史 - 知乎 (zhihu.com)印度是世界上最早出现文明的地区之一,印度河是其文明的发源地。古印度文明的疆域曾包括今印度共和国、巴基斯坦、孟加拉国、阿富汗斯坦南部部分地区和尼泊尔。史前时代200万年前,巴基斯坦北部的希瓦利克遗址…...
《设计模式》模板方法
《设计模式》模板方法 模板方法是一种行为型设计模式,用于定义一个算法的框架,而将一些步骤的实现留给子类来完成。模板方法在基类中定义了一个模板方法,该方法确定了算法的基本结构,然后将一些步骤的实现交给子类去完成。这个模…...
Linux环境内存管理——链表
我是荔园微风,作为一名在IT界整整25年的老兵,今天我们来重新审视一下Windows程序员如何学习Linux环境内存管理。由于很多程序在Windows环境下开发好后,还要部署到Linux服务器上去,所以作为Windows程序员有必要学习Linux环境的内存…...
String、StringBuffer、StringBuilder类
String类 由多个字符组成的一串数据,值一旦创建不可改变 private final char value[]; 一旦值改变,就会创建新的对象 String s "abc"; //char[] c {a,b,c}s"def"; // 并不是String的值改变,而是创建了一个新的对象s"gh";s"aaa"…...
在VScode中添加Linux中的Docker容器中的Python解释器
VScode编辑器在安装好Python插件之后会自动选择环境变量中排序最高的那一个解释器作为默认解释器,而想要额外添加新的Python解释器就需要自己设置。 VScode编辑器安装在本地电脑 支持Python的docker安装在远程服务器 第一步,在/usr/local/下新建pytho…...
无法将“django-admin”项识别为cmdlet,函数,脚本文件或可运行程序的名称问题
无法将“django admin”项识别为cmdlet,函数,脚本文件或可运行程序的名称问题 小提示:首先检查一下有没有拼写错误!!!没有的话请继续 我们要知道django装到哪里去了 pip show django 注意:3.0…...
乐友商城学习笔记(十五)
无状态登陆原理 在服务器端保存session 无状态不需要session,把登陆状态保存在cookie中 jwtrsa token:登陆时, jwt oath2 jwt:头信息(jwt) 载荷(用户信息,签发人,签发时…...
dwcs2018怎么做动态网站/高明公司搜索seo
EG:打印文件结果打印出一片空白 原因:使用了null的数据源而不是JREmptyDataSource 以下为正确代码 public <T> List<JasperPrint> createJasperPrint_1(List<T> list, Map<String, Object> imgMap, Map<String, Object>…...
etc工程承包模式/久久seo正规吗
fluorinefx C# 版的开源rtmp服务器 - [其它资源] 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://25swf.blogbus.com/logs/28529745.html fluorinefx支持的 .net 框架集有 1.1 2.0 3.5 以及 mono 1.2.4支持的东东Flex, Flash Remoting (RP…...
自助建网站/雅思培训机构哪家好机构排名
根据调研机构Gartner公司的预计,2020年全球云存储收入将以每年超过28%的速度增长,将达到650亿美元。其驱动力是为了实现规模经济,使基于云计算的解决方案能够提供比内部部署系统更具成本效益的主存储和备份存储。根据调研机构Gartner公司的预…...
手机怎样制作个人网站/如何弄一个自己的网站
将List类型转化为Json,是我们平常开发时最常见的了。在使用中,有很多种方法,也可以使用。 第一种 第三方组件:Newtonsoft.Json.dll //转化成Json Newtonsoft.Json.JsonConvert.SerializeObject(obj);//反序列化 Newtonsoft.Json.J…...
吉林网站建设/广告策划公司
基础 XML全称ExtensibleMarkup Language(可扩展标记语言);一种用来传输数据的标记语言。 看到这个定义,或许很多想学下去的兴趣就直减一半。看到标记语言,这是什么啊!标记语 言%#%##。?其实简单…...
20种推广方式/厦门seo网站推广
Linux下使用最广泛的C/C编译器是GCC,大多数的Linux发行版本都默认安装,不管是开发人员还是初学者,一般都将GCC作为Linux下首选的编译工具。本教程毫不犹豫地使用GCC来编译C程序。 首先检查系统是否安装GCC 以及make gcc -v make -v运行结果…...