Spring之IOC应用

第1节 Spring IOC基础

1.1 BeanFactory与ApplicationContext区别

BeanFactory是Spring框架中IoC容器的顶层接⼝,它只是⽤来定义⼀些基础功能,定义⼀些基础规范,⽽
ApplicationContext是它的⼀个⼦接⼝,所以ApplicationContext是具备BeanFactory提供的全部功能
的。
通常,我们称BeanFactory为SpringIOC的基础容器,ApplicationContext是容器的⾼级接⼝,比BeanFactory要拥有更多的功能,⽐如说国际化⽀持和资源访问(xml,java配置类)等等

启动 IoC 容器的⽅式

  • Java环境下启动IoC容器

    • ClassPathXmlApplicationContext:从类的根路径下加载配置⽂件(推荐使⽤)
    • FileSystemXmlApplicationContext:从磁盘路径上加载配置⽂件
    • AnnotationConfigApplicationContext:纯注解模式下启动Spring容器
  • Web环境下启动IoC容器

    • 从xml启动容器
    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
     <display-name>Archetype Created Web Application</display-name>
     <!--配置Spring ioc容器的配置⽂件-->
     <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>classpath:applicationContext.xml</param-value>
     </context-param>
     <!--使⽤监听器启动Spring的IOC容器-->
     <listener>
     <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
     </listener>
    </web-app>
    
    • 从配置类启动容器
    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
     <display-name>Archetype Created Web Application</display-name>
     <!--告诉ContextloaderListener知道我们使⽤注解的⽅式启动ioc容器-->
     <context-param>
     <param-name>contextClass</param-name>
     <paramvalue>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
     </context-param>
    	<!--配置启动类的全限定类名-->
     <context-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>com.demo.edu.SpringConfig</param-value>
     </context-param>
     <!--使⽤监听器启动Spring的IOC容器-->
     <listener>
     <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
     </listener>
    </web-app>
    

1.2 纯xml模式

