用xml注入service_IOC 详解(XML)

IOC -> XML

概念和作用

程序耦合

在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合

解决耦合思路:反射 + 配置文件,减少 new 关键字的使用

工厂模式解耦

实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用。这个读取配置文件,创建和获取三层对象的类就是工厂。

控制反转

问题一:对象存哪 ?

由于我们是很多对象,肯定要找个集合来存,这时候有 MapList 供选择。由于我们有查找需求,所以选择 Map,把这个 Map称为容器

问题二:什么是工厂 ?

工厂就是负责给我们从容器中获取指定对象的类

问题三:怎么获取对象 ?

主动方式:采用 new 的方式

651e640fe3040c6e17baf2fe91a445cf.png

被动方式:向工厂要,工厂为我们查找或者创建对象(这就是控制反转思想

e205880274344ec86782dbb7ed0df3cc.png

IOC 入门案例

引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
</dependencies>

创建接口及其配置类

public interface AccountService {
    void saveAccount();
}
​
import com.service.AccountService;
public class AccountServiceImpl implements AccountService {
    @Override
    public void saveAccount() {
        System.out.println("调用了 AccountServiceImpl 的 save 方法");
    }
}
​

创建配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="accountService" class="com.service.impl.AccountServiceImpl">          </bean>
</beans>

主方法进行测试

import com.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
public class ApplicationTest {
    public static void main(String[] args) {
        // 使用 ApplicationContext
        ApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
        AccountService accountService = application.getBean("accountService", AccountService.class);
        accountService.saveAccount();
        
        //使用 BeanFactory
        Resource resoure = new ClassPathResource("application.xml");
        BeanFactory factory = new XmlBeanFactory(resoure);
        AccountService as = (AccountService) factory.getBean("accountService");
        as.saveAccount();
    }
}
​

执行结果

3033debcd6f4a1cd173b03ffd034ceda.png

了解常用类

ApplicationCOntext的三个常用类

ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下

FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须要有访问权限)

AnnotationConfigApplicationContext基于注解使用的,它不需要配置文件,采用配置类和各种注解来配置

核心容器的两个接口

ApplicationContext:单例适用,它在构建核心容器时,创建对象采取的策略是采用立即加载,也就是说,只要已读取完配置文件马上就创建配置文件中配置的对象

BeanFactory:多例适用,它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式,也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象

IOC 中的 Bean 标签

bean 标签的常用属性

scope属性详解

证明scope(使用上面定义的 accountService):

<!--测试单例多例-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl" scope="`singleton`"></bean>
//测试 scope:singleton
AccountService accountService1 = application.getBean("accountService", AccountService.class);
AccountService accountService2 = application.getBean("accountService", AccountService.class);
System.out.println(accountService1 == accountService2);*///true
//测试 scope : prototype
AccountService accountService3 = application.getBean("accountService", AccountService.class);
AccountService accountService4 = application.getBean("accountService", AccountService.class);
System.out.println(accountService3 == accountService4);//false

实例化bean的方式

使用默认无参构造函数:在 spring 的配置文件中使用 bean标签,配以 idclass 属性之后,且没有其他属性和标签时采用的是默认构造函数创建 bean对象,此时如果类中没有默认构造函数,则对象无法创建

<bean id="accountService" class="com.service.impl.AccountServiceImpl" scope="singleton"></bean>

使用普通工厂中的方法创建对象:使用某个类中的方法创建对象,并存入 spring 容器中

<!-- factory-bean属性:用于指定实例工厂bean的id -->
<!-- factory-method属性:用于指定实例工厂中创建对象的方法 -->
​
<!--创建工厂 Bean-->
<bean id="instanceFactory" class="com.factory.InstanceFactory"></bean>
<!--使用工厂中的普通方法创建对象-->
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
// java 工厂
public class InstanceFactory {
    private AccountService accountService = new AccountServiceImpl();
    public AccountService getAccountService(){
        return accountService;
    }
}

使用工厂中的静态方法创建对象: 使某个类中的静态方法创建对象,并存入spring容器中

<!-- id属性:指定bean的id,用于从容器中获取 -->
<!-- class属性:指定静态工厂的全限定类名 -->
<!-- factory-method属性:指定生产对象的静态方法 -->

