侧边栏壁纸
博主头像
coydone博主等级

记录学习,分享生活的个人站点

  • 累计撰写 306 篇文章
  • 累计创建 51 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

基于XML的IoC

coydone
2022-03-14 / 0 评论 / 0 点赞 / 414 阅读 / 9,358 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2022-04-10,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

IoC概念和作用

控制反转的引入和分析

存储实体类中对象的数据,肯定要找个集合来存。这时候有 Map 和 List 供选择。到底选 Map 还是 List 就看我们有没有查找需求。有查找需求,选 Map。所以我们的答案就是在应用加载时,创建一个 Map,用于存放三层对象。我们把这个 map 称之为容器。工厂就是负责给我们从容器中获取指定对象的类。这时候我们获取对象的方式发生了改变。

原来: 我们在获取对象时,都是采用 new 的方式,是主动的。

现在:我们获取对象时,同时跟工厂要,有工厂为我们查找或者创建对象,是被动的。这种被动接收的方式获取对象的思想就是控制反转,它是 Spring 框架的核心之一。

控制反转的概念和作用

控制反转(Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是Spring框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。

IoC的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。

使用Spring的IoC解耦

案例:业务层和持久层的依赖关系解决。

Spring改造工厂模式

官网:http://spring.io/。

下载地址:http://repo.springsource.org/libs-release-local/org/springframework/spring。

解压:(Spring目录结构:docs:API 和开发规范、libs:jar包和源码、schema:约束)

注意:Spring5 版本是用 JDK8 编写的,所以要求我们的 JDK 版本是 8 及以上。同时 Tomcat 的版本要求 8.5 及以上。

Spring相关Jar包(核心包):

操作步骤

1、创建Maven工程,导入Spring依赖。

<packaging>jar</packaging>

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

2、创建三层架构的包结构,编写dao层和service层接口以及实现类。做到service层调用dao层。

private UserDao userDao = new UserDaoImpl();

UserService userService = new UserServiceImpl();

3、编写Spring的配置文件。

在resources目录下创建名为appicationContext.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">

    <!--把对象的创建交给spring来管理-->
    <bean id="userService" class="com.coydone.service.impl.UserServiceImpl"></bean>
    <bean id="userDao" class="com.coydone.dao.impl.UserDaoImpl"></bean>
</beans>

4、测试。

public static void main(String[] args) {
    //获取spring的IOC核心容器,并根据id获取对象
    //1、获取核心容器对象
    ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    //ApplicationContext ac = new FileSystemXmlApplicationContext("D:\\bean.xml");
    //2、根据id获取Bean对象
    UserService userService = (UserService) ac.getBean("userService");
    UserDao userDao = ac.getBean("userDao", UserDao.class);
    userDao.deleteUser("1");
    userService.deleteUser("1");
}

基于XML的IoC细节

Spring 中工厂的类结构图

BeanFactory和ApplicationContext的区别

BeanFactory才是Spring 容器中的顶层接口。ApplicationContext是它的子接口。

区别:创建对象的时间点不一样。

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

ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");

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

Resource resource = new ClassPathResource("bean.xml");
BeanFactory factory = new XmlBeanFactory(resource);
UserService service = factory.getBean("userService", UserService.class);

ApplicationContext接口的实现类

ApplicationContext的三个常用实现类:

  • ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)

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

  • AnnotationConfigApplicationContext:它是用于读取注解创建容器的。

IoC中bean标签和管理对象细节

bean标签作用:用于配置对象让 Spring 来创建的。

创建Bean的三种方式

1、使用默认构造函数创建。

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

<bean id="userService" class="com.coydone.service.impl.UserServiceImpl">
</bean>

2、使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入Spring容器)。

package com.coydone.factory;

import com.coydone.service.UserService;
import com.coydone.service.impl.UserServiceImpl;

public class InstanceFactory {
    public UserService getUserService(){
        return new UserServiceImpl();
    }
}
<bean id="instanceFactory" class="com.coydone.factory.InstanceFactory">
</bean>
<bean id="userService" factory-bean="instanceFactory" factory-method="getUserService">
</bean>

3、使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入Spring容器)。

public class StaticFactory {
    public static UserService getUserService(){
        return new UserServiceImpl();
    }
}
<bean id="accountService" class="com.coydone.factory.StaticFactory" factory-method="getAccountService">
</bean>

