目录

一:Spring对IoC的实现

1.IoC 控制反转

2.依赖注入

2.1set注入

2.2构造注入

3.set注入专题

3.1 注入外部Bean

3.2 注入内部Bean

3.3 注入简单类型

3.4 级联属性赋值(了解)

3.5 注入数组

3.6 注入List集合和Set集合

3.7注入Map和Properties集合

3.8 注入null和空字符串

3.9 注入的值中含有特殊符号

4.p命名空间注入

5.c命名空间注入

6.util命名空间

7. 基于XML的自动装配(byName & byType)

7.1 根据名称(byName)自动装配

7.2根据类型(byType)自动装配

8. Spring引入外部属性配置文件(使用context命名空间)


一:Spring对IoC的实现

前面我们已经学会了如何用spring创建管理对象,接下来就要学习如何让对象和对象产生关系,使用依赖注入!

1.IoC 控制反转

(1)控制反转是一种思想,一种新型的设计模式!

(2)控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。

(3)控制反转,反转的是什么?

①将对象的创建权利交出去,交给第三方容器负责。

②将对象和对象之间关系的维护权交出去,交给第三方容器负责。

(4)控制反转这种思想如何实现呢?

DI(Dependency Injection):依赖注入

2.依赖注入

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

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

依赖注入:

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

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

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

2.1set注入

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

pom.xml配置

    4.0.0    com.bjpowernode    spring6-002-dependency-injection    1.0-SNAPSHOT    jar                                    repository.spring.milestone            Spring Milestone Repository            https://repo.spring.io/milestone                                            org.springframework            spring-context            6.0.0-M2                                    junit            junit            4.12                                    org.apache.logging.log4j            log4j-core            2.19.0                            org.apache.logging.log4j            log4j-slf4j2-impl            2.19.0                        17        17    

log4j2.xml日志配置

                                                                        

UserDao类:连接数据库的操作

package com.bjpowernode.spring6.dao;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class UserDao {    // 一般声明为常量   private static final Logger logger = LoggerFactory.getLogger(UserDao.class);    // 使用日志进行打印,用System.out.println也可以    public void insert(){        logger.info("数据库正在保存用户信息!");    }}

UserService类:调用UserDao中的方法

①set注入的话,必须提供一个set方法;Spring容器会调用这个set方法,来给userDao属性赋值。

②这个set方法不符合javabean规范也可以,但是必须以set开头,例如:setUD也是可以的;这里我使用的是IDEA自动生成的符合javabean规范的。

package com.bjpowernode.spring6.service;import com.bjpowernode.spring6.dao.UserDao;public class UserService {    private UserDao userDao;    // set注入,必须提供一个set方法    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    public void saveUser(){        // 调用UserDao保存用户信息        userDao.insert();    }}

spring.xml配置

①配置userDaoBean和UserService,让spring管理这两个类。

②对于UserService,想让Spring调用对应的set方法,需要配置property标签

name属性值:set方法的方法名,去掉set,然后把剩下的单词首字母变小写
ref属性值:翻译为引用,英语单词references,后面指定的是要注入的bean的id

                              

③另外,对于property标签来说,ref属性也可以采用标签的方式,但使用ref属性是多数的:

        

编写测试类

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();    }}

执行结果:

正常输出日志信息了,说明两个问题:

①spring正常创建UserDao和UserService对象了!

②spring关联了对象与对象之间的关系了!

总结:set注入的核心实现原理是通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系。

2.2构造注入

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

①set注入:是先创建对象,才能执行set方法,给属性赋值。

②构造注入:是在创建对象的同时,给属性赋值,时机是不同的。

在定义一个VipDao类

package com.bjpowernode.spring6.dao;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class VipDao {    private static final Logger logger = LoggerFactory.getLogger(VipDao.class);    public void delete(){        logger.info("正在删除信息!");    }}

ConstructService类

构造方法注入,必须要提供一个构造方法!

package com.bjpowernode.spring6.service;import com.bjpowernode.spring6.dao.UserDao;import com.bjpowernode.spring6.dao.VipDao;public class ConstructService {    private UserDao userDao;    private VipDao vipDao;    // 构造注入,必须有构造方法    public ConstructService(UserDao userDao, VipDao vipDao) {        this.userDao = userDao;        this.vipDao = vipDao;    }        public void save(){        userDao.insert();        vipDao.delete();    }}

bean.xml配置

访问的方式有三种:使用的是constructor-arg标签

①第一种方式是根据下标index的方式,下标的顺序是构造方法参数的顺序。

②第二种方式是根据构造方法参数的名字name的方式。

③第三种方式是根据类型进行注入,不指定,spring会自己推断做类型匹配

                                                                                                             

编写测试

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();    }}

