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

Spring笔记之Spring对IoC的实现

文章目录

  • IoC控制反转
  • 依赖注入
    • set注入
      • 注入外部Bean
      • 注入内部Bean
      • 注入简单类型
        • 通过注入方式实现javax.sql.DateSource接口
        • 测试简单类型
      • 级联属性赋值(了解)
      • 注入数组
      • 注入List集合
      • 注入Set集合
      • 注入Map集合
      • 注入Properties
      • 注入null和空字符串
        • 不给属性赋值
        • 使用``
      • 注入的值中含有特殊符号
        • 转义字符
        • CDATE
    • 构造注入
  • p命名空间注入
  • c命名空间注入
  • util命名空间
  • 基于XML的自动装配
    • 根据名称自动装配
    • 根据类型自动装配
  • Spring引入外部属性配置文件

IoC控制反转

  • 控制反转是一种思想
  • 控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。
  • 控制反转,反转的是什么?
  1. 将对象的创建权力交出去,交给第三方容器负责
  2. 将对象和对象之间关系的维护权交出去,交给第三方容器负责
  • 控制反转思想的实现方式:依赖注入(DI)

依赖注入

依赖注入实现了控制反转思想


Spring通过依赖注入的方式来完成Bean管理的
Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)


依赖注入:

  • 依赖指的是对象和对象之间的关联关系。
  • 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

依赖注入常见的实现方式包括两种:

  • 第一种:ser注入
  • 第二种:构造注入

set注入

set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供set方法。

//UserDao
package com.powernode.spring6.dao;public class UserDao {public void insert(){System.out.println("正在保存用户数据。");}
}
//UserService
package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;public class UserService {private UserDao userDao;// 使用set方式注入,必须提供set方法。// 反射机制要调用这个方法给属性赋值的。public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void save(){userDao.insert();}
}
<!-- spring.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="userDaoBean" class="com.powernode.spring6.dao.UserDao"/><bean id="userServiceBean" class="com.powernode.spring6.service.UserService"><property name="userDao" ref="userDaoBean"/></bean></beans>
//test
public class DITest {@Testpublic void testSetDI(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");UserService userService = applicationContext.getBean("userServiceBean", UserService.class);userService.save();}
}

实现原理:
通过property标签获取到属性名:userDao
通过属性名推断出set方法名:setUserDao
通过反射机制调用setUserDao()方法给属性赋值
通过·property标签的name是属性名。
property标签的ref是要注入的bean对象的id(通过ref属性来完成bean的装配,这是bean最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)


底层时机调用了setUserDao()方法,所以需要确保这个方法存在

property标签的name是:setUserDao()方法名演变得到的。
演变规律:

  • setUsername()演变为username
  • setPassword()演变为password
  • setUserDao()演变为userDao
  • setUserService演变为userService

注入外部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 id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/><bean id="userServiceBean" class="com.powernode.spring6.service.UserService"><property name="userDao" ref="userDaoBean"/></bean></beans>

外部Bean的特点:bean定义到外面,在property标签中使用ref属性进行注入。
好像没什么区别

注入内部Bean

内部注入Bean的方式:在Bean标签中嵌套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 id="userServiceBean" class="com.powernode.spring6.service.UserService"><property name="userDao"><bean class="com.powernode.spring6.dao.UserDao"/></property></bean>
</beans>
@Test
public void testInnerBean(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-inner-bean.xml");UserService userService = applicationContext.getBean("userServiceBean", UserService.class);userService.save();
}

了解了解,用的不多

注入简单类型

我们在注入的时候,对象的属性是另一个对象,但是并没有涉及简单类型

package com.powernode.spring6.beans;public class User {private int age;public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"age=" + age +'}';}
}
<?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.powernode.spring6.beans.User"><!--如果像这种int类型的属性,我们称为简单类型,这种简单类型在注入的时候要使用value属性,不能使用ref--><!--<property name="age" value="20"/>--><property name="age"><value>20</value></property></bean>
</beans>
//test
@Test
public void testSimpleType(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-simple-type.xml");User user = applicationContext.getBean("userBean", User.class);System.out.println(user);
}