<!--使用静态方法创建对象-->
<bean id="accountService" class="com.factory.StaticFactory" factory-method="getAccountService"></bean>
// java 工厂
public class StaticFactory {
    private static AccountService accountService = new AccountServiceImpl();
    public static AccountService getAccountService(){
        return accountService;
    }
}

Spring 依赖注入

构造函数注入

测试下列情况所使用的 Person

import java.util.Date;
public class Person {
    private String name;
    private int age;
    private Date date;
    
    // 下列情况演示中使用的构造方法
    public Person(String name,int age,Date date){
        this.name = name;
        this.age = age;
        this.date = date;
    } 
}

情况一:index + value / index + ref

<bean id="date" class="java.util.Date"></bean>
<bean id="p" class="com.domain.Person">
    <constructor-arg index="0" value="张三"></constructor-arg>
    <constructor-arg index="1" value="15"></constructor-arg>
    <constructor-arg index="2" ref="date"></constructor-arg>
</bean>

情况二:type + value / type + ref

<bean id="date" class="java.util.Date"></bean>
<bean id="p1" class="com.domain.Person">
    <constructor-arg type="java.lang.String" value="张三"></constructor-arg>
    <constructor-arg type="int" value="15"></constructor-arg>
    <constructor-arg type="java.util.Date" ref="date"></constructor-arg>
</bean>

情况三:name + value / name + ref

<bean id="date" class="java.util.Date"></bean>
<bean id="p2" class="com.domain.Person">
    <constructor-arg name="name" value="张三"></constructor-arg>
    <constructor-arg name="age" value="15"></constructor-arg>
    <constructor-arg name="date" ref="date"></constructor-arg>
</bean>

测试验证

// 测试的代码
ApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
Person p = application.getBean("p", Person.class);
Person p1 = application.getBean("p1", Person.class);
Person p2 = application.getBean("p2", Person.class);
System.out.println(p);
System.out.println(p1);
System.out.println(p2);

bf72b48e5f6a8c72dec66b0d648e2819.png

Set 方法注入

说明:使用的是上面的 Person 类,但是需要添加 Getter / Setter方法,同时跟上面的验证使用的是同样的方法。

<bean id="p3" class="com.domain.Person">
    <property name="name" value="张三"></property>
    <property name="age" value="15"></property>
    <property name="date" ref="date"></property>
</bean>

复杂类型的注入

给数组类型注入

测试下列情况所使用的的 School

import java.util.Arrays;
public class School {
    private String[] schoolNames = new String[3];
    public School() {
    }
    public School(String[] schoolNames) {
        this.schoolNames = schoolNames;
    }
    public String[] getSchoolNames() {
        return schoolNames;
    }
    public void setSchoolNames(String[] schoolNames) {
        this.schoolNames = schoolNames;
    }
    toString();  // 自行补充
}

情况一 :使用构造方法

<bean id="s2" class="com.domain.School">
    <constructor-arg name="schoolNames">
        <array>
            <value>重庆大学</value>
            <value>重庆文理学院</value>
            <value>重庆师范大学</value>
        </array>
    </constructor-arg>
</bean>

情况二:使用 set 方法

<bean id="s1" class="com.domain.School">
    <property name="schoolNames">
        <array>
            <value>重庆大学</value>
            <value>重庆师范大学</value>
            <value>重庆文理学院</value>
        </array>
    </property>
</bean>

List 类型进行注入

测试下列情况所使用的的 Dates

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Dates {
    private List<Date> dates = new ArrayList<>();
    public Dates() {
    }
    public Dates(List<Date> dates) {
        this.dates = dates;
    }
    public List<Date> getDates() {
        return dates;
    }
    public void setDates(List<Date> dates) {
        this.dates = dates;
    }
    toString();  // 自行补充
}

情况一 :使用构造方法

<bean id="dates1" class="com.domain.Dates">
    <constructor-arg name="dates">
        <list>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
        </list>
    </constructor-arg>
</bean>

情况二:使用 set 方法

<bean id="dates2" class="com.domain.Dates">
    <property name="dates">
        <list>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
        </list>
    </property>
</bean>

Set 类型进行注入

测试下列情况所使用的的 Maps

