Spring入门:IOC和DI (基于XML)

Spring的IOC

IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想——降低程序间的耦合,削减依赖关系。
在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

下面演示通过spring的核心容器获取对象。

  • 新建maven工程,导入依赖:
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>
  • 创建业务层接口和实现类
public interface IAccountService {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao = new AccountDaoImpl(); //此处并未消除程序耦合

    public AccountServiceImpl(){
        System.out.println("对象创建了");
    }

    public void  saveAccount(){
        accountDao.saveAccount();
    }
}
  • 创建持久层接口和实现类
/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {

    public  void saveAccount(){

        System.out.println("保存了账户");
    }
}

在resource目录下配置bean.xml,让 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--把对象的创建交给spring来管理-->
    <bean id="accountService" class="com.zhu.service.impl.AccountServiceImpl"></bean>

    <bean id="accountDao" class="com.zhu.dao.impl.AccountDaoImpl"></bean>
</beans>

测试类:
使用核心容器ApplicationContext对象来获取bean

/**
 * 模拟一个表现层,用于调用业务层
 */
public class Client {

     * @param args
     */
    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
        as.saveAccount();
    }
}

执行效果就是由spring的核心容器为我们创建了对象,而不是在对象中直接new出来,并且使用xml来配置而不是写死在代码中,降低了程序的耦合。

ApplicationContext的三个常用实现类

在这里插入图片描述

  • ClassPathXmlApplicationContext:可以加载类路径下的配置文件,要求配置文件必须在类路径下。
  • FileSystemXmlApplicationContext:可以加载磁盘任意路径下的配置文件(必须有访问权限)。
  • AnnotationConfigApplicationContext:用于读取注解创建容器。

ApplicationContext与BeanFactory的区别

在这里插入图片描述

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

  • BeanFactory:
    BeanFactory是Spring 容器中的顶层接口,它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才创建对象。

Spring管理Bean的细节

1.创建Bean的三种方式

先在上面的Demo稍作修改,把dao的部分移除,只留下service:

public class AccountServiceImpl implements IAccountService {



    public AccountServiceImpl(){
        System.out.println("对象创建了");
    }

    public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行!");
    }
  }

测试方法:

    public static void main(String[] args) {
        //1.获取核心容器对象
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        as.saveAccount();

        //手动关闭容器
        ac.close();
    }

方式1:默认构造函数创建

在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时,采用的就是默认构造函数创建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">
    
    <bean id="accountService" class="com.zhu.service.impl.AccountServiceImpl"></bean>
    
</beans>

在这里插入图片描述
如果在AccountServiceImpl中的构造方法为有参,则运行时报错:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

方式2:使用实例工厂的方法创建对象

模拟一个实例工厂,创建业务层实现类:

/**
 * 模拟一个工厂类
 */
public class InstanceFactory {
    public IAccountService getAccountService(){
        return new AccountServiceImpl();
    }
}

必须先有工厂实例对象,才能获取业务对象。
配置方法:

    <bean id="instanceFactory" class="com.zhu.factory.InstanceFactory"></bean>
    <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>

如此,可以先把工厂的创建交给 spring 来管理,然后再使用工厂的 bean 来获取业务bean。
与方式一的区别是,业务bean不是直接反射来实例化的,而是由工厂创建的。

factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。

方式3:使用工厂中的静态方法创建

将方式2中的工厂替换为静态工厂:

/**
 * 模拟一个工厂类(
 */
public class StaticFactory {

    public static IAccountService getAccountService(){

        return new AccountServiceImpl();
    }
}

这种情况需要调用类(而不是实例对象)的方法来获取bean,并存入spring容器。
配置方法:

    <bean id="accountService" class="com.zhu.factory.StaticFactory" factory-method="getAccountService"> 
    </bean>

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

2.Bean的作用范围

bean标签的 scope属性用于指定bean的作用范围:

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

