欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java开发中Spring IOC容器的使用详解

程序员文章站 2022-04-15 17:56:14
详解Spring IOC文章内容输出来源:拉勾教育Java高薪训练营看前如果没有基础的话建议先看上一篇手动实现IOC和AOP思路Spring IoC基础Spring IoC有两个重要的概念:beans.xml:定义实例化对象的类全限定类名以及类之间依赖关系的描述。BeanFactory:IOC容器,通过反射技术来实例化对象并维护对象之间的依赖关系。1.BeanFactory与ApplicationContext区别BeanFactory是Spring框架中IoC容器的顶层接口,它只是用来...

详解Spring IOC



文章内容输出来源:拉勾教育Java高薪训练营


看前如果没有基础的话建议先看上一篇手动实现IOC和AOP思路

Spring IoC基础

Spring IoC有两个重要的概念:

  1. beans.xml:定义实例化对象的类全限定类名以及类之间依赖关系的描述。
  2. BeanFactory:IOC容器,通过反射技术来实例化对象并维护对象之间的依赖关系。

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启动容器

    • 从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> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </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> <param- value>org.springframework.web.context.support.AnnotationConfigWebAppli cationContext</param-value> </context-param> <!--配置启动类的全限定类名--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.lagou.edu.SpringConfig</param-value> </context-param> <!--使用监听器启动Spring的IOC容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app> 

2. 纯xml模式

2.1 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"> 
2.2 实例化Bean的三种方式
  • 方式一:使用无参构造

在默认情况下,它会通过反射调用无参构造函数来创建对象。如果类中没有无参构造函数,将创建失败。

<!--配置service对象--> <bean id="userService" class="com.lagou.service.impl.TransferServiceImpl"> </bean> 
  • 方法二:使用静态方法构建
//Java代码实例 public class BeanFactory{ private static UserService userService; public static UserService getTransferService(){ return userService; } } 
<!--使用静态方法创建对象的配置方式--> <bean id="userService" class="com.lagou.factory.BeanFactory" factory-method="getTransferService"></bean> 
  • 方法三:使用实例化方法构建
//Java代码实例 public class BeanFactory{ private UserService userService; public UserService getTransferService(){ return userService; } } 
<!--使用实例方法创建对象的配置方式--> <bean id="beanFactory" class="com.lagou.factory.instancemethod.BeanFactory"></bean> <bean id="transferService" factory-bean="beanFactory" factory-method="getTransferService"></bean> 
2.3 Bean的作用范围及生命周期
  • 作用范围

在spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它支持配置的方式改变作用范围。

作用范围官方提供的说明如下图:

在上图中提供的这些选项中,我们实际开发中用到最多的作用范围就是**singleton(单例模式)和 prototype(**原型模式,也叫多例模式)。

配置方式参考下面的代码:

 <!--scope属性就是描述作用范围--> <bean id="transferService" class="com.lagou.service.impl.TransferServiceImpl" scope="singleton"> </bean> 
  • 生命周期

    • 单例模式:singleton

      单例模式的bean对象生命周期与容器相同。

    • 多例模式:prototype

      多例模式的bean对象,spring框架只负责创建,不负责销毁。