import java.util.*;
public class Dates {
    private Set<Date> dates = new HashSet<>();
    public Dates() {
    }
    public Dates(Set<Date> dates) {
        this.dates = dates;
    }
    public Set<Date> getDates() {
        return dates;
    }
    public void setDates(Set<Date> dates) {
        this.dates = dates;
    }
    toString(); // 自行添加
}

情况一 :使用构造方法

<bean id="set2" class="com.domain.Dates">
    <constructor-arg name="dates">
        <set>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
        </set>
    </constructor-arg>
</bean>

情况二:使用 set 方法

<bean id="set1" class="com.domain.Dates">
    <property name="dates">
        <set>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
            <ref bean="date"></ref>
        </set>
    </property>
</bean>

Map 类型进行注入

测试下列情况所使用的的 Maps

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class Maps {
    private Map<String, Date> map = new HashMap<>();
    public Maps() {
    }
    public Maps(Map<String, Date> map) {
        this.map = map;
    }
    public Map<String, Date> getMap() {
        return map;
    }
    public void setMap(Map<String, Date> map) {
        this.map = map;
    }
    toString();  // 自行添加
}

情况一 :使用构造方法

<bean id="m1" class="com.domain.Maps">
    <constructor-arg name="map">
        <map>
            <entry key="1" value-ref="date"></entry>
            <entry key="2">
                <ref bean="date"></ref>
            </entry>
        </map>
    </constructor-arg>
</bean>

情况二:使用 set 方法

<bean id="m2" class="com.domain.Maps">
    <property name="map">
        <map>
            <entry key="1" value-ref="date"></entry>
            <entry key="2">
                <ref bean="date"></ref>
            </entry>
        </map>
    </property>
</bean>

autowire 属性详解

证明 autowire 属性所使用的类

public class Man {
    private Person person;
    public Man() {
    }
    public Man(Person person) {
        this.person = person;
    }
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
   	toString(); // 自行添加
}
import java.util.Date;
public class Person {
    private String name;
    private int age;
    private Date date;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name,int age,Date date){
        this.name = name;
        this.age = age;
        this.date = date;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    toString(); // 自行添加
}

测试代码:

ApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
//测试 autowire
Person person = application.getBean("person",Person.class);
Man man = application.getBean("man",Man.class);
System.out.println(person);
System.out.println(man);

证明 byName 属性

<bean id="date" class="java.util.Date"></bean>
<bean id="person" class="com.domain.Person">
    <property name="name" value="LEE"/>
    <property name="age" value="20"/>
    <property name="date" ref="date"/>
 </bean>
<bean id="man" class="com.domain.Man" autowire="byName"></bean>

e52b0945b6abfbb2b806c03dd0a969f6.png

证明 byType 属性

情况一 :IOC 容器中只有一个该类型的 bean

<bean id="date" class="java.util.Date"></bean>
<bean id="person" class="com.domain.Person">
    <property name="name" value="LEE"/>
    <property name="age" value="20"/>
    <property name="date" ref="date"/>
 </bean>
<bean id="man" class="com.domain.Man" autowire="byType"></bean>

e52b0945b6abfbb2b806c03dd0a969f6.png

情况二:IOC 容器中有多个该类型的 bean

<bean id="date" class="java.util.Date"></bean>
<bean id="p3" class="com.domain.Person">
    <property name="name" value="张三"></property>
    <property name="age" value="15"></property>
    <property name="date" ref="date"></property>
</bean>
<bean id="person" class="com.domain.Person">
    <property name="name" value="LEE"/>
    <property name="age" value="20"/>
    <property name="date" ref="date"/>
 </bean>
<bean id="man" class="com.domain.Man" autowire="byType"></bean>

ad1fd441e4ab3a99b008e942bc351ffe.png

测试 constructor

情况一:有相对应的构造器

<bean id="date" class="java.util.Date"></bean>
<bean id="person" class="com.domain.Person">
    <property name="name" value="LEE"/>
    <property name="age" value="20"/>
    <property name="date" ref="date"/>
 </bean>
<bean id="man" class="com.domain.Man" autowire="constructor"></bean>

e52b0945b6abfbb2b806c03dd0a969f6.png

情况二:没有相对应的构造器(还是使用情况一的配置,只是修改 Man 类)

public class Man {
    private Person person;
    public Man() {
    }
    public Person getPerson() {
        return person;
    }
    public void setPerson(Person person) {
        this.person = person;
    }
    toString(); // 自行添加
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值