执行结果:

3.set注入专题

set注入和构造注入中,set注入用的比较多,所以下面就学习一下set注入的专题!

3.1 注入外部Bean

(1)在之前我们使用的案例一直就是注入外部Bean的方式!

(2)外部Bean的特点:bean定义到外面,在property标签中使用ref属性进行注入通常这种方式是常用!

                    

3.2 注入内部Bean

内部Bean的方式:在bean标签中直接嵌套bean标签,不需要ref属性引入

                                    

3.3 注入简单类型

(1)之前在进行注入的时候,对象的属性都是另一个对象;那如果对象的属性是int类型呢?也可以通过set注入的方式给该属性赋值,实际上只要能够调用set方法就可以给属性赋值

(2)重点:如果给简单类型赋值,就不能使用ref属性,需要使用value属性

User类:定义了两个简单类型,写上set方法

package com.bjpowernode.spring6.bean;public class User {    private String name;    private int age;    public void setName(String name) {        this.name = name;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}

set-di.xm配置

注:既可以使用value标签的方式,也可以使用value属性的方式(常用)

                        

编写测试

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);    }}

执行结果:默认会调用toString方法

需要特别注意:如果给简单类型赋值,使用value属性或value标签,而不是ref!

(3)那么简单类型包括哪些呢?可以通过Spring的源码来分析一下!

双击shift搜索BeanUtils类,ctrl+F12搜索isSimpleValueType方法,里面都是简单类型:

(4)这里重点说一下Date类型,如果硬要把Date类型当做简单类型,使用value赋值的话,这个日期的格式有要求:Thu Jan 12 21:05:49 CST 2023 ,所以在实际的开发中,我们一般采用ref属性的方式给Date类型的属性赋值!

(5)简单类型注入的经典案例:给数据源的属性注入值:

假设我们现在要自己手写一个数据源(能够提供Connection对象的),我们都知道所有的数据源都要实现javax.sql.DataSource接口,并且数据源中应该有连接数据库的信息,例如:driver、url、username、password等。

数据源MyDataSource

package com.bjpowernode.spring6.jdbc;import javax.sql.DataSource;import java.io.PrintWriter;import java.sql.Connection;import java.sql.SQLException;import java.sql.SQLFeatureNotSupportedException;import java.util.logging.Logger;public class MyDateSource implements DataSource {    private String driver;    private String url;    private String username;    private String password;    public void setDriver(String driver) {        this.driver = driver;    }    public void setUrl(String url) {        this.url = url;    }    public void setUsername(String username) {        this.username = username;    }    public void setPassword(String password) {        this.password = password;    }    @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 unwrap(Class iface) throws SQLException {        return null;    }    @Override    public boolean isWrapperFor(Class                                                

编写测试

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);    }}

测试结果:成功注入连接数据库的信息

3.4 级联属性赋值(了解)

我们先回顾一下原来使用的注入方式,然后在使用级联属性赋值,进行对比!

clazz班级类

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学生类

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 +                '}';    }}

第一种:原来的注入方式

                                        

第二种方式:级联注入方式

使用级联属性赋值需要注意两点:

①配置的顺序不能颠倒,先配置student在配置clazz

clazz属性必须提供getClazz()方法(所以要在Student类当中要增加getter方法)

                                            

执行结果:

3.5 注入数组

这里主要学习两种情况:数组中的元素是简单类型和当数组中的元素是非简单类型

Woman类,作为非简单类型

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类,里面包含简单类型和非简单类型的数组属性

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配置

当属性是数组时,需要先使用一下array标签,在array标签中再写value和ref标签进行赋值!

                                                                                        抽烟                喝酒                烫头                                                                                                      

编写测试

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);    }}

执行结果:

要点:

如果数组中是简单类型,使用value标签。

如果数组中是非简单类型,使用ref标签。

3.6 注入List集合和Set集合

Person类

package com.bjpowernode.spring6.bean;import java.util.List;import java.util.Set;public class Person {    // 注入List    private List names;    // 注入Set集合    private Set addrs;    @Override    public String toString() {        return "Person{" +                "names=" + names +                ", addrs=" + addrs +                '}';    }    public void setNames(List names) {        this.names = names;    }    public void setAddrs(Set addrs) {        this.addrs = addrs;    }}

spring-collection.xml配置

如果是List集合或者Set集合的属性,需要先使用标签和标签,标签中再写value和ref标签进行赋值!

                                                     张三                 李四                 张三                 王五                                                                      张三                 李四                 张三                 王五                           

编写测试

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);    }}

执行结果:

从执行结果上看,可以得出:List集合是有序可重复、Set集合是无序不可重复!

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

3.7注入Map和Properties集合

Properties集合本质上也是一个Map集合,但是Properties集合的key和value只能是String类型,并且注入的方式也是与Map集合不同的!

Man类

package com.bjpowernode.spring6.bean;import java.util.Map;import java.util.Properties;public class Man {    // 注入Map集合    private Map 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 phones) {        this.phones = phones;    }}

spring-collection.xml配置

如果是Map集合的属性,使用map标签嵌套entry子标签(不使用ref和value标签了)

如果是Map集合的属性,使用props标签嵌套pro标签

                                                                                                                                                   com.mysql.jdbc.driver                jdbc:mysql://localhost:3306/spring6                        

执行结果:

要点:

对于Map集合使用

标签,对于Properties使用标签嵌套标签完成。

如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。

如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。

3.8 注入null和空字符串

Cat类

package com.bjpowernode.spring6.bean;public class Cat {    private String name;    private int age;    @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配置

①注入空字符串使用: 或者 value=””。

②注入null使用: 或者 不为该属性赋值。

                                                                                                                                               

3.9 注入的值中含有特殊符号

(1)XML中有5个特殊字符,分别是:、’、”、&

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

Math类

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配置

解决方案包括两种:

第一种:特殊符号使用转义字符代替。

第二种:将含有特殊符号的字符串放到: 当中。因为放在CDATA区中的数据不会被XML文件解析器解析。

注:使用的方式只能使用value标签的形式,不能使用value属性!

注:是XML的语法,放在这里面的东西不会被XML解析器解析!

5个特殊字符对应的转义字符分别是:

特殊字符

转义字符

>

>

<

<

'

"

&

&

                    <!--直接写2           <!-- <property name="result" value="2-->                                    <!--第二种解决方案:-->                                            <![CDATA[2                    

4.p命名空间注入

(1)p命名空间是简化set方法注入的。

(2)使用p命名空间注入的前提条件包括两个:

第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p=”http://www.springframework.org/schema/p”

第二:p命名空间注入还是基于set注入的,只不过p命名空间注入可以让spring配置变的更加简单;所以需要对应的属性提供setter方法

Dog类:提供了setter方法

package com.bjpowernode.spring6.bean;import java.util.Date;public class Dog {    private String name;    private int age;    // 虽然简单类型,但是一般都是当做非简单类型对待    private Date date;    @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配置

①在spring的配置文件头部添加p命名空间。
②使用:在标签中的class属性后面直接使用,对于简单类型属性赋值p:属性名 = “属性值”;对于非简单类型属性赋值p:属性名-ref = “属性值”

                                               

测试程序

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);    }}

执行结果:

如果把setter方法注释掉,会报错

5.c命名空间注入

(1)c命名空间是简化构造方法注入的。

(2)使用c命名空间的两个前提条件:

第一:需要在xml配置文件头部添加信息:xmlns:c=”http://www.springframework.org/schema/c”

第二:需要提供构造方法。

MyTime类:提供了构造方法

package com.bjpowernode.spring6.bean;public class MyTime {    private int year;    private int month;    private int day;    public MyTime(int year, int month, int day) {        this.year = year;        this.month = month;        this.day = day;    }    @Override    public String toString() {        return "MyTime{" +                "year=" + year +                ", month=" + month +                ", day=" + day +                '}';    }}

spring-c.xml配置

①在spring的配置文件头部添加c命名空间。
使用:c:_0 下标方式或者c:name 参数名方式。

                                            

测试程序

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);    }}

执行结果:

如果把构造方法注释掉

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

6.util命名空间

(1)使用util命名空间可以让配置复用

(2)使用util命名空间的前提是:在spring配置文件头部添加配置信息。如下:

(3)假设系统集成不同厂家的连接池,这里用自己写的数据源来代替;里面的连接数据库的配置实际上是相同的,所以我们就可以使用util命名空间进行配置复用!

数据源MyDataSource1