本部分内容我们不采⽤⼀⼀讲解知识点的⽅式,⽽是采⽤Spring IoC 纯 xml 模式改造我们前⾯⼿写的
IoC 和 AOP 实现,在改造的过程中,把各个知识点串起来。

  • 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
 https://www.springframework.org/schema/beans/spring-beans.xsd">
  • 实例化Bean的三种⽅式

    • ⽅式⼀:使⽤⽆参构造函数
      在默认情况下,它会通过反射调⽤⽆参构造函数来创建对象。如果类中没有⽆参构造函数,将创建失败。
    <!--配置service对象-->
    <bean id="userService" class="com.demo.service.impl.TransferServiceImpl"></bean>
    
    • ⽅式⼆:使⽤静态⽅法创建

    在实际开发中,我们使⽤的对象有些时候并不是直接通过构造函数就可以创建出来的,它可能在创建的过程 中会做很多额外的操作。此时会提供⼀个创建对象的⽅法,恰好这个⽅法是static修饰的⽅法,即是此种情况。

    例如,我们在做Jdbc操作时,会⽤到java.sql.Connection接⼝的实现类,如果是mysql数据库,那么⽤的就 是JDBC4Connection,但是我们不会去写 JDBC4Connection connection = newJDBC4Connection() ,因为我们要注册驱动,还要提供URL和凭证信息,⽤ DriverManager.getConnection ⽅法来获取连接。

    那么在实际开发中,尤其早期的项⽬没有使⽤Spring框架来管理对象的创建,但是在设计时使⽤了⼯⼚模式解耦,那么当接⼊spring之后,⼯⼚类创建对象就具有和上述例⼦相同特征,即可采⽤此种⽅式配置。

    <!--使⽤静态⽅法创建对象的配置⽅式-->
    <bean id="userService" class="com.demo.factory.BeanFactory" factory-method="getTransferService"></bean>
    
    • ⽅式三:使⽤实例化⽅法创建
      此种⽅式和上⾯静态⽅法创建其实类似,区别是⽤于获取对象的⽅法不再是static修 饰的了,⽽是类中的⼀ 个普通⽅法。此种⽅式⽐静态⽅法创建的使⽤⼏率要⾼⼀些。
      在早期开发的项⽬中,⼯⼚类中的⽅法有可能是静态的,也有可能是⾮静态⽅法,当是⾮静态⽅法时,即可 采⽤下⾯的配置⽅式:
    <!--使⽤实例⽅法创建对象的配置⽅式-->
    <bean id="beanFactory" class="com.demo.factory.instancemethod.BeanFactory"></bean>
    <bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean>
    
  • Bean的X及⽣命周期

    • 作⽤范围的改变
      在spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它⽀持配置的⽅式改变作⽤范围。作⽤范围官⽅提供的说明如下图:

    在上图中提供的这些选项中,我们实际开发中⽤到最多的作⽤范围就是singleton(单例模式)和prototype(原型模式,也叫多例模式)。配置⽅式参考下⾯的代码:

    <!--配置service对象-->
    <bean id="transferService"
    class="com.demo.service.impl.TransferServiceImpl" scope="singleton">
    </bean>
    
    • 不同作⽤范围的⽣命周期

    单例模式:singleton

    对象出⽣:当创建容器时,对象就被创建了。

    对象活着:只要容器在,对象⼀直活着。

    对象死亡:当销毁容器时,对象就被销毁了。

    ⼀句话总结:单例模式的bean对象⽣命周期与容器相同。

    多例模式:prototype

    对象出⽣:当使⽤对象时,创建新的对象实例。

    对象活着:只要对象在使⽤中,就⼀直活着。

    对象死亡:当对象⻓时间不⽤时,被java的垃圾回收器回收了。

    ⼀句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。

  • Bean标签属性

    在基于xml的IoC配置中,bean标签是最基础的标签。它表示了IoC容器中的⼀个对象。换句话
    说,如果⼀个对象想让spring管理,在XML的配置中都需要使⽤此标签配置,Bean标签的属性如 下:

    id属性: ⽤于给bean提供⼀个唯⼀标识。在⼀个标签内部,标识必须唯⼀。

    class属性:⽤于指定创建Bean对象的全限定类名。

    name属性:⽤于给bean提供⼀个或多个名称。多个名称⽤空格分隔。

    factory-bean属性:⽤于指定创建当前bean对象的⼯⼚bean的唯⼀标识。当指定了此属性之后,class属性失效。

    factory-method属性:⽤于指定创建当前bean对象的⼯⼚⽅法,如配合factory-bean属性使⽤,则class属性失效。如配合class属性使⽤,则⽅法必须是static的。

    scope属性:⽤于指定bean对象的作⽤范围。通常情况下就是singleton。当要⽤到多例模式时, 可以配置为prototype。

    init-method属性:⽤于指定bean对象的初始化⽅法,此⽅法会在bean对象装配后调⽤。必须是⼀个⽆参⽅法。

    destory-method属性:⽤于指定bean对象的销毁⽅法,此⽅法会在bean对象销毁前执⾏。它只 能为scope是singleton时起作⽤。

  • DI 依赖注⼊的xml配置

    • 依赖注⼊分类

      • 按照注⼊的⽅式分类

        构造函数注⼊:顾名思义,就是利⽤带参构造函数实现对类成员的数据赋值。

        set⽅法注⼊:它是通过类成员的set⽅法实现数据的注⼊。(使⽤最多的)

      • 按照注⼊的数据类型分类

        基本类型和String

        注⼊的数据类型是基本类型或者是字符串类型的数据。

        其他Bean类型

        注⼊的数据类型是对象类型,称为其他Bean的原因是,这个对象是要求出现在IoC容器中的。那么针对当前Bean来说,就是其他Bean了。

        复杂类型(集合类型)

        注⼊的数据类型是Aarry,List,Set,Map,Properties中的⼀种类型。

    • 依赖注⼊的配置实现之构造函数注⼊ 顾名思义,就是利⽤构造函数实现对类成员的赋值。它的使⽤要求是,类中提供的构造函数参数个数必须和配置的参数个数⼀致,且数据类型匹配。同时需要注意的是,当没有⽆参构造时,则必须提供构造函数参数的注⼊,否则Spring框架会报错。

    在使⽤构造函数注⼊时,涉及的标签是 constructor-arg ,该标签有如下属性:

    name:⽤于给构造函数中指定名称的参数赋值。

    index:⽤于给构造函数中指定索引位置的参数赋值。

    value:⽤于指定基本类型或者String类型的数据。

    ref:⽤于指定其他Bean类型的数据。写的是其他bean的唯⼀标识。

    • 依赖注⼊的配置实现之set⽅法注⼊

    顾名思义,就是利⽤字段的set⽅法实现赋值的注⼊⽅式。此种⽅式在实际开发中是使⽤最多的注⼊⽅式。

    在使⽤set⽅法注⼊时,需要使⽤ property 标签,该标签属性如下:

    name:指定注⼊时调⽤的set⽅法名称。(注:不包含set这三个字⺟,druid连接池指定属性名称)
    value:指定注⼊的数据。它⽀持基本类型和String类型。

    ref:指定注⼊的数据。它⽀持其他bean类型。写的是其他bean的唯⼀标识。

    复杂数据类型注⼊ ⾸先,解释⼀下复杂类型数据,它指的是集合类型数据。

    集合分为两类,⼀类是List结构(数组结构),⼀类是Map接⼝(键值对) 。

    接下来就是注⼊的⽅式的选择,只能在构造函数和set⽅法中选择,我们的示例选⽤set⽅法注⼊。

    在List结构的集合数据注⼊时, array , list , set 这三个标签通⽤,另外注值的 value 标签内部
    可以直接写值,也可以使⽤ bean 标签配置⼀个对象,或者⽤ ref 标签引⽤⼀个已经配合的bean
    的唯⼀标识。

    在Map结构的集合数据注⼊时, map 标签使⽤ entry ⼦标签实现数据注⼊, entry 标签可以使⽤key和value属性指定存⼊map中的数据。使⽤value-ref属性指定已经配置好的bean的引⽤。同时 entry 标签中也可以使⽤ ref 标签,但是不能使⽤ bean 标签。⽽ property 标签中不能使⽤ref或者 bean 标签引⽤对象

    1.3 xml与注解相结合模式

    注意:

    1)实际企业开发中,纯xml模式使⽤已经很少了

    2)引⼊注解功能,不需要引⼊额外的jar

    3)xml+注解结合模式,xml⽂件依然存在,所以,spring IOC容器的启动仍然从加载xml开始

    4)哪些bean的定义写在xml中,哪些bean的定义使⽤注解

    第三⽅jar中的bean定义在xml,⽐如德鲁伊数据库连接池⾃⼰开发的bean定义使⽤注解

  • xml中标签与注解的对应(IoC)