2.4 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时起作用。
2.5 DI 依赖注入的xml配置
  • 依赖注入分类

    • 按照注入的方式分类

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

        // 使用要求是,类中提供的构造函数参数个数必须和配置的参数个数一致,且数据类型匹配。同时需要注意的是,当没有无参构造时,则必须提供构造函数参数的注入,否则Spring框架会报错。 public class JdbcAccountDaoImpl implements AccountDao{ private ConnectionUtils connectionUtils; private String name; private int sex; private float money; public JdbcAccountDaoImpl(ConnectionUtils connectionUtils, String name, int sex, float money){ this.connectionUtils = connectionUtils; this.name = name; this.sex = sex; this.money = money; } } //xml name:用于给构造函数中指定名称的参数赋值。index:用于给构造函数中指定索引位置的参数赋值。 // 		value:用于指定基本类型或者String类型的数据。ref:用于指定其他Bean类型的数据。写的是其他bean的唯一标识。 <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcAccountDaoImpl"> <constructor-arg name="connectionUtils" ref="connectionUtils"/> <constructor-arg name="name" value="zhangsan"/> <constructor-arg name="sex" value="1"/> <constructor-arg name="money" value="100.6"/> </bean> 
      • set方法注入:它是通过类成员的set方法实现数据的注入。(使用最多的)

        //利用字段的set方法实现赋值的注入方式。此种方式在实际开发中是使用最多的注 入方式。 public class JdbcAccountDaoImpl implements AccountDao{ private ConnectionUtils connectionUtils; private String name; private int sex; private float money; public void setConnectionUtils(ConnectionUtils connectionUtils){ this.ConnectionUtils = connectionUtils; } public void setName(String name){ this.name = name; } ... } <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcAccountDaoImpl"> <property name="connectionUtils" ref="connectionUtils"/> <property name="name" value="zhangsan"/> <property name="sex" value="1"/> <property name="money" value="100.6"/> </bean> 
    • 按照注入的数据类型分类

      • 基本类型和String:name-value
      • 其他Bean类型:name-ref
      • 复杂类型(集合类型)
      <!--set注入复杂数据类型--> <property name="myArray"> <array> <value>array1</value> <value>array2</value> <value>array3</value> </array> </property> <property name="myMap"> <map> <entry key="key1" value="value1"/> <entry key="key2" value="value2"/> <entry key="key3" value="value3"/> </map> </property> <property name="mySet"> <set> <value>set1</value> <value>set2</value> <value>set3</value> </set> </property> <property name="myProperties"> <props> <prop>prop1</prop> <prop>prop2</prop> <prop>prop3</prop> </props> </property> 

      在相同结构的集合数据注入时,内部标签是通用的,例如array , list , set 这三个标签通用。

3. xml与注解相结合模式

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

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

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

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

  • 第三方jar中的bean定义在xml,比如德鲁伊数据库连接池

  • 自己开发的bean定义使用注解

3.1 xml中标签与注解的对应(IoC)
xml形式 对应的注解形式
标签 @Component(“accountDao”),注解加在类上 bean的id属性内容直接配置在注解后面如果不配置,默认定义个这个bean的id为类 的类名首字母小写; 另外,针对分层代码开发提供了@Componenet的三种别名@Controller、 @Service、@Repository分别用于控制层类、服务层类、dao层类的bean定义,这 四个注解的用法完全一样,只是为了更清晰的区分而已
标签的 scope属性 @Scope(“prototype”),默认单例,注解加在类上
标签的init- method 属性 @PostConstruct,注解加在方法上,该方法就是初始化后调用的方法
标签的destory- method 属性 @PreDestory,注解加在方法上,该方法就是销毁前调用的方法
3.2 DI 依赖注入到的注解实现方式
  • @Autowired(推荐使用)
public class TransferServiceImpl { @Autowired private AccountDao accountDao; } public class TransferServiceImpl { @Autowired @Qualifier(name="jdbcAccountDaoImpl") private AccountDao accountDao; } 

如上第一个代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注入进来。

这样会产生一个问题,当一个类型有多个bean值的时候,会造成无法选择具体注入哪一个的情况, 这个时候我们需要配合着@Qualifier使用。

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

  • @Resource

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

且不常用,有需要的可以自行了解。

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

4. 纯注解模式

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

//xml中遗留的内容,目的就是将其全部以注解的形式迁移出去,最终删除xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" 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
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd "> <!--开启注解扫描,base-package指定扫描的包路径--> <context:component-scan base-package="com.lagou.edu"/> <!--引入外部资源文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--第三方jar中的bean定义在xml中--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> </beans> 

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

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

@PropertySource,引入外部属性配置文件

@Import 引入其他配置类

@Value 对变量赋值,可以直接赋值,也可以使用 ${} 读取资源配置文件中的信息 @Bean 将方法返回对象加入 SpringIOC 容器

@Configuration @ComponentScan({"com.lagou.edu"}) @PropertySource({"classpath:jdbc.properties"}) /*@Import()*/ public class SpringConfig { @Value("${jdbc.driver}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource createDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } } 

这样,我们就成功将xml中的内容全部用注解的形式迁移出去了。

本文地址:https://blog.csdn.net/weixin_43871142/article/details/108248877

相关标签: Java IOC