给简单类型注入,只要用value标签或者value属性给它赋上值就行了
注意不是ref,ref译为参考,后面加的是个类名,参考这个类,就是它最后生成的样子就是这个类,参考这个类注入。


简单类型包括:

  • 基本数据类型
  • 基本数据类型对应的包装类
  • String或其他的CharSequence子类
  • Number子类
  • Date子类(这玩意不好用,格式很复杂,正常人记不住)
  • Enum子类
  • URI
  • URL
  • Temporal子类
  • Local
  • Class
  • 另外还包括以上简单类型对应的数组类型。

通过注入方式实现javax.sql.DateSource接口

//MyDataSource.java
package com.powernode.spring6.beans;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 MyDataSource 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 "MyDataSource{" +"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 -->
<?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="dataSource" class="com.powernode.spring6.beans.MyDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/spring"/><property name="username" value="root"/><property name="password" value="123456"/></bean>
</beans>
//test
@Test
public void testDataSource(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-datasource.xml");MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);System.out.println(dataSource);
}

测试简单类型

//类A
package com.powernode.spring6.beans;import java.net.URI;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;public class A {private byte b;private short s;private int i;private long l;private float f;private double d;private boolean flag;private char c;private Byte b1;private Short s1;private Integer i1;private Long l1;private Float f1;private Double d1;private Boolean flag1;private Character c1;private String str;private Date date;private Season season;private URI uri;private URL url;private LocalDate localDate;private Locale locale;private Class clazz;// 生成setter方法// 生成toString方法
}enum Season {SPRING, SUMMER, AUTUMN, WINTER
}
<!-- spring-all-simple-type.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="a" class="com.powernode.spring6.beans.A"><property name="b" value="1"/><property name="s" value="1"/><property name="i" value="1"/><property name="l" value="1"/><property name="f" value="1"/><property name="d" value="1"/><property name="flag" value="false"/><property name="c" value="a"/><property name="b1" value="2"/><property name="s1" value="2"/><property name="i1" value="2"/><property name="l1" value="2"/><property name="f1" value="2"/><property name="d1" value="2"/><property name="flag1" value="true"/><property name="c1" value="a"/><property name="str" value="zhangsan"/><!--注意:value后面的日期字符串格式不能随便写,必须是Date对象toString()方法执行的结果。--><!--如果想使用其他格式的日期字符串,就需要进行特殊处理了。具体怎么处理,可以看后面的课程!!!!--><property name="date" value="Fri Sep 30 15:26:38 CST 2022"/><property name="season" value="WINTER"/><property name="uri" value="/save.do"/><!--spring6之后,会自动检查url是否有效,如果无效会报错。--><property name="url" value="http://www.baidu.com"/><property name="localDate" value="EPOCH"/><!--java.util.Locale 主要在软件的本地化时使用。它本身没有什么功能,更多的是作为一个参数辅助其他方法完成输出的本地化。--><property name="locale" value="CHINESE"/><property name="clazz" value="java.lang.String"/></bean>
</beans>
//test
@Test
public void testAllSimpleType(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-all-simple-type.xml");A a = applicationContext.getBean("a", A.class);System.out.println(a);
}

需要注意的是:
如果把Date当作简单类型的话,日期字符串格式不能随便写(随便写的话,会报错这是个字符串类型,不是date类型)。格式必须符合Date的toString方法格式(长这个臭样”Fri Sep 30 15:26:38 CST 2022“)。如果我们提供一个这样的日期字符串:2010-10-10,在这里无法赋值给Date类型的属性的。
spring6之后,当注入的是URL,那么这个url字符串是会进行有效性检测的。如果是一个存在的url,那就没问题。如果不存在就会报错

级联属性赋值(了解)

这个名字让我想起了mybatis里的级联赋值(帮助完成一对多,多对一映射的关联)