xml形式对应的注解形式
标签@Component(“accountDao”),注解加在类上bean的id属性内容直接配置在注解后⾯如果不配置,默认定义个这个bean的id为类的类名⾸字⺟⼩写;另外,针对分层代码开发提供了@Componenet的三种别名@Controller、@Service、@Repository分别⽤于控制层类、服务层类、dao层类的bean定义,这四个注解的⽤法完全⼀样,只是为了更清晰的区分⽽已
标签的scope属性@Scope(“prototype”),默认单例,注解加在类上
标签的initmethod属性@PostConstruct,注解加在⽅法上,该⽅法就是初始化后调⽤的⽅法
标签的destorymethod属性@PreDestory,注解加在⽅法上,该⽅法就是销毁前调⽤的⽅法
  • DI 依赖注⼊的注解实现方式

@Autowired(推荐使⽤)

@Autowired为Spring提供的注解,需要导⼊包

org.springframework.beans.factory.annotation.Autowired。

@Autowired采取的策略为按照类型注⼊。

public class TransferServiceImpl {
 @Autowired
 private AccountDao accountDao;
}

如上代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注⼊进来。这
样会产⽣⼀个问题,当⼀个类型有多个bean值的时候,会造成⽆法选择具体注⼊哪⼀个的情况,
这个时候我们需要配合着@Qualifier使⽤。

@Qualifier告诉Spring具体去装配哪个对象。

public class TransferServiceImpl {
 @Autowired
 @Qualifier(name="jdbcAccountDaoImpl")
 private AccountDao accountDao;
}

这个时候我们就可以通过类型和名称定位到我们想注⼊的对象。

@Resource

@Resource 注解由 J2EE 提供,需要导⼊包 javax.annotation.Resource。

@Resource 默认按照 ByName ⾃动注⼊。

public class TransferService {
 @Resource
 private AccountDao accountDao;
 @Resource(name="studentDao")
 private StudentDao studentDao;
 @Resource(type="TeacherDao")
 private TeacherDao teacherDao;
 @Resource(name="manDao",type="ManDao")
 private ManDao manDao;
}
  • 如果同时指定了 name 和 type,则从Spring上下⽂中找到唯⼀匹配的bean进⾏装配,找不
    到则抛出异常。
  • 如果指定了 name,则从上下⽂中查找名称(id)匹配的bean进⾏装配,找不到则抛出异
    常。
  • 如果指定了 type,则从上下⽂中找到类似匹配的唯⼀bean进⾏装配,找不到或是找到多个,
    都会抛出异常。
  • 如果既没有指定name,⼜没有指定type,则⾃动按照byName⽅式进⾏装配;

注意:

@Resource 在 Jdk 11中已经移除,如果要使⽤,需要单独引⼊jar包

<dependency>
 <groupId>javax.annotation</groupId>
 <artifactId>javax.annotation-api</artifactId>
 <version>1.3.2</version>
</dependency>

1.4 纯注解模式

改造xm+注解模式,将xml中遗留的内容全部以注解的形式迁移出去,最终删除xml,从Java配置类启动

对应注解

@Configuration 注解,表名当前类是⼀个配置类

@ComponentScan 注解,替代 context:component-scan

@PropertySource,引⼊外部属性配置⽂件

@Import 引⼊其他配置类

@Value 对变量赋值,可以直接赋值,也可以使⽤ ${} 读取资源配置⽂件中的信息

@Bean 将⽅法返回对象加⼊ SpringIOC 容器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值