Table of contents
One: Spring's implementation of IoC
3.4 Cascade attribute assignment (understand)
3.6 Inject List collection and Set collection
3.7 Inject Map and Properties collections
3.8 Injecting null and empty strings
3.9 The injected value contains special symbols
7. XML-based autowiring (byName & byType)
7.1 Automatic assembly according to name (byName)
7.2 Automatic assembly according to type (byType)
8. Spring introduces external attribute configuration files (using the context namespace)
One: Spring's implementation of IoC
We have learned how to create management objects with spring, and then we need to learn how to create relationships between objects and use dependency injection!
1. IoC Inversion of Control
(1) Inversion of control is an idea, a new design pattern!
(2) The purpose of inversion of control is to reduce the degree of program coupling, improve program scalability, achieve the OCP principle, and achieve the DIP principle.
(3) Inversion of control, what is the inversion?
① Hand over the creation right of the object to the third-party container.
② The right to maintain the relationship between objects and objects is handed over to the third-party container.
(4) How to implement the idea of inversion of control ?
DI (Dependency Injection): dependency injection
2. Dependency Injection
Dependency injection implements the idea of inversion of control!
Spring completes Bean management through dependency injection. Bean management refers to: the creation of Bean objects, and the assignment of attributes in Bean objects (or the maintenance of relationships between Bean objects).
Dependency injection:
- Dependency refers to the relationship between objects and objects.
- Injection refers to a data transfer behavior, through the injection behavior to make objects and objects have a relationship.
There are two common implementations of dependency injection:
- The first type: set injection
- The second type: construct injection
2.1 set injection
Set injection is implemented based on the set method. The bottom layer will call the set method corresponding to the attribute through the reflection mechanism and then assign a value to the attribute; this method requires the attribute to provide a set method to the outside world !
pom.xml configuration
<?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 log configuration
<?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 class: the operation of connecting to the database
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 class: call the method in UserDao
①For set injection, a set method must be provided; the Spring container will call this set method to assign a value to the userDao attribute.
②This set method does not conform to the javabean specification, but it must start with set, for example: setUD is also possible; here I am using the javabean specification automatically generated by IDEA.
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 configuration
① Configure userDaoBean and UserService to let spring manage these two classes.
② For UserService, if you want Spring to call the corresponding set method, you need to configure the property tag :
name attribute value: the method name of the set method, remove the set, and then lowercase the first letter of the remaining word
ref attribute value: translated as a reference, the English word references, followed by the id of the bean to be injected
<?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>
③In addition, for the property tag, the ref attribute can also use the label method , but the use of the ref attribute is the majority:
<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
<property name="userDao">
<ref bean="userDaoBean"/>
</property>
</bean>
write test class
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class DITest {
@Test
public void testSetDI(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);
userServiceBean.saveUser();
}
}
Results of the:
The log information is output normally, indicating two problems:
① spring creates UserDao and UserService objects normally!
②spring associates the relationship between objects and objects!
Summary: The core implementation principle of set injection is to assign values to attributes by calling the set method through the reflection mechanism, so that a relationship can be created between two objects.
2.2 Construct injection
Core principle: Assign values to properties by calling constructors .
①set injection: the object is created first before the set method can be executed to assign values to the properties.
②Constructive injection: it is to assign values to attributes while creating objects, and the timing is different.
When defining a VipDao class
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类
Constructor injection must provide a constructor!
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 configuration
There are three ways to access: using the constructor-arg tag
① The first method is based on the subscript index method, and the order of the subscripts is the order of the parameters of the construction method.
②The second method is based on the name of the constructor parameter name .
③The third way is to inject according to the type, if not specified, spring will infer the type matching by itself .
<?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>
write tests
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.service.ConstructService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ConstructTest {
@Test
public void testConstructDI(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
ConstructService constructServiceBean = applicationContext.getBean("constructServiceBean", ConstructService.class);
constructServiceBean.save();
}
}
Results of the:
3. Set injection topic
In set injection and construction injection, set injection is used more, so let's learn about the topic of set injection!
3.1 Injecting external beans
(1) The case we used before has always been the way of injecting external beans!
(2) Features of external beans : The bean is defined outside, and injected using the ref attribute in the property tag ; usually this method is commonly used!
<?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 Injecting internal beans
The way of internal beans : directly nest bean tags in bean tags, and do not need to introduce ref attributes .
<?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 Injecting Simple Types
(1) When injecting before, the properties of the object are all other objects; what if the properties of the object are of type int? You can also assign a value to the attribute through set injection. In fact, as long as you can call the set method, you can assign a value to the attribute .
(2) Key point: If you assign a value to a simple type , you cannot use the ref attribute, you need to use the value attribute !
User class: two simple types are defined, and the set method is written
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
set-di.xm configuration
Note: You can use either the value tag or the value attribute (commonly used)
<?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>
write tests
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SetDITest {
@Test
public void testSimpleTypeSet(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
User user = applicationContext.getBean("userBean", User.class);
System.out.println(user);
}
}
Execution result: the toString method will be called by default
Special attention needs to be paid: if assigning a value to a simple type, use the value attribute or value tag instead of ref!
(3) So what are the simple types? You can analyze it through Spring's source code!
Double-click shift to search for the BeanUtils class , and ctrl+F12 to search for the isSimpleValueType method, which contains simple types:
(4) Here we focus on the Date type. If you insist on treating the Date type as a simple type and using value assignment, the format of this date has requirements: Thu Jan 12 21:05:49 CST 2023 , so in actual development, We generally use the ref attribute to assign values to Date type attributes!
(5) A classic case of simple type injection: inject values into the properties of the data source:
Suppose we now want to write a data source by ourselves (that can provide Connection objects), we all know that all data sources must implement the javax.sql.DataSource interface, and the data source should have information about connecting to the database, such as: driver, url , username, password, etc.
Data source 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;
}
@Override
public String toString() {
return "MyDateSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
spring-datasource.xml: Use spring's dependency injection to complete the creation of data source objects and the assignment of attributes
<?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>
write tests
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 {
@Test
public void testMyDataSource(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-datasource.xml");
MyDateSource myDataSource = applicationContext.getBean("myDataSource", MyDateSource.class);
System.out.println(myDataSource);
}
}
Test result: Successfully injected information to connect to the database
3.4 Cascade attribute assignment (understand)
Let's first review the original injection method, and then use cascading attribute assignment for comparison!
clazz class class
package com.bjpowernode.spring6.bean;
public class Clazz {
// 班级名称
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Clazz{" +
"name='" + name + '\'' +
'}';
}
}
Student class
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", clazz=" + clazz +
'}';
}
}
The first method: the original injection method
<?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>
The second method: cascading injection method
There are two points to note when using cascading property assignments:
①The order of configuration cannot be reversed, first configure student and then configure clazz
② The clazz attribute must provide the getClazz() method (so the getter method must be added to the Student class)
<?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>
Results of the:
3.5 Injecting arrays
There are two main situations to learn here: when the elements in the array are simple types and when the elements in the array are non- simple types !
class Woman, as a non-simple type
package com.bjpowernode.spring6.bean;
public class Woman {
private String name;
@Override
public String toString() {
return "Woman{" +
"name='" + name + '\'' +
'}';
}
public void setName(String name) {
this.name = name;
}
}
QY class, which contains array properties of simple types and non-simple types
package com.bjpowernode.spring6.bean;
import java.util.Arrays;
public class QY {
// 简单类型的数组
private String[] loves;
// 非简单类型的数组
private Woman[] women;
@Override
public 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 configuration
When the attribute is an array, you need to use the array tag first, and then write the value and ref tags in the array tag for assignment!
<?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>
write tests
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 {
@Test
public void testArraySet(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");
QY yqBean = applicationContext.getBean("yqBean", QY.class);
System.out.println(yqBean);
}
}
Results of the:
Main points:
If the array is a simple type, use the value tag.
If there are non-simple types in the array, use the ref tag.
3.6 Inject List collection and Set collection
Person class
package com.bjpowernode.spring6.bean;
import java.util.List;
import java.util.Set;
public class Person {
// 注入List
private List<String> names;
// 注入Set集合
private Set<String> addrs;
@Override
public 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 configuration
If it is an attribute of a List collection or a Set collection, you need to use the <list> tag and <set> tag first, and then write the value and ref tags in the tags for assignment!
<?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>
write tests
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 {
@Test
public void testCollectionSet(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);
}
}
Results of the:
From the execution results, it can be concluded that the List collection is ordered and repeatable, and the Set collection is disordered and non-repeatable!
Note: Use the list tag when injecting the List collection, use the set tag when injecting the Set collection, use the value tag if the collection is a simple type, and use the ref tag otherwise.
3.7 Inject Map and Properties collections
The Properties collection is essentially a Map collection, but the key and value of the Properties collection can only be of String type, and the injection method is also different from the Map collection!
man class
package com.bjpowernode.spring6.bean;
import java.util.Map;
import java.util.Properties;
public class Man {
// 注入Map集合
private Map<String,Integer> phones;
// 注入Properties
private Properties properties;
@Override
public 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 configuration
If it is an attribute of the Map collection, use the map tag to nest the entry sub-tag (the ref and value tags are not used anymore)
If it is a property of the Map collection, use the props tag to nest the pro tag
<?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>
Results of the:
Main points:
Use the <map> tag for the Map collection, and use the <props> tag to nest the <prop> tag for Properties.
If the key is a simple type, use the key attribute, otherwise use the key-ref attribute.
If the value is a simple type, use the value attribute, otherwise use the value-ref attribute.
3.8 Injecting null and empty strings
Cat class
package com.bjpowernode.spring6.bean;
public class Cat {
private String name;
private int age;
@Override
public 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 configuration
①Inject an empty string using: <value/> or value="".
② Inject null and use: <null/> or do not assign a value to the property.
<?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 The injected value contains special symbols
(1) There are 5 special characters in XML, namely: <, >, ', ", &
(2) The above five special symbols will be treated specially in XML, and will be parsed as part of the XML grammar. If these special symbols appear directly in the injected string, an error will be reported.
Math class
package com.bjpowernode.spring6.bean;
public class Math {
private String result;
@Override
public String toString() {
return "Math{" +
"result='" + result + '\'' +
'}';
}
public void setResult(String result) {
this.result = result;
}
}
math.xml configuration
There are two solutions:
The first one: special symbols are replaced by escape characters.
The second method: Put the string containing special symbols into: <![CDATA[]]> . Because the data placed in the CDATA area will not be parsed by the XML file parser.
Note: The method of using <![CDATA[]]> can only use the form of value tag, and cannot use the value attribute!
Note: <![CDATA[]]> is the syntax of XML, and the things placed here will not be parsed by the XML parser!
The escape characters corresponding to the five special characters are:
Special characters |
escape character |
> |
> |
< |
< |
' |
' |
" |
" |
& |
& |
<?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 namespace injection
(1) The p namespace is injected by simplifying the set method.
(2) The prerequisites for using p namespace injection include two:
First: Add the configuration information of the p namespace in the XML header information : xmlns:p=" http://www.springframework.org/schema/p"
Second: p namespace injection is still based on set injection , but p namespace injection can make spring configuration easier; so the corresponding attributes need to provide setter methods .
Dog class: Provides a setter method
package com.bjpowernode.spring6.bean;
import java.util.Date;
public class Dog {
private String name;
private int age;
// 虽然简单类型,但是一般都是当做非简单类型对待
private Date date;
@Override
public 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 configuration
① Add the p namespace to the head of the spring configuration file.
② Use: Use directly behind the class attribute in the <bean> tag, for simple type attribute assignment p: attribute name = "attribute value" ; for non-simple type attribute assignment p: attribute name-ref = "attribute 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"
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>
test program
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.Dog;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PTest {
@Test
public void testPTest(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");
Object dogBean = applicationContext.getBean("dogBean", Dog.class);
System.out.println(dogBean);
}
}
Results of the:
If you comment out the setter method, an error will be reported
5. C namespace injection
(1) The c namespace is injected by the simplified constructor.
(2) Two prerequisites for using the c namespace:
① First: You need to add information to the header of the xml configuration file: xmlns:c=" http://www.springframework.org/schema/c"
②Second : A construction method needs to be provided.
MyTime class: Provides a constructor
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;
}
@Override
public String toString() {
return "MyTime{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}
spring-c.xml configuration
①Add the c namespace to the head of the spring configuration file.
② Use: c:_0 subscript method or c:name parameter name method.
<?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>
test program
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.bean.MyTime;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CTest {
@Test
public void testCDI(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");
MyTime myTimeBean = applicationContext.getBean("myTimeBean", MyTime.class);
System.out.println(myTimeBean);
}
}
Results of the:
If you comment out the constructor
Note: Regardless of the p namespace or the c namespace, simple types and non-simple types can be injected during injection.
6. util namespace
(1) Using the util namespace allows configuration reuse .
(2) The prerequisite for using the util namespace is to add configuration information to the header of the spring configuration file. as follows:
(3) Assuming that the system integrates connection pools from different manufacturers, here we use the data source written by ourselves instead; the configuration of the connection database inside is actually the same, so we can use the util namespace for configuration reuse!
Data source 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;
}
@Override
public String toString() {
return "MyDateSource1{" +
"properties=" + properties +
'}';
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
spring-util.xml configuration: util namespace not used
<?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 configuration: use the util namespace, and use util to name the public configuration
After using the util namespace, put the repeated configuration in the util:properties tag, and set a unique identifier id; if you want to use it later, just use the ref attribute to directly import the 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 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>
test code
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 {
@Test
public 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);
}
}
Results of the:
In fact, the util namespace is mainly for collections:
7. XML-based autowiring (byName & byType)
Spring can also complete automatic injection , which is also called automatic assembly. It can be autowired by name (byName) or by type (byType) .
UserDao class
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 class
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 Automatic assembly according to name (byName)
The following configuration plays a key role:
(1) Autowire="byName" needs to be added to the UserService Bean, indicating that it is assembled by name .
(2) If it is a normal assembly, the id of UserDao can be written casually, as long as it corresponds to the value of the above ref!
(3) If it is an automatic assembly, the id of UserDao must be the setUserDao (set method) method corresponding to the UserDao attribute in the UserService class to remove the previous set, and the value after the first letter becomes lowercase: userDao!
(4) So automatic configuration based on name is essentially set injection!
spring-autowire.xml configuration
<?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>
write tests
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AutowireTest {
@Test
public void testAutowireTest(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);
userServiceBean.saveUser();
}
}
Results of the:
Normal execution means that if it is assembled according to the name (byName), the bottom layer will call the set method for injection! For example: setAge() corresponds to age, setPassword() corresponds to password, and setEmail() corresponds to email.
7.2 Automatic assembly according to type (byType)
(1) In fact , whether it is automatically equipped byName according to the name or braked byType according to the type, it is based on the set method when assembling , so the set method must be provided!
(2) When auto-assembling according to byType, for the injected object, you only need to use the bean tag to specify the type to be injected, and you don't need to specify the id.
spring-autowire.xml configuration
<?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>
Results of the:
If byType is assembled according to type, what will happen if there are two beans of the same type in the configuration file?
<?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>
Results of the:
The test results show that when byType performs automatic assembly, a certain type of Bean in the configuration file must be unique, and there cannot be more than one!
8. Spring introduces external attribute configuration files (using the context namespace)
We all know that when writing a data source, information about connecting to the database is needed, such as: driver, url, username password and other information. Can this information be written separately into a properties configuration file? In this way, it will be more convenient for users to modify it. Of course, it is possible to use the context namespace!
Step 1: Write a data source class and provide relevant properties
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;
}
@Override
public String toString() {
return "MyDateSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
@Override
public Connection getConnection() throws SQLException {
return null;
}
@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}
@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
}
@Override
public int getLoginTimeout() throws SQLException {
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}
}
Step 2: Create a new jdbc.properties file under the classpath and configure the information
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring6
username=root
password=123456
Step 3: Introduce the context namespace in the spring-properties.xml configuration file
<?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">
</beans>
Step 4: Configure and use the jdbc.properties file in spring
The first step: introduce the context namespace, which has been cited before.
Step 2: Use the location attribute of the <context:property-placeholder> tag to specify the path of the property configuration file. location loads resources from the root path of the class by default .
<?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">
<!--引入外部的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>
test program:
package com.bjpowernode.spring6.test;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class JDBCPropertiesTest {
@Test
public void testProperties(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");
MyDateSource dataSource = applicationContext.getBean("dataSource", MyDateSource.class);
System.out.println(dataSource);
}
}
Results of the:
Why is username not in our configuration file here? Spring is loaded through ${}, and the default is to load the environment variables of the windows system first!
How to deal with it? Generally add the jdbc prefix in front of all configurations
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=123456
Results of the: