• Java--Spring之IoC控制反转;基于XML配置文件的DI


    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架

    控制反转Inversion of Control,缩写IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。

    依赖:classA 类中含有 classB 的实例,在 classA 中调用 classB 的方法完成功能,即 classA 对 classB 有依赖

    控制:创建对象,给对象的属性赋值,管理对象之间的关系

    反转:控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。

    正转:开发人员在代码中,使用new 构造方法创建对象(主动管理对象),如下

    User user = new User();

    Ioc 的实现:

    1、依赖注入Dependency Injection,简称DI):组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系

    容器全权负责的组件的装配,它会把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。

    (1)设值注入(Setter Injection):通过JavaBean属性注射依赖关系的做法称为设值方法注入

    (2)构造注入Constructor Injection): 将依赖关系作为构造函数参数传入的做法称为构造器注入

    2、依赖查找Dependency Lookup):容器提供回调接口和上下文条件给组件

    Spring 框架使用依赖注入(DI)实现 IoC

    spring的IOC是使用的di实现了ioc的功能, spring底层创建对象,使用的是反射机制

    spring是一个容器,管理对象,给属性赋值, 底层是反射创建对象

    Spring 容器负责创建、管理所有的 Java 对象,这些 Java 对象被称为 Bean

    Spring 容器管理着容器中 Bean 之间的依赖关系,Spring 使用“依赖注入”(DI)的方式来管理 Bean之间的依赖关系。使用 IoC 实现对象之间的解耦和

    Java中创建对象主要有如下方式:

    (1)构造方法,new对象

    User user = new User();

    (2)反射机制

    【1】使用class的newInstance()方法

    1. // 通过反射机制,获取Class,通过Class来实例化对象
    2. Class className = Class.forName("com.xx.User");
    3. // newInstance()方法会调用User类的无参数构造方法,完成对象的创建(必须保证无参构造方法是存在)
    4. Object obj = className.newInstance();//User对象无参构造

    【2】使用Constructor的newInstance()方法

    1. Class userClass = Class.forName("reflect.xx.User");
    2. Constructor constructor = userClass .getConstructor();
    3. Object obj = constructor.newInstance();

    (3)序列化和反序列化

    1. /*
    2. 序列化对象
    3. */
    4. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/iostream/users"));
    5. /**
    6. * 1、一次序列化多个对象
    7. * 将对象放到集合当中,序列化集合。
    8. * 参与序列化的ArrayList集合以及集合中的元素都需要实现 java.io.Serializable接口
    9. * 2、ArrayList 也实现了 java.io.Serializable 接口
    10. * public class ArrayList extends AbstractList
    11. * implements List, RandomAccess, Cloneable, java.io.Serializable
    12. * */
    13. //创建List数组
    14. List list = new ArrayList<>();
    15. User u1 = new User();
    16. list.add(u1);
    17. oos1.writeObject(list);
    18. oos1.flush();
    19. /*
    20. 反序列化对象
    21. */
    22. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/iostream/users"));
    23. // 开始反序列化,读
    24. List list = (List) ois.readObject();
    25. for (User user:list) {
    26. System.out.println(user);
    27. }

    (4)克隆

    User user1 = (User) user.clone();

    首先我们先设置一下maven的本地仓库

    一、基于XML配置文件的DI

    (一)设值注入(Setter Injection)

    set 注入也叫设值注入是指,通过 setter 方法传入被调用者的实例

    1、简单类型

    简单类型set注入语法如下:

    1. <bean id="xx" class="xx">
    2. <property name="属性名字" value="属性值" />
    3. ...
    4. bean>

    注:

    (1)没有set方法报错

            Bean property 'userName' is not writable or has an invalid setter method

    (2)有set方法没赋值 不报错,值为null;User{userName='null', age=18}

    (3)没有email属性,但是有setEmail方法,不会报错,该属性值不存在

    (4)spring还可以创建非自定义对象,如 java.util.Date

    (1)创建一个Java类对象User

    1. public class User {
    2. private String userName;
    3. private int age;
    4. public User() {
    5. System.out.println("spring会调用User类的无参构造方法创建对象");
    6. }
    7. /*
    8. (1)没有set方法报错
    9. Bean property 'userName' is not writable or has an invalid setter method
    10. (2)有set方法没赋值
    11. 不报错,值为null;User{userName='null', age=18}
    12. (3)没有email属性,但是有setEmail方法,不会报错,该属性值不存在
    13. */
    14. public void setUserName(String userName) {
    15. this.userName = userName;
    16. }
    17. public void setAge(int age) {
    18. this.age = age;
    19. }
    20. //没有email属性,但是有setEmail方法,不会报错,该属性值不存在
    21. public void setEmail(String email) {
    22. System.out.println("setEmail="+email);
    23. }
    24. @Override
    25. public String toString() {
    26. return "User{" +
    27. "userName='" + userName + '\'' +
    28. ", age=" + age +
    29. '}';
    30. }
    31. }

    (2)spring配置文件 applicationContext.xml

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="user" class="com.mycompany.p1setinject.User">
    5. <property name="userName" value="admin" />
    6. <property name="age" value="18" />
    7. <property name="email" value="45678545@qq.com" />
    8. bean>
    9. <bean id="myDate" class="java.util.Date">
    10. <property name="time" value="987657289037632" />
    11. bean>
    12. beans>

    (3)测试类

    1. public class TestSetInject {
    2. @Test
    3. public void testSetInjectNormal(){
    4. String config = "p1setinject/applicationContext.xml";
    5. ApplicationContext ac = new ClassPathXmlApplicationContext(config);
    6. User user = (User) ac.getBean("user");
    7. System.out.println(user);
    8. }
    9. @Test
    10. public void testSetDate(){
    11. String config = "p1setinject/applicationContext.xml";
    12. ApplicationContext ac = new ClassPathXmlApplicationContext(config);
    13. Date date = (Date) ac.getBean("myDate");
    14. System.out.println("myDate="+date);
    15. }
    16. }

    2、引用类型

    语法如下

    1. (1)简单类型set注入
    2. <bean id="xx" class="xx">
    3. <property name="属性名字" value="属性值" />
    4. <property name="引用对象名称" ref="引用对象bean的id(对象的名称)" />
    5. ...
    6. bean>
    7. (2)引用类型set注入:spring调用类的set方法
    8. <bean id="xx" class="xx">
    9. <property name="属性名称" ref="引用对象bean的id(对象的名称)" />
    10. bean>

    (1)User和Address对象

    1. public class User {
    2. private String userName;
    3. private int age;
    4. //声明一个引用类型
    5. private Address address;
    6. public User() {
    7. System.out.println("spring会调用User类的无参构造方法创建对象");
    8. }
    9. public void setUserName(String userName) {
    10. this.userName = userName;
    11. }
    12. public void setAge(int age) {
    13. this.age = age;
    14. }
    15. public void setAddress(Address address) {
    16. this.address = address;
    17. }
    18. @Override
    19. public String toString() {
    20. return "User{" +
    21. "userName='" + userName + '\'' +
    22. ", age=" + age +
    23. ", address=" + address +
    24. '}';
    25. }
    26. }
    27. public class Address {
    28. private String name;
    29. private String address;
    30. public void setName(String name) {
    31. this.name = name;
    32. }
    33. public void setAddress(String address) {
    34. this.address = address;
    35. }
    36. @Override
    37. public String toString() {
    38. return "Address{" +
    39. "name='" + name + '\'' +
    40. ", address='" + address + '\'' +
    41. '}';
    42. }
    43. }

    (2)spring配置文件 applicationContext.xml

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="user" class="com.mycompany.p2setinjectreference.User">
    5. <property name="userName" value="admin" />
    6. <property name="age" value="18" />
    7. <property name="address" ref="myAddress" />
    8. bean>
    9. <bean id="myAddress" class="com.mycompany.p2setinjectreference.Address">
    10. <property name="name" value="家住址" />
    11. <property name="address" value="江南水乡" />
    12. bean>

    (二)构造注入Constructor Injection

    spring调用类的有参构造方法,在创建对象同时,在构造方法中给属性赋值

    构造注入使用 标签

    标签:一个标签表示构造方法的一个参数

    标签属性:

    (1)name:表示构造方法的形参名

    (2)index:表示构造方法的参数位置,参数从左往右位置是 0 , 1 ,2...

    (3)value:构造方法形参是简单类型,使用value

    (4)ref:构造方法形参是引用类型,使用ref

    注:

    (1)使用name属性实现构造注入;给形参赋值位置可以打乱,根据形参名name赋值

    (2)使用index属性实现构造注入;给形参赋值位置可以打乱,根据index赋值

    (3)省略index;使用index属性实现构造注入;给形参赋值位置不可以打乱

    User和Address对象

    1. public class User {
    2. private String userName;
    3. private int age;
    4. //声明一个引用类型
    5. private Address address;
    6. public User() {
    7. System.out.println("spring会调用User类的无参构造方法创建对象");
    8. }
    9. /**
    10. * 创建有参数构造方法
    11. */
    12. public User(String userName, int age, Address address) {
    13. System.out.println("=====User有参数构造方法======");
    14. //属性赋值
    15. this.userName = userName;
    16. this.age = age;
    17. this.address = address;
    18. }
    19. public void setUserName(String userName) {
    20. this.userName = userName;
    21. }
    22. public void setAge(int age) {
    23. this.age = age;
    24. }
    25. public void setAddress(Address address) {
    26. this.address = address;
    27. }
    28. @Override
    29. public String toString() {
    30. return "User{" +
    31. "userName='" + userName + '\'' +
    32. ", age=" + age +
    33. ", address=" + address +
    34. '}';
    35. }
    36. }

    spring配置文件 applicationContext.xml

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="myAddress" class="com.mycompany.p3constructorinject.Address">
    5. <property name="name" value="家住址" />
    6. <property name="address" value="江南水乡" />
    7. bean>
    8. <bean id="user" class="com.mycompany.p3constructorinject.User">
    9. <constructor-arg name="age" value="20" />
    10. <constructor-arg name="userName" value="admin" />
    11. <constructor-arg name="address" ref="myAddress" />
    12. bean>
    13. <bean id="user1" class="com.mycompany.p3constructorinject.User">
    14. <constructor-arg index="1" value="20" />
    15. <constructor-arg index="0" value="root" />
    16. <constructor-arg index="2" ref="myAddress" />
    17. bean>
    18. <bean id="user2" class="com.mycompany.p3constructorinject.User">
    19. <constructor-arg value="root" />
    20. <constructor-arg value="20" />
    21. <constructor-arg ref="myAddress" />
    22. bean>
    23. <bean id="myFile" class="java.io.File">
    24. <constructor-arg name="parent" value="D:\Java\JavaProject\spring-course\spring-1" />
    25. <constructor-arg name="child" value="readme.txt" />
    26. bean>
    27. beans>

    (三)引用类型自动注入

    引用类型属性的注入,也可不在配置文件中显示注入。可通过标签设置 autowire 属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属 性)

    引用类型自动注入:spring根据某些规则给引用类型赋值;常用规则:byName;byType

    1、byName:按名称自动注入

    当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的

    语法如下,使用autowire = "byName"

    1. <bean id="xx" class="xx" autowire="byName">
    2. <property name="xx" value="xx" />
    3. bean>

    User对象

    1. public class User {
    2. private String userName;
    3. private int age;
    4. //声明一个引用类型
    5. private Address address;
    6. public User() {
    7. System.out.println("spring会调用User类的无参构造方法创建对象");
    8. }
    9. public void setUserName(String userName) {
    10. this.userName = userName;
    11. }
    12. public void setAge(int age) {
    13. this.age = age;
    14. }
    15. public void setAddress(Address address) {
    16. this.address = address;
    17. }
    18. @Override
    19. public String toString() {
    20. return "User{" +
    21. "userName='" + userName + '\'' +
    22. ", age=" + age +
    23. ", address=" + address +
    24. '}';
    25. }
    26. }

    spring配置文件 applicationContext.xml

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="user" class="com.mycompany.p4referenceautobyname.User" autowire="byName">
    5. <property name="userName" value="admin" />
    6. <property name="age" value="20" />
    7. bean>
    8. <bean id="address" class="com.mycompany.p4referenceautobyname.Address">
    9. <property name="name" value="家住址" />
    10. <property name="address" value="江南水乡" />
    11. bean>
    12. beans>

     注: 使用byName,属性是引用类型时,不用使用标签,但是单独声明引用类型时 其标签的id值需要和Java属性值名一致

    2、byType:按类型自动注入

    使用 byType 方式自动注入,要求:配置文件中被调用者 bean 的 class 属性指定的类,要与代码中调用者 bean 类的某引用类型属性类型同源。即要么相同,要么有 is-a 关系(子 类,或是实现类)。但这样的同源的被调用 bean 只能有一个。多于一个,容器就不知该匹配哪一个

    语法如下:

    1. <bean id="xx" class="xx" autowire="byType">
    2. <property name="xx" value="xx" />
    3. bean>

    同源关系:

    (1)java类中引用类型的数据类型和bean的class的值一致

    (2)java类中引用类型的数据类型和bean的class的值是父子类关系

    (3)java类中引用类型的数据类型和bean的class的值是接口和实现类关系 

    User和Address对象

    1. public class User {
    2. private String userName;
    3. private int age;
    4. //声明一个引用类型
    5. private Address address;
    6. private Address address1;
    7. public User() {
    8. System.out.println("spring会调用User类的无参构造方法创建对象");
    9. }
    10. public void setUserName(String userName) {
    11. this.userName = userName;
    12. }
    13. public void setAge(int age) {
    14. this.age = age;
    15. }
    16. public void setAddress(Address address) {
    17. System.out.println("address:"+address);
    18. this.address = address;
    19. }
    20. public void setAddress1(Address address1) {
    21. System.out.println("address1111:"+address1);
    22. this.address1 = address1;
    23. }
    24. @Override
    25. public String toString() {
    26. return "User{" +
    27. "userName='" + userName + '\'' +
    28. ", age=" + age +
    29. ", address=" + address +
    30. '}';
    31. }
    32. }
    33. public class Address {
    34. private String name;
    35. private String address;
    36. public void setName(String name) {
    37. this.name = name;
    38. }
    39. public void setAddress(String address) {
    40. this.address = address;
    41. }
    42. @Override
    43. public String toString() {
    44. return "Address{" +
    45. "name='" + name + '\'' +
    46. ", address='" + address + '\'' +
    47. '}';
    48. }
    49. }
    50. public class DetailAddress extends Address{
    51. }

    spring配置文件 applicationContext.xml

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="user" class="com.mycompany.p5referenceautobytype.User" autowire="byType">
    5. <property name="userName" value="admin" />
    6. <property name="age" value="20" />
    7. bean>
    8. <bean id="mySubAddress" class="com.mycompany.p5referenceautobytype.DetailAddress">
    9. <property name="name" value="详细家住址" />
    10. <property name="address" value="详细江南水乡" />
    11. bean>
    12. beans>

    注:
    在byType中, 在xml配置文件中声明bean只能有一个,多余一个报错

    NoUniqueBeanDefinitionException: No qualifying bean of type 'com.mycompany.p5referenceautobytype.Address' available: expected single matching bean but found 2: myAddress,mySubAddress

    (四)多个Spring配置文件

    在实际应用里,随着应用规模的增加,系统中 Bean 数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将Spring 配置文件分解成多个配置文件。

    包含关系的配置文件:

    多个配置文件中有一个总文件,总配置文件将各其它子文件通过引入。在 Java代码中只需要使用总配置文件对容器进行初始化即可

    applicationContext.xml :表示主配置文件

    包含关系配置文件;包含其他的配置文件的,主配置文件一般是不定义对象

    语法:

    1. <import resource="其他配置文件路径" />
    2. classpath:类路径(class文件所在的目录)
    3. 在spring的配置文件中要指定其他文件的位置, 需要使用classpath,告诉spring到哪去加载读取文件

    如下,主配置文件

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <import resource="classpath:p6moreconfig/spring-user.xml" />
    5. <import resource="classpath:p6moreconfig/spring-address.xml" />
    6. beans>

    User类的配置文件

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="user" class="com.mycompany.p6moreconfig.User" autowire="byType">
    5. <property name="userName" value="admin" />
    6. <property name="age" value="20" />
    7. bean>
    8. beans>
  • 相关阅读:
    C#常用数据操作方法详解
    ​毕设作品案例-基于JAVA-SSM实现-小程序-商品展示系统-微信外卖小程序-附源码+LW(文档+PPT)+示例视频
    cesium api放大缩小地图
    二维码那点事
    软件测试流程是什么?这题我不会啊
    MySQL 事务隔离级别与锁机制详解
    11.13 训练周记
    k8s-生产级的k8s高可用(2) 25
    Dubbo基本用法-Dubbo Provider配置
    论文阅读笔记 | 三维目标检测——VeloFCN算法
  • 原文地址:https://blog.csdn.net/MinggeQingchun/article/details/122880488