一、控制反转
1.控制反转是一种思想。
2.控制反转的目的:降低程序的耦合度,从而提高程序的扩展力,达到OCP原则和DIP原则。
3.什么是控制反转?
(1)将创建对象这一任务交给容器去完成;
(2)对象和对象之间的关系交给容器去管理。
4.真正实现控制反转这个思想的技术是依赖注入DI
(Dependence Injection )
二、依赖注入
1.依赖注入实现了控制反转的思想。
2.Spring通过依赖注入的方式来完成Bean的管理
管理指:Bean对象的创建,以及Bean对象之间的关系的维护。
3.依赖注入:
(1)依赖指的是对象和对象之间的关联关系。
(2)注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。
4.依赖注入的常见两种方式:
(1)set注入
(2)构造注入
三、set 注入
(1)set注入是基于set方法实现的
因为反射机制要调用这个方法给属性赋值。
<?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.dao.UserDao"/>
<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
<property name="userDao" ref="userDaoBean"/>
</bean>
</beans>
*通过property标签获取属性名:userDao
*通过属性名推断出set方法:setUserDao
*通过反射机制调用setUserDao( )方法给属性赋值
*在property标签里,name是属性名,ref注入对象的id,将对象之间关联起来
(2)注入外部Bean(如上)
特点:在property标签中使用ref属性进行注入
(3)注入内部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.service.UserService">
<property name="userDao">
<bean class="com.dao.UserDao"/>
</property>
</bean>
</beans>
(4)注入简单类型
<?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">
<!--如果像这种int类型的属性,我们称为简单类型,简单类型在注入的时候要使用value属性或者value标签,不能使用ref-->
<!--value标签赋值-->
<bean id="userBean1" class="com.beans.User">
<property name="age">
<value>20</value>
</property>
</bean>
<!--value属性-->
<bean id="userBean2" class="com.beans.User">
<property name="age" value="22"></property>
</bean>
</beans>
简单类型包括:
*基本简单类型
*基本简单类型对应的包装类
*String或其他的CharSequence子类
*Number子类
*Date子类
*Enum子类
*URL
*URI
*Temporal子类
*Locale
Class
*还包括以上简单类型对应的数组类型
测试如下:
package com.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;
//String类
private String str;
//日期类
private Date date;
//枚举类
private Season season;
//URI
private URI uri;
//URL
private URL url;
//时区
private LocalDate localDate;
private Locale locale;
//Class类
private Class clazz;
// 生成setter方法,略
// 生成toString方法,略
}
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
<?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.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>
(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="banjiBean" class="com.beans.banji"/>
<bean id="student" class="com.beans.Student">
<property name="name" value="张三"/>
<!--要点1:以下两行配置的顺序不能颠倒-->
<property name="banji" ref="banjiBean"/>
<!--要点2:banji对象的name属性须有getter方法-->
<property name="banji.name" value="高一二班"/>
</bean>
</beans>
(6)注入数组
property标签里面是array标签
如果L数组集合中的值是简单类型使用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="person" class="com.beans.Goods">
<property name="favariteFoods">
<array>
<value>鸡排</value>
<value>汉堡</value>
<value>鹅肝</value>
</array>
</property>
</bean>
</beans>
数组中的元素是非简单类型:
<?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.beans.Goods">
<property name="name" value="鸡排"/>
</bean>
<bean id="goods2" class="com.beans.Goods">
<property name="name" value="汉堡"/>
</bean>
<bean id="goods3" class="com.beans.Goods">
<property name="name" value="鹅肝"/>
</bean>
<bean id="order" class="com.beans.Order">
<property name="goods">
<array>
<!--这里使用ref标签即可-->
<ref bean="goods1"/>
<ref bean="goods2"/>
<ref bean="goods3"/>
</array>
</property>
</bean>
</beans>
(7)注入List集合
*roperty标签里是list标签
*如果List集合中的值是简单类型使用value标签,反之用ref标签
*List集合:有序可重复
People.java
package com.beans;
import java.util.List;
public class People {
// 一个人有多个名字
private List<String> names;
public void setNames(List<String> names) {
this.names = names;
}
@Override
public String toString() {
return "People{" +
"names=" + names +
'}';
}
}
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="peopleBean" class="com.beans.People">
<property name="names">
<list>
<value>铁锤</value>
<value>张三</value>
<value>张三</value>
<value>张三</value>
<value>李四</value>
</list>
</property>
</bean>
</beans>
输出结果为:铁锤、张三、张三、张三、李四
(8)注入Set集合
*poperty标签里使用set标签
*如果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="peopleBean" class="com.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>
输出结果为:110、120、119
(9)注入Map集合
*property标签里使用map标签
*如果key是简单类型使用key属性,反之用key-ref属性
*如果value是简单类型使用value属性,反之用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="peopleBean" class="com.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>
(10)注入Properties标签
*java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合
*property标签里面使用props标签,props标签里嵌套prop标签
*
package com.beans;
import java.util.Properties;
public class People {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "People{" +
"properties=" + 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="peopleBean" class="com.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>
(11)注入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="UserBean1" class="com.beans.User">
<property name="email">
<null/>
</property>
</bean>
<!--方式二-->
<bean id = "UserBean2" class = "com.beans.User">
<property name = "email"></propery>
</bean>
</beans>
(12)注入的值含有特殊符号
*在XML中有5个特殊的字符,分别是:< 、> 、’ 、" 、&
*以上字符会被当做XML语法的一部分进行解析,直接出现在注入的字符串中,会报错。
*解决方法:使用转义字符代替、将含有特殊符号的字符串放到<![CDATA[]]>中。
*5个特殊符号对应的转义字符是:
特殊字符 | 转义字符 |
---|---|
> | >; |
< | <; |
’ | &apos; |
" | "; |
& | &; |
<?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.beans.Math">
<property name="result" value="2 < 3"/>
</bean>
</beans>
使用CDATA方式:
<?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.beans.Math">
<property name="result">
<!--只能使用value标签,不能使用value属性-->
<value><![CDATA[2 < 3]]></value>
</property>
</bean>
</beans>
四、构造注入
*核心要点:通过构造方法给属性赋值
*通过构造方法注入时:
可以通过下标,
也可以通过参数、
也可以不指定下标和参数
<bean id="orderDaoBean" class="com.dao.OrderDao"/>
<!--使用参数下标-->
<bean id="orderServiceBean1" class="com.service.OrderService">
<!--index="0"表示构造方法的第一个参数,将orderDaoBean对象传递给构造方法的第一个参数。-->
<constructor-arg index="0" ref="orderDaoBean"/>
</bean>
<!--使用参数名-->
<bean id = "orderServiceBean2" class = "com.service.orderService">
<constructor-arg name = "orderDao" ref = "orderDaoBean"/>
</bean>
<!--不使用下标,也不使用参数名-->
<bean id = "orderService3" class = "com.service.orderService">
<constructor-arg ref = "orderDaoBean">
</bean>
五、p命名空间注入
使用p命名空间注入的前提条件:
(1)在XML头部信息中添加p命名空间的配置信息:
xmlns:p=“http://www.springframework.org/schema/p”
(2)p命名空间注入是基于setter方法的,所以对应的属性提供setter方法。
<?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.beans.Customer" p:name="zhangsan" p:age="20"/>
</beans>
六、c命名空间注入
使用c命名空间的两个前提条件:
(1)在XML头部信息中添加c命名空间的配置信息:
xmlns:p=“http://www.springframework.org/schema/c”
(2)c命名空间注入基于构造方法,所以要提供构造方法。
<?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="myTimeBean1" class="com.beans.MyTime" c:year="1970" c:month="1" c:day="1"/>
<!--使用参数下标-->
<bean id="myTimeBean2" class="com.beans.MyTime" c:_0="2008" c:_1="8" c:_2="8"/>
</beans>
七、使用util命名空间
使用util命名空间可以让配置复用
使用util的前提,在spring配置文件头部添加如下配置信息:
xmlns:util=“http://www.springframework.org/schema/util”
xsi:“http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd”
<?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 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.beans.MyDataSource1">
<property name="properties" ref="prop"/>
</bean>
<bean id="dataSource2" class="com.MyDataSource2">
<property name="properties" ref="prop"/>
</bean>
</beans>
八、基于XML的自动装配
(1)根据名称自动装配
<?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">
<!--在userService中添加autowire="byName",表示通过名称进行装配-->
<bean id="userService" class="com.service.UserService" autowire="byName"/>
<!--在userService类中有一个UserDao属性,这个属性对应的名字为aaa,对应的set方法为setAaa(),在-->
<bean id="aaa" class="com.powernode.spring6.dao.UserDao"/>
</beans>
(2)根据类型自动装配
<?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="accountService" class="com.service.AccountService" autowire="byType"/>
<bean id="x" class="com.dao.AccountDao"/>
</beans>
*无论是byName还是byType,都是基于set方法装配的,因此必须要提供set方法.
*在使用byType类型装配时,配置文件中某种类型的Bean是唯一的.
九、Spring 引入外部属性配置文件
以一个完整的程序为例:
(1) 第一步:写一个数据源类,提供相关属性
package com.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;
/**
* @author 动力节点
* @version 1.0
* @className MyDataSource
* @since 1.0
**/
public class MyDataSource implements DataSource {
@Override
public 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;
}
//......
}
(2) 第二步:在类路径下新建jdbc.properties文件,并配置信息。
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring
username=root
password=root123
(3) 第三步:在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.xsd
http://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.beans.MyDataSource">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
</beans>
(4) 测试:
@Test
public void testProperties(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");
MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);
System.out.println(dataSource);
}