直接看一下如何在spring配置bean文件里的代码,我的评价是不如constructor-arg标签好用

<?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="clazzBean" class="com.powernode.spring6.beans.Clazz"/><bean id="student" class="com.powernode.spring6.beans.Student"><property name="name" value="张三"/><!--要点1:以下两行配置的顺序不能颠倒--><property name="clazz" ref="clazzBean"/><!--要点2:clazz属性必须有getter方法--><property name="clazz.name" value="高三一班"/></bean>
</beans>

这种方式注意:

  • 在spring配置文件中注意顺序
  • 在spring配置文件中,clazz属性必须提供getter方法。

注入数组

当数组的元素是简单类型:

//Person.java
package com.powernode.spring6.beans;import java.util.Arrays;public class Person {private String[] favariteFoods;public void setFavariteFoods(String[] favariteFoods) {this.favariteFoods = favariteFoods;}@Overridepublic String toString() {return "Person{" +"favariteFoods=" + Arrays.toString(favariteFoods) +'}';}
}
<!-- spring-array-simple.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="person" class="com.powernode.spring6.beans.Person"><property name="favariteFoods"><array><value>鸡排</value><value>汉堡</value><value>鹅肝</value></array></property></bean>
</beans>
//test
@Test
public void testArraySimple(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array-simple.xml");Person person = applicationContext.getBean("person", Person.class);System.out.println(person);
}

当注入的元素是非简单类型:(一个订单中包含多个商品)

//Goods.java
package com.powernode.spring6.beans;public class Goods {private String name;public Goods() {}public Goods(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Goods{" +"name='" + name + '\'' +'}';}
}
//Order.java
package com.powernode.spring6.beans;import java.util.Arrays;public class Order {// 一个订单中有多个商品private Goods[] goods;public Order() {}public Order(Goods[] goods) {this.goods = goods;}public void setGoods(Goods[] goods) {this.goods = goods;}@Overridepublic String toString() {return "Order{" +"goods=" + Arrays.toString(goods) +'}';}
}
<!-- spring-array.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="goods1" class="com.powernode.spring6.beans.Goods"><property name="name" value="西瓜"/></bean><bean id="goods2" class="com.powernode.spring6.beans.Goods"><property name="name" value="苹果"/></bean><bean id="order" class="com.powernode.spring6.beans.Order"><property name="goods"><array><!--这里使用ref标签即可--><ref bean="goods1"/><ref bean="goods2"/></array></property></bean></beans>
//test
@Test
public void testArray(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");Order order = applicationContext.getBean("order", Order.class);System.out.println(order);
}

要点:

  • 如果数组中的简单类型,使用value标签直接赋值。
  • 如果数组是非简单类型,使用ref标签赋值。

注入List集合

List集合的特性:有序可重复

package com.powernode.spring6.beans;import java.util.List;public class People {// 一个人有多个名字private List<String> names;public void setNames(List<String> names) {this.names = names;}@Overridepublic String toString() {return "People{" +"names=" + names +'}';}
}
<?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="peopleBean" class="com.powernode.spring6.beans.People"><property name="names"><list><value>张三</value><value>李四</value><value>王五</value><value>赵六</value><value>钱七</value><value>勾八</value><value>勾八</value><value>勾八</value></list></property></bean>
</beans>
//test
@Test
public void testCollection(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");People peopleBean = applicationContext.getBean("peopleBean", People.class);System.out.println(peopleBean);
}

注意:
注入List集合的时候使用list标签,如果List集合中是简单类型使用value标签;反之使用ref标签

注入Set集合

Set集合的特性:无序,不可重复

//People.java
package com.powernode.spring6.beans;import java.util.List;
import java.util.Set;public class People {// 一个人有多个电话private Set<String> phones;public void setPhones(Set<String> phones) {this.phones = phones;}//......@Overridepublic String toString() {return "People{" +"phones=" + phones +", names=" + names +'}';}
}
<?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="peopleBean" class="com.powernode.spring6.beans.People"><property name="phones"><set><!--非简单类型可以使用ref,简单类型使用value--><value>110</value><value>110</value><value>120</value><value>120</value><value>119</value><value>119</value></set></property></bean>
</beans>

注意:
使用<set>标签
set集合中元素是简单类型的使用value标签;反之使用ref标签

注入Map集合

//People.java
package com.powernode.spring6.beans;import java.util.List;
import java.util.Map;
import java.util.Set;public class People {// 一个人有多个住址private Map<Integer, String> addrs;public void setAddrs(Map<Integer, String> addrs) {this.addrs = addrs;}//......@Overridepublic String toString() {return "People{" +"addrs=" + addrs +", phones=" + phones +", names=" + names +'}';}}
<!-- spring-coolection.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="peopleBean" class="com.powernode.spring6.beans.People"><property name="addrs"><map><!--如果key不是简单类型,使用 key-ref 属性--><!--如果value不是简单类型,使用 value-ref 属性--><entry key="1" value="北京大兴区"/><entry key="2" value="上海浦东区"/><entry key="3" value="深圳宝安区"/></map></property></bean>
</beans>

要点:
使用<map>标签
如果key是简单类型,使用key属性;反之使用key-ref属性
如果value是简单类型,使用value属性,反之使用value-ref属性

注入Properties

java.util.Properties继承java.uril.Hashtable,所以Properties也是一个Map集合。

//People.java
package com.powernode.spring6.beans;import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;public class People {private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}//......@Overridepublic String toString() {return "People{" +"properties=" + properties +", addrs=" + addrs +", phones=" + phones +", names=" + names +'}';}
}
<!-- spring-collection.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="peopleBean" class="com.powernode.spring6.beans.People"><property name="properties"><props><prop key="driver">com.mysql.cj.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring</prop><prop key="username">root</prop><prop key="password">123456</prop></props></property></bean>
</beans>

要点:
使用<props>标签嵌套<prop>标签完成。

注入null和空字符串

  • 注入空字符串使用:<value/>或者value=""
  • 注入null使用:<null>或者不为该属性赋值
//Vip.java
package com.powernode.spring6.beans;public class Vip {private String email;public void setEmail(String email) {this.email = email;}@Overridepublic String toString() {return "Vip{" +"email='" + email + '\'' +'}';}
}
<!-- spring-null,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="vipBean" class="com.powernode.spring6.beans.Vip"><!--空串的第一种方式--><!--<property name="email" value=""/>--><!--空串的第二种方式--><property name="email"><value/></property></bean>
</beans>
//test
@Test
public void testNull(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-null.xml");Vip vipBean = applicationContext.getBean("vipBean", Vip.class);System.out.println(vipBean);
}

如何注入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="vipBean" class="com.powernode.spring6.beans.Vip" /></beans>

使用<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="vipBean" class="com.powernode.spring6.beans.Vip"><property name="email"><null/></property></bean></beans>

注入的值中含有特殊符号

XML中有5个特殊字符,分别是<>'"&

以上五个特殊符号在XML中会被特殊对待,会被当作XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错


解决方案包括两种

  • 第一种:特殊符号使用转义字符代替
  • 第二种:将含有特殊符号的字符串放到:<![CDATE[]]>当中。因为放在CDATE区中的数据不会被XML文件解析器解析。

转义字符

//Math.java
package com.powernode.spring6.beans;public class Math {private String result;public void setResult(String result) {this.result = result;}@Overridepublic String toString() {return "Math{" +"result='" + result + '\'' +'}';}
}
<!-- spring-special.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="mathBean" class="com.powernode.spring6.beans.Math"><property name="result" value="2 &lt; 3"/></bean>
</beans>
//test
@Test
public void testSpecial(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-special.xml");Math mathBean = applicationContext.getBean("mathBean", Math.class);System.out.println(mathBean);
}

CDATE

<?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.powernode.spring6.beans.Math"><property name="result"><!--只能使用value标签--><value><![CDATA[2 < 3]]></value></property></bean></beans>

注意:
使用CDATE时,不能使用value属性,只能使用value标签

构造注入

核心原理:通过调用构造方法来给属性赋值。

//OrderDao.java
package com.powernode.spring6.dao;public class OrderDao {public void deleteById(){System.out.println("正在删除订单。。。");}
}
//OrderService.java
package com.powernode.spring6.service;import com.powernode.spring6.dao.OrderDao;public class OrderService {private OrderDao orderDao;// 通过反射机制调用构造方法给属性赋值public OrderService(OrderDao orderDao) {this.orderDao = orderDao;}public void delete(){orderDao.deleteById();}
}
<!-- spring.xml -->
<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"/>
<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService"><!--index="0"表示构造方法的第一个参数,将orderDaoBean对象传递给构造方法的第一个参数。--><constructor-arg index="0" ref="orderDaoBean"/>
</bean>
//test
@Test
public void testConstructorDI(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");OrderService orderServiceBean = applicationContext.getBean("orderServiceBean", OrderService.class);orderServiceBean.delete();
}

如果构造参数有两个,那就需要将两个参数都加入到bean中,利用constructor-arg子标签将构造的参数补齐

  • index属性名:补齐参数对应位置,用0,1方式对应参数的位置
  • name属性名:补齐参数对应位置,用对应上构造参数值的名字赋值进去
  • 空:也可以不指定参数的位置,利用spring强大的功能让他自己对应进去,位置可以不对应
  • ref属性名:指向要映射成的类

p命名空间注入

目的:简化配置。
使用p命名空间注入的前提条件包括两个:

  • 第一:在XML头部信息中添加p命名空间的配置信息:
    xmlns:p="http://www.springframework.org/schema/p"
  • 第二:p命名空间注入是基于setter方法的,所以需要对应的属性提供setter方法。
//Customer.java
package com.powernode.spring6.beans;public class Customer {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 "Customer{" +"name='" + name + '\'' +", age=" + age +'}';}
}
<!-- spring-p.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"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="customerBean" class="com.powernode.spring6.beans.Customer" p:name="zhangsan" p:age="20"/></beans>
//test
@Test
public void testP(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");Customer customerBean = applicationContext.getBean("customerBean", Customer.class);System.out.println(customerBean);
}

p命名空间实际上是对set注入的简化

c命名空间注入

c命名空间是简化构造方法注入的
使用c命名空间的两个前提条件:

  • 第一:需要在xml配置信息文件头部添加信息:
    xmlns:c="http://www.springframework.org/schema/c"
  • 第二:需要提供构造方法
//MyTime.java
package com.powernode.spring6.beans;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 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:c="http://www.springframework.org/schema/c"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="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:year="1970" c:month="1" c:day="1"/>--><bean id="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:_0="2008" c:_1="8" c:_2="8"/></beans>
//test
@Test
public void testC(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");MyTime myTimeBean = applicationContext.getBean("myTimeBean", MyTime.class);System.out.println(myTimeBean);
}

不管是p命名空间还是c命名空间,注入的时候都可以注入简单类型以及非简单类型

util命名空间

使用util命名空间可以让配置复用
使用util命名空间的前提是:在spring配置头文件添加配置信息

//MyDataSource1.java
package com.powernode.spring6.beans;import java.util.Properties;public class MyDataSource1 {private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}@Overridepublic String toString() {return "MyDataSource1{" +"properties=" + properties +'}';}
}
//MyDataSource2.java
package com.powernode.spring6.beans;import java.util.Properties;public class MyDataSource2 {private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}@Overridepublic String toString() {return "MyDataSource2{" +"properties=" + properties +'}';}
}
<!-- spring-util.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"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:properties id="prop"><prop key="driver">com.mysql.cj.jdbc.Driver</prop><prop key="url">jdbc:mysql://localhost:3306/spring</prop><prop key="username">root</prop><prop key="password">123456</prop></util:properties><bean id="dataSource1" class="com.powernode.spring6.beans.MyDataSource1"><property name="properties" ref="prop"/></bean><bean id="dataSource2" class="com.powernode.spring6.beans.MyDataSource2"><property name="properties" ref="prop"/></bean>
</beans>
//test
@Test
public void testUtil(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");MyDataSource1 dataSource1 = applicationContext.getBean("dataSource1", MyDataSource1.class);System.out.println(dataSource1);MyDataSource2 dataSource2 = applicationContext.getBean("dataSource2", MyDataSource2.class);System.out.println(dataSource2);
}

基于XML的自动装配

Spring还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字进行自动装配,也可以根据类型进行自动装配。

根据名称自动装配

//UserDao.java
package com.powernode.spring6.dao;public class UserDao {public void insert(){System.out.println("正在保存用户数据。");}
}
package com.powernode.spring6.service;import com.powernode.spring6.dao.UserDao;public class UserService {private UserDao aaa;// 这个set方法非常关键public void setAaa(UserDao aaa) {this.aaa = aaa;}public void save(){aaa.insert();}
}
<!-- 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="userService" class="com.powernode.spring6.service.UserService" autowire="byName"/><bean id="aaa" class="com.powernode.spring6.dao.UserDao"/></beans>

这个配置起到关键作用:

  • UserService Bean中需要添加autowire=“byName”,表示通过名称进行装配。
  • UserService类中有一个UserDao属性,而UserDao属性的名字是aaa,对应的set方法是setAaa(),正好和UserDao Bean的id1是一样的。这就是根据名称自动装配。
//test
@Test
public void testAutowireByName(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");UserService userService = applicationContext.getBean("userService", UserService.class);userService.save();
}

如果根据名称装配(byName),底层会调用set方法进行注入。
例如:setAge()对应的名字是age,setPassword()对应的名字是password,setEmail()对应的名字是email。

根据类型自动装配

//AccountDao.java
package com.powernode.spring6.dao;public class AccountDao {public void insert(){System.out.println("正在保存账户信息");}
}
//AccountService.java
package com.powernode.spring6.service;import com.powernode.spring6.dao.AccountDao;/*** @author 动力节点* @version 1.0* @className AccountService* @since 1.0**/
public class AccountService {private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}public void save(){accountDao.insert();}
}
<!-- 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"><!--byType表示根据类型自动装配--><bean id="accountService" class="com.powernode.spring6.service.AccountService" autowire="byType"/><bean class="com.powernode.spring6.dao.AccountDao"/></beans>
@Test
public void testAutowireByType(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");AccountService accountService = applicationContext.getBean("accountService", AccountService.class);accountService.save();
}

无论是byName还是byType,在装配的时候都是基于set方法的。所以set方法是必须要提供的。提供构造方法是不行的。
当byType进行自动装配的时候,配置文件中,某种类型的Bean必须是唯一的,不能出现多个。

Spring引入外部属性配置文件

mybatis可以将配置文件的信息单独写到一个文件中,Spring也可以

  1. 第一步:写一个数据源类,提供相关属性
package com.powernode.spring6.beans;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 MyDataSource implements DataSource {@Overridepublic String toString() {return "MyDataSource{" +"driver='" + driver + '\'' +", url='" + url + '\'' +", username='" + username + '\'' +", password='" + password + '\'' +'}';}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;}//......
}
  1. 第二步:在类路径下新创建jdbc.propertirs文件,并配置信息
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库名
username=账号
password=密码
  1. 在spring配置文件中引入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>
  1. 在spring中配置使用jdbc.properties文件
<?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"><context:property-placeholder location="jdbc.properties"/><bean id="dataSource" class="com.powernode.spring6.beans.MyDataSource"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></bean>
</beans>
//test
@Test
public void testProperties(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);System.out.println(dataSource);
}

注意一个事情,就是properties文件中的username在注入的时候会先查询windows本地的,所以在调试的时候会发现username注入的值不是我们提供的值,而是本地的一个值
建议properties文件加个前缀jdbc啥的

相关文章:

Spring笔记之Spring对IoC的实现

文章目录 IoC控制反转依赖注入set注入注入外部Bean注入内部Bean注入简单类型通过注入方式实现javax.sql.DateSource接口测试简单类型 级联属性赋值&#xff08;了解&#xff09;注入数组注入List集合注入Set集合注入Map集合注入Properties注入null和空字符串不给属性赋值使用 注…...

【eNSP】Telnet远程登录

Telnet远程登录 eNSP软件TelnetTelnet远程登录-路由连接关闭防火墙eNSP根据图1画图路线配置路由端口IP配置路由R1改名配置接口IP 配置路由R2 配置R2的远程登录设置登录用户授权级别退出登录超时时间 Telnet测试 eNSP软件 eNSP(Enterprise Network Simulation Platform)是一款由…...

SOP/详解*和**/python数据结构(iter,list,tuple,dict)/ 解包

一、错误解决合集 1. > combined_seq.named_children() 2. isinstance 2th parameter : must be a type or tuple of types > 改为tuple&#xff0c;不要用列表。改为 LLLayer (nn.Conv2d,nn.Linear) 3. File “test.py”, line 90, in calculate_fin_fout print(“hi”…...

使用webdriver-manager解决浏览器与驱动不匹配所带来自动化无法执行的问题

1、前言 在我们使用 Selenium 进行 UI 自动化测试时&#xff0c;常常会因为浏览器驱动与浏览器版本不匹配&#xff0c;而导致自动化测试无法执行&#xff0c;需要手动去下载对应的驱动版本&#xff0c;并替换原有的驱动&#xff0c;可能还会遇到跨操作系统进行测试的时候&…...

【vue】Vue中debugger报错 unexpected ‘debugger’ statement no-debugger

前言&#xff1a; Vue中debugger报错 unexpected ‘debugger’ statement no-debugger &#xff08;意外的“调试器”语句没有调试器&#xff09; eslink规则没有开启’debugger’ &#xff0c;被规则屏蔽了&#xff0c;需要手动放开 解决方法 方式一&#xff1a; 找到.esl…...

课题方向a

首先在无线感知的研究方向下,辅以深度学习和计算机视觉的技术和知识,可以从事哪些具体课题的研究?请你尽可能多的给出课题名称供我选择 在无线感知的研究方向下,辅以深度学习和计算机视觉的技术,有很多具体课题可以进行研究。以下是一些供您选择的课题名称: 基于深度学习…...

【Matter】基于Ubuntu 22.04 交叉编译chip-tool

编译工程之际&#xff0c;记录一下编译过程&#xff0c;免得后续遗忘&#xff0c;总结下来chip-tool 交叉编译涉及到的知识点&#xff1a; 需要了解如何支持交叉编译&#xff0c;基于GN编译框架需要理解应用库如何交叉编译&#xff0c;理解pkg-config的使用meson 编译&#xf…...

Qt/C++音视频开发50-不同ffmpeg版本之间的差异处理

一、前言 ffmpeg的版本众多&#xff0c;从2010年开始计算的项目的话&#xff0c;基本上还在使用的有ffmpeg2/3/4/5/6&#xff0c;最近几年版本彪的比较厉害&#xff0c;直接4/5/6&#xff0c;大版本之间接口有一些变化&#xff0c;特别是一些废弃接口被彻底删除了&#xff0c;…...

低碳 Web 实践指南

现状和问题 2023年7月6日&#xff0c;世界迎来有记录以来最热的一天。气候变化是如今人类面临的最大健康威胁。据世界卫生组织预测2030年至2050年期间&#xff0c;气候变化预计每年将造成约25万人死亡。这是人们可以真切感受到的变化&#xff0c;而背后的主要推手是碳排放。 …...

信息安全:网络安全体系 与 网络安全模型.

信息安全&#xff1a;网络安全体系 与 网络安全模型. 网络安全保障是一项复杂的系统工程&#xff0c;是安全策略、多种技术、管理方法和人员安全素质的综合。一般而言&#xff0c;网络安全体系是网络安全保障系统的最高层概念抽象&#xff0c;是由各种网络安全单元按照一定的规…...

【云原生】Serverless 技术架构分析

一、什么是Serverless? 1、Serverless技术简介 ​ Serverless&#xff08;无服务器架构&#xff09;指的是由开发者实现的服务端逻辑运行在无状态的计算容器中&#xff0c;它由事件触发&#xff0c; 完全被第三方管理&#xff0c;其业务层面的状态则被开发者使用的数据库和存…...

Visual Studio Code 设置文件头部添加作者、日期和函数注释

step1:安装插件KoroFileHeader step2:左下角选择管理—设置—输入"fileheader"—点击"在setting.json中编辑" step3:添加下面的代码到json文件中 // 文件头部注释 "fileheader.customMade": {"Descripttion":"","ve…...

HCIA云计算 V5.0题库

云计算&#xff0c;这是近几年听得最多词了&#xff0c;云计算对于网络的发展帮助非常大&#xff0c;它自身所产生的价值是不可估量的&#xff01;所以云计算的岗位对于很多IT公司来说&#xff0c;都是有一定地位的。华为认证云计算面向的对象很简单就是对云计算技术感兴趣的人…...

基于Matlab实现帧间差分法的运动目标检测(附上完整源码+图像+程序运行说明)

帧间差分法是一种常用的运动目标检测方法&#xff0c;可以通过对连续帧之间的差异进行分析来确定目标的运动情况。在本文中&#xff0c;我们将介绍如何使用Matlab实现帧间差分法的运动目标检测。 文章目录 部分源码完整源码图像程序运行说明下载 部分源码 首先&#xff0c;我们…...

Jenkins搭建最简教程

纠结了一小会儿&#xff0c;到底要不要写这个&#xff0c;最终还是决定简单记录一下&#xff0c;因为Jenkins搭建实在是太简单了&#xff0c;虽然也有坑&#xff0c;但是坑主要在找稳定的版本上。 先学一个简称&#xff0c;LTS (Long Term Support) 属实是长见识了&#xff0c…...

设置git可以同时推送gitee和github

查看当前的远程仓库设置&#xff1a; git remote -v 这会列出你当前配置的远程仓库。你可能会看到类似以下的输出&#xff1a;origin-gitee <gitee仓库地址> (fetch)origin-gitee <gitee仓库地址> (push) 新增一个远程仓库 git remote add origin-github <githu…...

Java给Excel设置单元格格式

maven 依赖 <!--读取excel文件--> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version> </dependency> <dependency><groupId>org.apache.poi</group…...

__block的深入研究

__block可以用于解决block内部无法修改auto变量值的问题 __block不能修饰全局变量、静态变量&#xff08;static&#xff09; 编译器会将__block变量包装成一个对象 调用的是&#xff0c;从__Block_byref_a_0的指针找到 a所在的内存&#xff0c;然后修改值 第一层拷贝&…...

Segment anything(图片分割大模型)

目录 1.Segment anything 2.补充图像分割和目标检测的区别 1.Segment anything 定义&#xff1a;图像分割通用大模型 延深&#xff1a;可以预计视觉检测大模型&#xff0c;也快了。 进一步理解&#xff1a;传统图像分割对于下图处理时&#xff0c;识别房子的是识别房子的模型…...

【雕爷学编程】MicroPython动手做(27)——物联网之掌控板小程序3

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

数据结构:递归的种类(Types of Recursion)

目录 尾递归&#xff08;Tail Recursion&#xff09; 什么是 Loop&#xff08;循环&#xff09;&#xff1f; 复杂度分析 头递归&#xff08;Head Recursion&#xff09; 树形递归&#xff08;Tree Recursion&#xff09; 线性递归&#xff08;Linear Recursion&#xff09;…...