package com.bjpowernode.spring6.jdbc;import javax.sql.DataSource;import java.io.PrintWriter;import java.sql.Connection;import java.sql.SQLException;import java.sql.SQLFeatureNotSupportedException;import java.util.Properties;import java.util.logging.Logger;public class MyDateSource1 implements DataSource {    // 连接数据库的信息,放到成员变量里    /*private String driver;    private String url;    private String username;    private String password;*/        // 当然也可以放到一个Properties集合当中    private Properties properties;    public void setProperties(Properties properties) {        this.properties = properties;    }    @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 unwrap(Class iface) throws SQLException {        return null;    }    @Override    public boolean isWrapperFor(Class                                            com.mysql.jdbc.Driver                jdbc:mysql://localhost:3306/spring6                root                123456                                                                    com.mysql.jdbc.Driver                jdbc:mysql://localhost:3306/spring6                root                123456                        

spring-util.xml配置:使用util命名空间,把公共的配置使用util命名

使用util命名空间后,把重复的配置放到util:properties标签里面,并设置唯一标识id;后面如果想使用,直接使用ref属性直接引入id即可。

                com.mysql.jdbc.Driver        jdbc:mysql://localhost:3306/spring6        root        123456                                            

测试代码

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);    }}

执行结果:

实际上util命名空间主要是针对集合的:

7. 基于XML的自动装配(byName & byType)

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

UserDao类

package com.bjpowernode.spring6.dao;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class UserDao {      private static final Logger logger = LoggerFactory.getLogger(UserDao.class);    public void insert(){        logger.info("数据库正在保存用户信息!");    }}

UserDaoService类

package com.bjpowernode.spring6.service;import com.bjpowernode.spring6.dao.UserDao;public class UserService {    private UserDao userDao;    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }    public void saveUser(){        // 调用UserDao保存用户信息        userDao.insert();    }}

7.1 根据名称(byName)自动装配

下面这个配置起到关键作用:

(1)UserService Bean中需要添加autowire=”byName”,表示通过名称进行装配

(2)如果是正常的装配,UserDao的id随便写,只要和上面ref的值对应着就行!

(3)如果是自动装配,UserDao的id必须是UserService类中的UserDao属性对应的setUserDao(set方法)方法去掉前面的set,后面首字母变成小写的值:userDao!

(4)所以根据名称自动配置本质上也是set注入!

spring-autowire.xml配置

                                    

编写测试

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();    }}

执行结果:

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

7.2根据类型(byType)自动装配

(1)其实无论是根据名称自动装备byName还是根据类型制动装备byType,在装配的时候都是基于set方法的,所以set方法是必须要提供的!

(2)根据byType自动装配时,对于被注入的对象,只需要使用bean标签指定要注入的类型,不需要再指定id。

spring-autowire.xml配置

            

执行结果:

如果byType根据类型装配时,如果配置文件中有两个类型一样的bean会出现什么问题呢?

                

执行结果:

测试结果说明了,当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个!

8. Spring引入外部属性配置文件(使用context命名空间)

我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver、url、username password等信息。这些信息可以单独写到一个属性配置文件中吗?这样用户修改起来会更加的方便,当然是可以的,使用context命名空间!

第一步:写一个数据源类,提供相关属性

package com.bjpowernode.spring6.jdbc;import javax.sql.DataSource;import java.io.PrintWriter;import java.sql.Connection;import java.sql.SQLException;import java.sql.SQLFeatureNotSupportedException;import java.util.logging.Logger;public class MyDateSource implements DataSource {    private String driver;    private String url;    private String username;    private String password;    public void setDriver(String driver) {        this.driver = driver;    }    public void setUrl(String url) {        this.url = url;    }    public void setUsername(String username) {        this.username = username;    }    public void setPassword(String password) {        this.password = password;    }    @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 unwrap(Class iface) throws SQLException {        return null;    }    @Override    public boolean isWrapperFor(Class

第四步:在spring中配置使用jdbc.properties文件

第一步:引入context命名空间,前面已经引过了。

第二步:使用标签的location属性来指定属性配置文件的路径。 location默认从类的根路径下开始加载资源

                                                        

测试程序:

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);    }}

执行结果:

这里username怎么不是我们配置文件里的?spring通过${}加载,默认是是先加载windows系统的环境变量!

怎么解决?一般在所有配置前面加上jdbc前缀

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/spring6jdbc.username=rootjdbc.password=123456

执行结果: