Spring6 -(05)Spring 对 IoC 的实现
1. IoC 控制反转
1.控制反转是一种思想。
2.控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。
3.控制反转,反转的是什么?
-
将对象的创建权利交出去,交给第三方容器负责。
-
将对象和对象之间关系的维护权交出去,交给第三方容器负责。
4.控制反转这种思想如何实现呢?
- DI(Dependency Injection):依赖注入
2. 依赖注入
依赖注入是控制反转的思想的实现。
Spring通过依赖注入的方式来完成Bean管理的。
Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。
依赖注入:
- 依赖指的是对象和对象之间的关联关系。
- 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。
依赖注入常见的实现方式包括两种:
- 第一种:set注入
- 第二种:构造注入
2.1 set注入
set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供set方法。
第一步:创建UserDao
package com.julissa.spring6.dao;
public class UserDao {
/**
* 添加用户
*
*/
public void insert(){
System.out.println("-------数据库正在保存用户信息-------");
}
}
第二步:创建UserService
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
public class UserService {
//要注入的对象
private UserDao userDao;
// 使用set方式注入,必须提供set方法。
// 反射机制要调用这个方法给属性赋值的。
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
userDao.insert();
}
}
第三步:配置beans.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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService -->
<bean id="UserServiceBean" class="com.julissa.spring6.service.UserService">
<!-- 想让Spring调用对应的set方法,需要配置property标签 -->
<!-- name属性指定值:set方法的方法名去掉set,然后把剩下的单词首字母变小写-->
<!-- ref 翻译为引用,ref后面指定的是要注入的bean的id-->
<property name="userDao" ref="userDaoBean"/>
</bean>
</beans>
第四步:编写测试程序
package com.julissa.spring.test;
import com.julissa.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUserService {
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = applicationContext.getBean("UserServiceBean", UserService.class);
userService.add();
}
}
第五步:运行测试程序
分析
<?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.julissa.spring6.dao.UserDao"/>
<bean id="UserServiceBean" class="com.julissa.spring6.service.UserService">
<property name="userDao" ref="userDaoBean"/>
</bean>
</beans>
实现原理:
第一步:通过property标签获取到属性名:userDao
第二步:通过属性名推断出set方法名:setUserDao
第三步:通过反射机制调用setUserDao()方法给属性赋值
property标签的name是set方法去掉set后首字母小写后的字符组合。
property标签的ref是要注入的bean对象的id。(通过ref属性来完成bean的装配,这是bean最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)
可以把set方法注释掉,再测试一下:
通过测试得知,底层实际上调用了setUserDao()方法。所以需要确保这个方法的存在。
我们现在把属性名修改一下,但方法名还是setUserDao(),我们来测试一下:
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
public class UserService {
private UserDao peiqi;
// 使用set方式注入,必须提供set方法。
// 反射机制要调用这个方法给属性赋值的。
public void setUserDao(UserDao userDao) {
this.peiqi = userDao;
}
public void add(){
peiqi.insert();
}
}
运行测试程序:
通过测试看到程序仍然可以正常执行,说明property标签的name是:setUserDao()方法名演变得到的。演变的规律是:
- setUserDao() 演变为 userDao
- setUserService() 演变为 userService
另外,对于property标签来说,ref属性也可以采用标签的方式,但使用ref属性是多数的:
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<property name="userDao">
<ref bean="userDaoBean"/>
</property>
</bean>
总结:set注入的核心实现原理:通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系。
2.2 构造器注入
核心原理:通过调用构造方法来给属性赋值。
第一步:创建UserDao
package com.julissa.spring6.dao;
public class UserDao {
/**
* 添加用户
*
*/
public void insert(){
System.out.println("-------数据库正在保存用户信息-------");
}
}
第二步:创建UserService
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
public class UserService {
private UserDao userDao;
// 通过反射机制调用构造方法给属性赋值
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
userDao.insert();
}
}
第三部:配置beans.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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<!--index="0"表示构造方法的第一个参数,将userDaoBean对象传递给构造方法的第一个参数。-->
<constructor-arg index="0" ref="userDaoBean"/>
</bean>
</beans>
第四步:编写测试程序
package com.julissa.spring.test;
import com.julissa.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUserService {
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = applicationContext.getBean("userServiceBean", UserService.class);
userService.add();
}
}
第五步:运行测试程序
如果构造方法有两个参数
第一步:再创建一个VipDao
package com.julissa.spring6.dao;
public class VipDao {
/**
* 添加vip用户
*
*/
public void insert(){
System.out.println("-------数据库正在保存VIP信息-------");
}
}
第二步:修改UserService
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
import com.julissa.spring6.dao.VipDao;
public class UserService {
private UserDao userDao;
private VipDao vipDao;
// 通过反射机制调用构造方法给属性赋值
public UserService(UserDao userDao, VipDao vipDao) {
this.userDao = userDao;
this.vipDao = vipDao;
}
public void add(){
userDao.insert();
vipDao.insert();
}
}
第三步:配置beans.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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置VipDao -->
<bean id="vipDaoBean" class="com.julissa.spring6.dao.VipDao"/>
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<!--index="0"表示构造方法的第一个参数,将userDaoBean对象传递给构造方法的第一个参数。-->
<constructor-arg index="0" ref="userDaoBean"/>
<!--index="1"表示构造方法的第二个参数,将vipDaoBean对象传递给构造方法的第一个参数。-->
<constructor-arg index="1" ref="vipDaoBean"/>
</bean>
</beans>
第四步:运行测试程序
不使用参数下标,使用参数的名字可以吗?
第一步:修改beans.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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置VipDao -->
<bean id="vipDaoBean" class="com.julissa.spring6.dao.VipDao"/>
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<!-- 使用了构造方法上参数的名字 -->
<constructor-arg name="userDao" ref="userDaoBean"/>
<constructor-arg name="vipDao" ref="vipDaoBean"/>
</bean>
</beans>
第二步:运行测试程序
不指定参数下标,不指定参数名字,可以吗?
第一步:修改beans.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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置VipDao -->
<bean id="vipDaoBean" class="com.julissa.spring6.dao.VipDao"/>
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<!--没有指定下标,也没有指定参数名字-->
<constructor-arg ref="userDaoBean"/>
<constructor-arg ref="vipDaoBean"/>
</bean>
</beans>
第二步:运行测试程序
配置文件中构造方法参数的类型顺序和构造方法参数的类型顺序不一致呢?
第一步:修改beans.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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置VipDao -->
<bean id="vipDaoBean" class="com.julissa.spring6.dao.VipDao"/>
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<!--顺序已经和构造方法的参数顺序不同了-->
<constructor-arg ref="vipDaoBean"/>
<constructor-arg ref="userDaoBean"/>
</bean>
</beans>
第二步:运行测试程序
总结:
通过测试得知,通过构造方法注入的时候:
- 可以通过下标
- 可以通过参数名
- 也可以不指定下标和参数名,可以类型自动推断。
3. set注入专题
3.1 注入外部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">
<!-- 配置UserDao -->
<bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<property name="userDao" ref="userDaoBean"/>
</bean>
</beans>
外部Bean的特点:bean定义到外面,在property标签中使用ref属性进行注入。通常这种方式是常用。
3.2 注入内部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">
<!-- 配置UserDao -->
<!-- <bean id="userDaoBean" class="com.julissa.spring6.dao.UserDao"/>-->
<!-- 配置UserService -->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService">
<property name="userDao">
<bean class="com.julissa.spring6.dao.UserDao"/>
</property>
</bean>
</beans>
内部Bean的方式:在bean标签中嵌套bean标签。
3.3 注入简单类型
之前在进行注入的时候,对象的属性是另一个对象
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
import com.julissa.spring6.dao.VipDao;
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
userDao.insert();
}
}
那如果对象的属性是int类型呢?
package com.julissa.spring6.bean;
public class User {
private int age;
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
}
以通过set注入的方式给该属性赋值吗?
- 当然可以。因为只要能够调用set方法就可以给属性赋值。
编写程序给一个User对象的age属性赋值20:
第一步:创建User类
package com.julissa.spring6.bean;
/**
* bean类 封装用户信息
*/
public class User {
private int age;
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<bean id="userBean" class="com.julissa.spring6.bean.User">
!--如果像这种int类型的属性,我们称为简单类型,这种简单类型在注入的时候要使用value属性,不能使用ref-->
<property name="age" value="20"/>
</bean>
</beans>
第三步:编写测试程序
package com.julissa.spring6.test;
import com.julissa.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
}
第四步:运行测试程序
需要特别注意:如果给简单类型赋值,使用value属性或value标签。而不是ref。
简单类型包括哪些呢?可以通过Spring的源码来分析一下:BeanUtils类
public class BeanUtils{
//.......
/**
* Check if the given type represents a "simple" property: a simple value
* type or an array of simple value types.
* <p>See {@link #isSimpleValueType(Class)} for the definition of <em>simple
* value type</em>.
* <p>Used to determine properties to check for a "simple" dependency-check.
* @param type the type to check
* @return whether the given type represents a "simple" property
* @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE
* @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies
* @see #isSimpleValueType(Class)
*/
public static boolean isSimpleProperty(Class<?> type) {
Assert.notNull(type, "'type' must not be null");
return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}
/**
* Check if the given type represents a "simple" value type: a primitive or
* primitive wrapper, an enum, a String or other CharSequence, a Number, a
* Date, a Temporal, a URI, a URL, a Locale, or a Class.
* <p>{@code Void} and {@code void} are not considered simple value types.
* @param type the type to check
* @return whether the given type represents a "simple" value type
* @see #isSimpleProperty(Class)
*/
public static boolean isSimpleValueType(Class<?> type) {
return (Void.class != type && void.class != type &&
(ClassUtils.isPrimitiveOrWrapper(type) ||
Enum.class.isAssignableFrom(type) ||
CharSequence.class.isAssignableFrom(type) ||
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
Locale.class == type ||
Class.class == type));
}
//........
}
通过源码分析得知,简单类型包括:
- 基本数据类型
- 基本数据类型对应的包装类
- String或其他的CharSequence子类
- Number子类
- Date子类
- Enum子类
- URI
- URL
- Temporal子类
- Locale
- Class
- 另外还包括以上简单值类型对应的数组类型。
编写一个程序,把所有的简单类型全部测试一遍:
第一步:创建Simple类
package com.julissa.spring6.bean;
import java.net.URI;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;
public class Simple {
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;
//set方法
//toString方法
}
enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
第二步:配置beans.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">
<!-- 配置Simple-->
<bean id="simpleBean" class="com.julissa.spring6.bean.Simple">
<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()方法执行的结果。-->
<!--在实际开发中,我们一般不会把Date当作简单类型,虽然它是简单类型,一般会采用ref给Date属性赋值-->
<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>
第三步:编写测试程序
package com.julissa.spring6.test;
import com.julissa.spring6.bean.Simple;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSimple {
@Test
public void testAllSimpleType(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Simple simple = applicationContext.getBean("simpleBean", Simple.class);
System.out.println(simple);
}
}
第四步:运行测试程序
需要注意的是:
- 如果把Date当做简单类型的话,日期字符串格式不能随便写。格式必须符合Date的toString()方法格式。显然这就比较鸡肋了。如果我们提供一个这样的日期字符串:2010-10-11,在这里是无法赋值给Date类型的属性的。
- spring6之后,当注入的是URL,那么这个url字符串是会进行有效性检测的。如果是一个存在的url,那就没问题。如果不存在则报错。
经典案例:给数据源的属性注入值:
假设我们现在要自己手写一个数据源,我们都知道所有的数据源都要实现javax.sql.DataSource接口,并且数据源中应该有连接数据库的信息,例如:driver、url、username、password等。
第一步:创建MyDataSource类
package com.julissa.spring6.bean;
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;
@Override
public String toString() {
return "MyDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + 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 Connection getConnection() throws SQLException {
//获取数据库连接需要四个信息
//driver、url、username、password
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;
}
}
我们给driver、url、username、password四个属性分别提供了setter方法,我们可以使用spring的依赖注入完成数据源对象的创建和属性的赋值
第二步:配置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.julissa.spring6.bean.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
public void testDataSource(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-datasource.xml");
MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);
System.out.println(dataSource);
}
第四步:运行测试程序
3.4 级联属性赋值
第一步:创建clazz类
package com.julissa.spring6.bean;
public class Clazz {
private String className;
public void setClassName(String className) {
this.className = className;
}
@Override
public String toString() {
return "Clazz{" +
"className='" + className + '\'' +
'}';
}
}
第二步:创建Student类
package com.julissa.spring6.bean;
public class Student {
private String name;
private Clazz clazz;// 学生属于哪个班
public String getName() {
return name;
}
public Clazz getClazz() {
return 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 +
'}';
}
}
第三步:配置beans.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">
<!-- 配置Clazz-->
<bean id="clazzBean" class="com.julissa.spring6.bean.Clazz"/>
<!-- 配置Student -->
<bean id="studentBean" class="com.julissa.spring6.bean.Student">
<property name="name" value="julissa"/>
<!--要点1:以下两行配置的顺序不能颠倒-->
<property name="clazz" ref="clazzBean"/>
<!--要点2:clazz属性必须有getter方法-->
<property name="clazz.className" value="Java0001班"/>
</bean>
</beans>
第四步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Student studentBean = applicationContext.getBean("studentBean", Student.class);
System.out.println(studentBean);
}
第五步:运行测试程序
要点:
- 在spring配置文件中,如上,注意顺序。
- 在spring配置文件中,clazz属性必须提供getter方法。
3.5 注入数组
当数组中的元素是简单类型:
第一步:创建User类
package com.julissa.spring6.bean;
import java.util.Arrays;
/**
* bean类 封装用户信息
*/
public class User {
private String[] hobbies;
public void setHobbies(String[] hobbies) {
this.hobbies = hobbies;
}
@Override
public String toString() {
return "User{" +
"hobbies=" + Arrays.toString(hobbies) +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<bean id="userBean" class="com.julissa.spring6.bean.User">
<property name="hobbies">
<!-- 注入数据用array标签 -->
<array>
<!-- 注入简单类型用value -->
<value>吃饭</value>
<value>睡觉</value>
<value>打豆豆</value>
</array>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
第四步:运行测试程序
当数组中的元素是非简单类型:一个订单中包含多个商品。
第一步:创建Order类
package com.julissa.spring6.bean;
import java.util.Arrays;
public class Order {
private Goods[] goods;
public void setGoods(Goods[] goods) {
this.goods = goods;
}
@Override
public String toString() {
return "Order{" +
"goods=" + Arrays.toString(goods) +
'}';
}
}
第二步:创建Goods类
package com.julissa.spring6.bean;
public class Goods {
private String goodsName;
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
'}';
}
}
第三步:配置beans.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">
<!-- 配置Goods-->
<bean id="goodsBean01" class="com.julissa.spring6.bean.Goods">
<property name="goodsName" value="手机"/>
</bean>
<bean id="goodsBean02" class="com.julissa.spring6.bean.Goods">
<property name="goodsName" value="耳机"/>
</bean>
<!-- 配置Order-->
<bean id="orderBean" class="com.julissa.spring6.bean.Order">
<property name="goods">
<!-- 注入数据用array标签 -->
<array>
<!-- 注入非简单类型用ref -->
<ref bean="goodsBean01"/>
<ref bean="goodsBean02"/>
</array>
</property>
</bean>
</beans>
第四步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Order orderBean = applicationContext.getBean("orderBean", Order.class);
System.out.println(orderBean);
}
第五步:运行测试程序
要点:
- 如果数组中是简单类型,使用value标签。
- 如果数组中是非简单类型,使用ref标签。
3.6 注入List集合
List集合:有序可重复
第一步:创建Person类
package com.julissa.spring6.bean;
import java.util.List;
public class Person {
private List<String> names; // 一个人有多个名字
public void setNames(List<String> names) {
this.names = names;
}
@Override
public String toString() {
return "Person{" +
"names=" + names +
'}';
}
}
第二步:配置beans.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">
<!-- 配置Person-->
<bean id="personBean" class="com.julissa.spring6.bean.Person">
<property name="names">
<!-- 注入集合属性用list标签 -->
<list>
<!-- 简单类型用value-->
<value>julissa</value>
<value>julissa</value>
<value>小清</value>
<value>小清</value>
<value>julissa</value>
</list>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);
}
第四步:运行测试程序
注意:注入List集合的时候使用list标签,如果List集合中是简单类型使用value标签,反之使用ref标签。
3.7 注入Set集合
Set集合:无序不可重复
第一步:创建Person类
package com.julissa.spring6.bean;
import java.util.Set;
public class Person {
private Set<String> phones; // 一个人有多个电话号码
public void setPhones(Set<String> phones) {
this.phones = phones;
}
@Override
public String toString() {
return "Person{" +
"phones=" + phones +
'}';
}
}
第二步:配置beans.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">
<!-- 配置Person-->
<bean id="personBean" class="com.julissa.spring6.bean.Person">
<property name="phones">
<!-- 注入Set集合属性用set标签 -->
<set>
<!-- 简单类型用value-->
<value>13030303300</value>
<value>12020202200</value>
<value>14040404400</value>
<value>15050505500</value>
<value>12020202200</value>
<value>14040404400</value>
<value>15050505500</value>
</set>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);
}
第四步:运行测试程序
要点:
- 使用<set>标签
- set集合中元素是简单类型的使用value标签,反之使用ref标签。
3.8 注入Map集合
Map集合,以键值对形式出现
第一步:创建Person类
package com.julissa.spring6.bean;
import java.util.Map;
public class Person {
private Map<Integer,String> addresses; // 一个人有多个住址
public void setAddresses(Map<Integer, String> addresses) {
this.addresses = addresses;
}
@Override
public String toString() {
return "Person{" +
"addresses=" + addresses +
'}';
}
}
第二步:配置beans.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">
<!-- 配置Person-->
<bean id="personBean" class="com.julissa.spring6.bean.Person">
<property name="addresses">
<!-- 注入Map集合属性用map标签 -->
<map>
<!-- 简单类型用value-->
<entry key="1" value="广东省"/>
<entry key="2" value="湖南省"/>
<entry key="3" value="福建省"/>
</map>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person personBean = applicationContext.getBean("personBean", Person.class);
System.out.println(personBean);
}
第四步:运行测试程序
要点:
- 使用<map>标签
- 如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。
- 如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。
3.9 注入Properties
java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合。
第一步:创建MySQLDataSource类
package com.julissa.spring6.bean;
import java.util.Properties;
public class MySQLDataSource {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MySQLDataSource{" +
"properties=" + properties +
'}';
}
}
第二步:配置beans.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">
<!-- 配置MySQLDataSource-->
<bean id="mySQLDataSourceBean" class="com.julissa.spring6.bean.MySQLDataSource">
<property name="properties">
<!-- 注入Properties集合属性用props标签 -->
<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>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
MySQLDataSource mySQLDataSourceBean = applicationContext.getBean("mySQLDataSourceBean", MySQLDataSource.class);
System.out.println(mySQLDataSourceBean);
}
第四步:运行测试程序
要点:
- 使用<props>标签嵌套<prop>标签完成。
3.10 注入空字符串
注入空字符串使用:<value/> 或者 value=“”
第一步:创建User类
package com.julissa.spring6.bean;
import java.util.Arrays;
/**
* bean类 封装用户信息
*/
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<bean id="userBean" class="com.julissa.spring6.bean.User">
<!-- 注入空字符串-->
<!-- 第一种方式-->
<!--
<property name="name" value=""/>
-->
<!-- 第二种方式-->
<property name="name">
<value/>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
第四步:运行测试程序
要点:
- 注入空字符串使用:<value/> 或者 value=“”
3.11 注入null
注入null使用:<null/> 或者 不为该属性赋值
第一步:创建User类
package com.julissa.spring6.bean;
import java.util.Arrays;
/**
* bean类 封装用户信息
*/
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<bean id="userBean" class="com.julissa.spring6.bean.User">
<!-- 注入null-->
<!-- 第一种方式-->
</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">
<!-- 配置User-->
<bean id="userBean" class="com.julissa.spring6.bean.User">
<!-- 注入null-->
<!-- 第二种方式-->
<property name="name">
<null/>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
第四步:运行测试程序
要点:
- 注入null使用:<null/> 或者 不为该属性赋值
3.12 注入的值中含有特殊符号
XML中有5个特殊字符,分别是:<、>、'、"、&
以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C2npWCIt-1679732787628)(null)]
解决方案包括两种:
- 第一种:特殊符号使用转义字符代替。
- 第二种:将含有特殊符号的字符串放到:<![CDATA[]]> 当中。因为放在CDATA区中的数据不会被XML文件解析器解析。
5个特殊字符对应的转义字符分别是:
特殊字符 | 转义字符 |
---|---|
> | > |
< | < |
’ | ' |
" | " |
& | & |
第一步:创建User类
package com.julissa.spring6.bean;
import java.util.Arrays;
/**
* bean类 封装用户信息
*/
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<bean id="userBean" class="com.julissa.spring6.bean.User">
<!-- 注入的只含有特殊符号 -->
<!-- 第一种:特殊符号使用转义字符代替 -->
<!--
<property name="name" value="2 < 3"/>
-->
<!-- 将含有特殊符号的字符串放到:<![CDATA[]]> 当中 -->
<property name="name">
<!-- 只能使用value标签 -->
<value><![CDATA[2 < 3]]></value>
</property>
</bean>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
第四步:运行测试程序
要点:
注入带有特殊符号的值包括两种:
- 第一种:特殊符号使用转义字符代替。
- 第二种:将含有特殊符号的字符串放到:<![CDATA[]]> 当中。因为放在CDATA区中的数据不会被XML文件解析器解析。
注意:使用CDATA时,不能使用value属性,只能使用value标签。
4. p命名空间注入
目的:简化配置。
使用p命名空间注入的前提条件包括两个:
- 第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p=“http://www.springframework.org/schema/p”
- 第二:p命名空间注入是基于setter方法的,所以需要对应的属性提供setter方法。
第一步:创建User类
package com.julissa.spring6.bean;
import java.util.Arrays;
/**
* bean类 封装用户信息
*/
public class User {
private String name;
private int age;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<!-- p命名空间注入格式 p.set方法去掉set后首字母小写:值-->
<bean id="userBean" class="com.julissa.spring6.bean.User" p:name="julissa" p:age="20"/>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
第四步:运行测试程序
把setter方法去掉后运行测试程序
所以p命名空间实际上是对set注入的简化。
5. c命名空间注入
c命名空间是简化构造方法注入的。
使用c命名空间的两个前提条件:
-
第一:需要在xml配置文件头部添加信息:xmlns:c=“http://www.springframework.org/schema/c”
-
第二:需要提供构造方法。
第一步:创建User类
package com.julissa.spring6.bean;
import java.util.Arrays;
/**
* bean类 封装用户信息
*/
public class User {
private String name;
private int age;
public User(String username, int age) {
this.name = username;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
第二步:配置beans.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">
<!-- 配置User-->
<!-- C命名空间注入-->
<!-- 第一种写法:c_下标,从0开始,对应构造方法种参数的位置-->
<!--
<bean id="userBean" class="com.julissa.spring6.bean.User" c:_0="julissa" c:_1="20"/>
-->
<!-- 第一种写法:c_xxx:xxx为构造方法中形参的参数名-->
<bean id="userBean" class="com.julissa.spring6.bean.User" c:username="julissa" c:age="20"/>
</beans>
第三步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
User userBean = applicationContext.getBean("userBean", User.class);
System.out.println(userBean);
}
第四步:运行测试程序
把构造方法注释掉运行测试程序
所以,c命名空间是依靠构造方法的。
注意:不管是p命名空间还是c命名空间,注入的时候都可以注入简单类型以及非简单类型。
6. util命名空间
使用util命名空间可以让配置复用。
使用util命名空间的前提是:在spring配置文件头部添加配置信息。如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
</beans>
第一步:创建MyDataSource类
package com.julissa.spring6.bean;
import java.util.Properties;
public class MyDataSource {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MyDataSource{" +
"properties=" + properties +
'}';
}
}
第一步:创建MyDataSource2类
package com.julissa.spring6.bean;
import java.util.Properties;
public class MyDataSource2 {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "MyDataSource{" +
"properties=" + properties +
'}';
}
}
第三步:配置beans.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.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 配置Properties -->
<util:properties id="prop">
<prop key="driver">com.mysql.cj.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
<prop key="user">root</prop>
<prop key="password">123456</prop>
</util:properties>
<!-- 配置MyDataSource -->
<bean id="myDataSourceBean" class="com.julissa.spring6.bean.MyDataSource">
<property name="properties" ref="prop"/>
</bean>
<!-- 配置MyDataSource2 -->
<bean id="myDataSource2Bean" class="com.julissa.spring6.bean.MyDataSource2">
<property name="properties" ref="prop"/>
</bean>
</beans>
第四步:编写测试程序
@Test
public void testDataSource(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
MyDataSource dataSource = applicationContext.getBean("myDataSourceBean", MyDataSource.class);
System.out.println(dataSource);
MyDataSource2 dataSource2 = applicationContext.getBean("myDataSource2Bean", MyDataSource2.class);
System.out.println(dataSource2);
}
第五步:运行测试程序
7. 基于XML的自动装配
Spring还可以完成自动化的注入,自动化注入又被称为自动装配。
自动装配分为:
- 根据名字进行自动装配
- 根据类型进行自动装配。
7.1 根据名字进行自动装配
第一步:创建UserDao类
package com.julissa.spring6.dao;
public class UserDao {
/**
* 添加用户
*
*/
public void insert(){
System.out.println("-------数据库正在保存用户信息-------");
}
}
第一步:创建UserService类
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
public class UserService {
private UserDao aaa;
public void setAaa(UserDao aaa) {
this.aaa = aaa;
}
public void add(){
aaa.insert();
}
}
第三步:配置beans.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">
<!-- 配置UserDao-->
<bean id="aaa" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService-->
<!-- 根据名称自动进行装配-->
<!-- id ,也叫做bean的名称-->
<!-- id为set方法名去掉set后首字母小写,如果是自动生成的set方法,写属性名就可以了-->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService" autowire="byName"/>
</beans>
这个配置起到关键作用:
- UserService Bean中需要添加autowire=“byName”,表示通过名称进行装配。
- UserService类中有一个UserDao属性,而UserDao属性的名字是aaa,对应的set方法是setAaa(),正好和UserDao Bean的id是一样的。这就是根据名称自动装配。
第四步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = applicationContext.getBean("userServiceBean", UserService.class);
userService.add();
}
第五步:运行测试程序
来测试一下,byName装配是和属性名有关还是和set方法名有关系
第一步:修改UserService类
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
import com.julissa.spring6.dao.VipDao;
public class UserService {
//属性名没有修改
private UserDao aaa;
//修改了set方法名
public void setUserDao(UserDao aaa) {
this.aaa = aaa;
}
/**
public void setAaa(UserDao aaa) {
this.aaa = aaa;
}
*/
public void add(){
aaa.insert();
}
}
第二步:运行测试程序
通过测试得知,aaa属性并没有赋值成功。也就是并没有装配成功。
第三步:修改beans.xml,将UserDaoBean的id从aaa修改为userDao
<?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">
<!-- 配置UserDao-->
<!--
<bean id="aaa" class="com.julissa.spring6.dao.UserDao"/>
-->
<bean id="userDao" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService-->
<!-- 根据名称自动进行装配-->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService" autowire="byName"/>
</beans>
第四步:运行测试程序
这说明,如果根据名称装配(byName),底层会调用set方法进行注入。
例如:setAge() 对应的名字是age,setPassword()对应的名字是password,setEmail()对应的名字是email。
7.2 根据类型进行自动装配
第一步:创建UserDao类
package com.julissa.spring6.dao;
public class UserDao {
/**
* 添加用户
*
*/
public void insert(){
System.out.println("-------数据库正在保存用户信息-------");
}
}
第一步:创建UserService类
package com.julissa.spring6.service;
import com.julissa.spring6.dao.UserDao;
import com.julissa.spring6.dao.VipDao;
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
userDao.insert();
}
}
第三步:配置beans.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">
<!-- 配置UserDao-->
<bean class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService-->
<!-- 根据类型自动进行装配-->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService" autowire="byType"/>
</beans>
这个配置起到关键作用:
- UserService Bean中需要添加autowire=“byType”,表示通过类型进行装配。
- UserService类中有一个UserDao属性,而UserDao属性的类型是UserDao,于是在Spring容器中匹配类型为UserDao的对象,再通过set方法进行注入
第四步:编写测试程序
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = applicationContext.getBean("userServiceBean", UserService.class);
userService.add();
}
第五步:运行测试程序
我们把UserService中的set方法注释掉,再执行:
可以看到无论是byName还是byType,在装配的时候都是基于set方法的。所以set方法是必须要提供的。提供构造方法是不行的。
如果byType,根据类型装配时,如果配置文件中有两个类型一样的bean会出现什么问题呢?
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置UserDao-->
<bean id="userDao" class="com.julissa.spring6.dao.UserDao"/>
<bean id="userDao2" class="com.julissa.spring6.dao.UserDao"/>
<!-- 配置UserService-->
<!-- 根据类型自动进行装配-->
<bean id="userServiceBean" class="com.julissa.spring6.service.UserService" autowire="byType"/>
</beans>
执行测试程序
测试结果说明了,当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个。
8. 引入外部配置属性文件
我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver url username password等信息。这些信息可以单独写到一个属性配置文件中吗,这样用户修改起来会更加的方便。当然可以。
引入外部配置属性文件需要引入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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
</beans>
第一步:创建MyDataSource类
package com.julissa.spring6.bean;
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 MyDataSource implements DataSource {
private String driver;
private String url;
private String username;
private String password;
@Override
public String toString() {
return "MyDataSource{" +
"driver='" + driver + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + 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 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;
}
}
第一步:创建jdbc.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring
jdbc.username=root
jdbc.password=123456
第三步:配置beans.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: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">
<!-- 引入外部文件jdbc.properties-->
<context:property-placeholder location="jdbc.properties"/>
<!-- 配置MyDataSource-->
<bean id="myDataSourceBean" class="com.julissa.spring6.bean.MyDataSource">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
第四步:编写测试程序
@Test
public void testDataSource(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
MyDataSource dataSource = applicationContext.getBean("myDataSourceBean", MyDataSource.class);
System.out.println(dataSource);
}
第五步:运行测试程序