取值:

  • singleton单例(默认值),作用范围就是整个引用。
  • prototype多例,每次访问对象时,都会重新创建对象实例。
  • request:作用于web应用的请求范围
  • session:作用于web应用的会话范围
  • global-session:作用于集群环境的会话范围(全局会话范围),非集群环境时即为session

3.Bean的生命周期

  • 单例对象: scope=“singleton”

对象出生:当应用加载,创建容器时,对象就被创建。
对象活着:容器存在在则对象一直存活。
对象死亡:当应用卸载,销毁容器时,对象被销毁。

  • 多例对象: scope=“prototype”

对象出生:当使用对象时,创建新的对象实例。
对象活着:使用中一直存活。
对象死亡:垃圾回收器回收。

如:

public class AccountServiceImpl implements IAccountService {
    public AccountServiceImpl(){
        System.out.println("对象创建了");
    }

    public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行!");
    }

    public void  init(){
        System.out.println("对象初始化了。。。");
    }
    public void  destroy(){
        System.out.println("对象销毁了。。。");
    }

}
    <bean id="accountService" class="com.zhu.service.impl.AccountServiceImpl"
          scope="prototype" init-method="init" destroy-method="destroy"></bean>

init-method: 指定类中的初始化方法名称。
destroy-method: 指定类中销毁方法名称。

Spring的依赖注入(DI)

依赖注入(Dependency Injection),是 spring 框架的核心——IOC 的具体实现。
spring对依赖关系的维护称之为依赖注入。

能注入的数据:有三类

  • 基本类型和String
  • 其他bean类型(在配置文件中或注解 配置过的bean)
  • 复杂类型/集合类型

注入的方式:有三种

  • 使用构造函数提供
  • 使用set方法提供
  • 使用注解提供

修改业务实现类的构造方法:

/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    //如果是经常变化的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;

    public AccountServiceImpl(String name,Integer age,Date birthday){
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行了。。。"+name+","+age+","+birthday);
    }
}

构造函数注入

bean标签的内部使用标签 constructor-arg

    <bean id="accountService" class="com.zhu.service.impl.AccountServiceImpl">
        <constructor-arg name="name" value="乔布斯"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>

    <!-- 配置一个日期对象 -->
    <bean id="now" class="java.util.Date"></bean>

标签中的属性
type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,从0开始
name:用于指定给构造函数中指定名称的参数赋值 (常用)
以上三个用于指定参数=============================
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。它指的是在spring的Ioc核心容器所管理 的bean对象

测试结果
在这里插入图片描述

  • 优势:
    在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。

setter方法注入

为实现类提供setter方法:
在这里插入图片描述
配置方法:

    <bean id="accountService2" class="com.zhu.service.impl.AccountServiceImpl2">
        <property name="name" value="林志玲" ></property>
        <property name="age" value="21"></property>
        <property name="birthday" ref="now"></property>
    </bean>

    <!-- 配置一个日期对象 -->
    <bean id="now" class="java.util.Date"></bean>

涉及的标签 :property
name:用于指定注入时所调用的set方法名称(把set去掉,大写首字母改小写)
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。

优点:只有当对象是需要被注入的时候它才会帮助我们注入依赖,而不是在初始化的时候就注入

集合类型的注入

以上都是基本类型或简单类型,若类的属性是集合类型呢?
在这里插入图片描述
配置方法:

    <bean id="accountService3" class="com.zhu.service.impl.AccountServiceImpl3">
        <property name="myStrs">
            <set>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </set>
        </property>

        <property name="myList">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>

        <property name="mySet">
            <list>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </list>
        </property>

        <property name="myMap">
            <props>
                <prop key="testC">ccc</prop>
                <prop key="testD">ddd</prop>
            </props>
        </property>

        <property name="myProps">
            <map>
                <entry key="testA" value="aaa"></entry>
                <entry key="testB">
                    <value>BBB</value>
                </entry>
            </map>
        </property>
    </bean>
  • 用于给List结构集合注入的标签:
    list array set

  • 用于个Map结构集合注入的标签:
    map props

    结构相同,标签可以互换

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值