bean的属性

  • id:给对象在容器中提供一个唯一标识。用于获取对象。

  • class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。

  • scope:指定对象的作用范围。

    • singleton:默认值,单例的。

    • prototype:多例的。

    • request:Web项目中,Spring创建一个Bean的对象,将对象存入到 request 域中。

    • session:Web项目中,Spring创建一个Bean的对象,将对象存入到 session 域中。

    • global-session:Web项目中,应用在 Portlet(集群) 环境。如果没有 Portlet 环境,那么globalSession 相当于 session。

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

  • destroy-method:指定类中销毁方法名称。

bean对象的生命周期

单例对象:

  • 出生:当容器创建时对象出生。

  • 活着:只要容器还在,对象一直活着。

  • 死亡:容器销毁,对象消亡。

总结:单例对象的生命周期和容器相同。

多例对象:

  • 出生:当我们使用对象时Spring框架为我们创建。

  • 活着:对象只要是在使用过程中就一直活着。

  • 死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收。

<bean id="userService" class="com.coydone.service.impl.UserServiceImpl"
          scope="prototype" init-method="init" destroy-method="destroy">
</bean>

public static void main(String[] args) {
    //1.获取核心容器对象
    //ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
    //2.根据id获取Bean对象
    UserService as  = (UserService)ac.getBean("userService");
    as.saveAccount();
    //手动关闭容器
    ac.close();
}

依赖注入(DI)

依赖注入的概念

依赖注入:Dependency Injection。它是Spring框架核心IoC的具体实现。

我们的程序在编写时,通过控制反转,把对象的创建交给了Spring,但是代码中不可能出现没有依赖的情况。IoC解耦只是降低他们的依赖关系,但不会消除。

例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用Spring之后,就让Spring来维护了。

在当前类需要用到其他类的对象,由Spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,就称之为依赖注入。

简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。

依赖注入能注入的数据有三类:

  • 基本类型和String。

  • 其他bean类型(在配置文件中或者注解配置过的bean)。

  • 复杂类型/集合类型。

注入的方式

  • 使用构造函数提供。

  • 使用set方法提供。

  • 使用注解提供。

构造函数注入

顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让Spring框架来为我们注入。

使用的标签:constructor-arg

标签出现的位置:bean标签的内部

标签中的属性

  • type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型。

  • index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始。

  • name:用于指定给构造函数中指定名称的参数赋值(常用)。

以上三个用于指定给构造函数中哪个参数赋值。

  • value:用于提供基本类型和String类型的数据。

  • ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象。

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

弊端:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

public class UserServiceImpl implements UserService {
    //如果是经常变化的数据,并不适用于注入的方式
    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;
    }
}

<bean id="userService" class="com.coydone.service.impl.UserServiceImpl">
    <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>

set方法注入(常用)

涉及的标签:property。

出现的位置:bean标签的内部。

标签的属性

  • name:用于指定注入时所调用的set方法名称。

  • value:用于提供基本类型和String类型的数据。

  • ref:用于指定其他的bean类型数据。它指的就是在Spring的IoC核心容器中出现过的bean对象。

优势:创建对象时没有明确的限制,可以直接使用默认构造函数。

弊端:如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

public class UserServiceImpl2 implements UserService {
    //如果是经常变化的数据,并不适用于注入的方式
    private String name;
    private Integer age;
    private Date birthday;
    //添加set()方法
}
<bean id="userService2" class="com.coydone.service.impl.UserServiceImpl2">
    <property name="name" value="TEST" ></property>
    <property name="age" value="21"></property>
    <property name="birthday" ref="now"></property>
</bean>

set方法注入复杂类型/集合类型

用于给List结构集合注入的标签:list、array、set。

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

结构相同,标签可以互换。

public class UserServiceImpl3 implements UserService {
    private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties myProps;
    //省略setter()方法
}

bean.xml编写

<bean id="accountService3" class="com.coydone.service.impl.UserServiceImpl3">
    <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>

自动装配

自动装配:Spring在实例化bean的时候从Spring容器中找到匹配的实例赋值给当前bean的属性。

自动装配的策略有两种:

byName:根据当前Bean的属性名在Spring容器中寻找匹配的对象。如果根据name找到了 bean但是类型不匹配则抛出异常。

byType:根据当前Bean的属性类型在Spring容器中寻找匹配的对象。如果根据类型找到了多个bean会抛出异常。

<!--Student中有Clazz属性-->
<bean id="clazz" class="com.coydone.bean.Clazz"></bean>
<bean id="stu2" class="com.coydone.bean.Student" autowire="byName"></bean>

<bean id="clazz2" class="com.coydone.bean.Clazz"></bean>
<bean id="stu2" class="com.coydone.bean.Student" autowire="byType"></bean>
0

评论区