详解SpringIOC容器的基本配置 - Go语言中文社区

详解SpringIOC容器的基本配置


今天我们要分享的主题是关于Spring IOC(控制反转)的相关内容。

详解SpringIOC容器的基本配置Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式)轻量级开源框架。控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。 控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)。依赖注入应用比较广泛。

1、实例化ApplicationContext

Spring提供了两种IOC容器的实现类型。一种是Bean工厂(Bean factory),还有一种更高级的称为应用程序上下文ApplicationContext,它是对bean工厂兼容的扩展。它提供比bean工厂更高级的特性,同时保持基本特性的兼容。

Applicationcontext继承自BeanFactory接口,除了包含BeanFactory的所有功能之外,在国际化支持、资源访问(如URL和文件)、事件传播等方面进行了良好的支持,被推荐为Java EE应用之首选,可应用在Java APP与Java Web中。

Applicationcontext仅仅是一个接口,你必须实例化一个接口的实现。在ApplicationContext接口的众多实现类中,有3个是我们经常用到的,并且使用这3个实现类也基本能满足我们Java EE应用开发中的绝大部分需求。

详解SpringIOC容器的基本配置

这些实现类的主要区别就时装载Spring配置文件实例化ApplicationContext容器的方式不同,在ApplicationContext实例化后,同样通过getBean方法从ApplicationContext容器中获取装配好的Bean实例以供使用。下面我们通过代码来熟悉这些实现方式:

(1)ClassPathXmlApplicationContext

我们使用ClassPathXmlApplicationContext来实现applicationContext,创建applicationConetxt放置在classpath路径下,内容如下:

详解SpringIOC容器的基本配置其中,userDao对应的是one.applicationcontext.UserDao类,这个类很简单,源代码如下:

详解SpringIOC容器的基本配置

然后创建一个类为ApplicationContextTest.java类,完成对ApplicationContext的实例,并加载配置文件,获取该类的实例对象,调用say方法。

详解SpringIOC容器的基本配置

此时我们的applicationContext.xml存放的目录是在classes下:

(2)FileSystemXmlApplicationContext

当然,我们也可以将其放置在E盘下,此时我们需要用到的类就是:FileSystemXmlAp..了。代码如下:

详解SpringIOC容器的基本配置(3)XmlWebApplicationContext

在Java项目中通过ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext手动实例化ApplicationContext容器通常是不二之选。但对于Web项目就不行了,Web项目的启动是由相应的Web服务器负责的,因此,在Web项目中ApplicationContext容器的实例化工作最好交给Web服务器来完成,而此时使用的类就是XmlWebApplicationContext。我们在spring的源代码中可以找到contextLoader.properties文件,里面有一句默认的配置:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

在源码中,通过ContextLoader.class 的initWebApplicationContext方法的281行,我们可以找到其调用了createWebApplicationContext方法,在createWebApplicationContext方法中,又调用了Class<?> contextClass = determineContextClass(sc); 在determineContextClass方法里,我们可以看到如下代码:

详解SpringIOC容器的基本配置

通过getProperties方法获取的对象就是webapplicationContext.class.name对应的xmlWebApplicationContext的实现。我们断点了一下这个contextClassName 他的值就是:

详解SpringIOC容器的基本配置

也就是说xmlWebApplicationContext就是webApplicationContext的默认实现。也就证实了我们的理论。下面我们来看一下如何配置监听器完成容器的加载。

在web环境下,我们需要在web.xml中配置spring容器的监听器,他负责spring容器的初始化工作,在这个过程中就会调用XmlWebApplicationContext,读取默认的配置文件路径,当然,这个配置文件的路径我们可以在web.xml制定,配置如下:

详解SpringIOC容器的基本配置

下面,将我们的应用部署在tomcat服务器下,为了证明我们的实例对象userDao被spring容器加载完成,我们给UserDao加一个构造方法,然后等服务启动后看一下这个构造方法是否被调用,如果被调用了,就说明spring容器在web环境在创建成功。

详解SpringIOC容器的基本配置

启动服务:

详解SpringIOC容器的基本配置

以上我们就讲述了关于ApplicationContext应用程序上下文的初始化过程,以及3种常用的实现方式。并且针对xmlWebApplicationContext,我们还通过源代码的方式讲解了它的出处,如果对这方面感兴趣的同学也可以看一下源代码的执行过程,加深对application实例化的理解。下一节我们要讲的是,如何配置springIOC容器的各种Bean对象。

2、配置Bean

Spring为我们提供了一个IOC容器帮助我们管理应用bean,我们可以通过xml文件,注解等多种方式完成配置bean,根据项目的大小,我们可以根据功能将bean的配置文件分割成多个,当然也可以集中写在一起。

(1)配置简单属性

其实在上一节中,我们就使用到了bean的配置如图:

详解SpringIOC容器的基本配置

每个bean都提供了一个唯一的名称或者ID,以及一个类的全名,这样就可以使spring的IOC容器对其进行实例化。如图中的userDao对应的类就是one.applicationcontext.UserDao,spring容器通过反射机制完成对bean的实例化,这是一个最简单的bean配置,如果我们的bean有属性的话,可以使用<properties>元素配置其属性,然后通过<value>元素配置属性的值,但<value>标签只适用于基本类型数据的属性,对于应用类型的属性,要使用<ref>标签,例如,加入我们有一个类UserService,他有两个属性,一个是username,一个是UserDao;如果我们想通过IOC帮助我们将属性的值注入进去的话,我们应该怎么做呢:

<1>为属性添加set和get方法(底层机制需要)

详解SpringIOC容器的基本配置<2>在配置文件中添加bean,并使用<prioperty>注入属性

详解SpringIOC容器的基本配置

然后我们在Test.java中进行测试,看能否如我们所愿,将username输出,并调用userDao的say方法:

详解SpringIOC容器的基本配置

这是我们使用set的方式对属性进行注入的,我们都知道,属性的初始化也可以在构造方法中完成,所以我们还可以使用<constructor-arg>元素声明,通过构造方法来配置bean的属性例如:

详解SpringIOC容器的基本配置

配置文件是:

详解SpringIOC容器的基本配置

然后执行测试结果也是一样的,但在这里要注意的问题就是,<constructor-arg>没有name属性,因为构造程序参数是基于位置的。

从spring2.0开始,添加了一个更加便利的定义属性的简写,使用p schema像<bean>元素中的属性那样定义bean属性,可以缩短xml的配置行,例如:

详解SpringIOC容器的基本配置

需要注意的问题是,如果使用这种方式,我们需要保证我们的UserService是有无参的构造方法的,之前我们使用构造方法注入参数时因为重写了构造方法所以再使用这种方式会报错:Could not instantiate bean class [two.configbean.UserService]: No default constructor found; nested exception is java.lang.NoSuchMethodException: two.configbean.UserService.<init>();只要为类新增无参构造方法即可解决该问题。

(2)配置常用集合

List ,set和map是几种比较常见的集合类型的接口,对于每一种的集合类型,java都提供多种实现,在spring中也提供了一组标记来对他们进行配置,我们依旧哪UserService类做参考,为其加上这几个集合的属性,看一下如何进行配置。首先是List,在UserSerivice中加入一个List<Object> 因为泛型是Object类型的,所以我们可以在集合中添加任意类型的数据例如:

详解SpringIOC容器的基本配置

详解SpringIOC容器的基本配置

详解SpringIOC容器的基本配置

Properties和Map差不多,区别在于它的关键字和值始终都是字符串:

详解SpringIOC容器的基本配置


(3)配置注意事项

之前我们讲解了关于简单的bean对象的配置以及常见集合的配置,在这里,我们需要讲解一些注意事项。

<1>我们之前使用的构造方法<constructor-arg>来完成属性的注入,没有name属性,因为他的参数是基于位置的,但考虑一些复杂的情况,假如我们为我们的bean指定了多个构造方法,spring又会选择哪个构造方法来作为属性注入的方法呢?Spring会调用匹配参数最合适的构造方法,即类型和位置都最接近真实值的方法。但尽管如此,有些情况下仍然存在一些歧义,对于<constructor-arg>,我们可以通过type和index属性加以描述,帮助spring查找预期的构造程序,例如:

详解SpringIOC容器的基本配置

<2>默认情况下,spring将集合中所有元素都作为字符串对待,如果你不打算将集合元素作为字符串使用,需要对他们制定数据类型,例如:

详解SpringIOC容器的基本配置

3、认识FactoryBean

(1)FactoryBean简单扩展

Spring中有两种类型的Bean,一种是普通的bean,另外一种是FactoryBean,这两种bean都被spring容器管理,但工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,而是该FactoryBean的getObject方法所返回的对象,在spring框架内部,有很多地方有FactoryBean的实现类,例如:在IOC容器中创建一个Hibernate会话工厂时,可以使用LocalSessionFactoryBean.FactoryBean它对于spring来说是很重要的,用户可以通过实现该工厂接口来定制实例化Bean的逻辑,它有3个接口方法:

详解SpringIOC容器的基本配置

现在我们自己来定义一个工厂bean,尝试扩展FacoryBean,例如,创建一个CarFactoryBean类,根据参数返回不同的car:

详解SpringIOC容器的基本配置

注意该方法的getObject方法返回的是Car类型的对象,且内部含有car类型的属性需要我们在配置时进行依赖注入。

详解SpringIOC容器的基本配置

这样在客户端执行getBean,返回的对象不再是CarFactoryBean实例,而是Car实例,如下:

详解SpringIOC容器的基本配置

有了这样的实现,我们可以灵活的控制实例对象的返回,假如我们需要自己做一个数据源的FactoryBean,接受不同的参数,根据参数获取不同的数据源,也是轻而易举就可以实现的了,代码简写:

详解SpringIOC容器的基本配置

然后配置文件如下:

详解SpringIOC容器的基本配置

最后执行测试:

详解SpringIOC容器的基本配置

当然,案例中的代码比较简单,考虑的情况不全面,且一般情况下,不需要我们自动手动的写太多自定义的工厂Bean,因为他们是框架专用的,无法用在springIOC容器之外。

4、自动装配

(1)使用XML自动装配Bean

Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。由于autowire可以针对单个bean进行设置,因此可以让有些bean使用autowire,有些bean不采用。autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以给我们的配置文件减减肥。

<bean>的autowire属性有如下六个取值,他们的说明如下:

1、 No:即不启用自动装配。Autowire默认的值。

2、 byName:通过属性的名字的方式查找JavaBean依赖的对象并为其注入。比如说类Computer有个属性printer,指定其autowire属性为byName后,Spring IoC容器会在配置文件中查找id/name属性为printer的bean,然后使用Seter方法为其注入。

3、 byType:通过属性的类型查找JavaBean依赖的对象并为其注入。比如类Computer有个属性printer,类型为Printer,那么,指定其autowire属性为byType后,Spring IoC容器会查找Class属性为Printer的bean,使用Seter方法为其注入。

4、 constructor:通byType一样,也是通过类型查找依赖对象。与byType的区别在于它不是使用Seter方法注入,而是使用构造子注入。

5、 autodetect:在byType和constructor之间自动的选择注入方式。

6、 default:由上级标签<beans>的default-autowire属性确定。

例如:

详解SpringIOC容器的基本配置

我们并没有为roleService配置其roleDao的属性,而是使用了autowire中的byType,为其自动装配,也是可以为其装配的,这就是通过属性的类型查找javabean依赖的对象进行注入。当然除此之外,我们还可以有byName等。

(2)使用注解自动装配Bean

使用xml配置autowire进行自动装配的确很好用,但也有自身的限制,不够灵活且只能通过类型或者名称自动装配,如果这两种策略都不能满足需求的时候,我们可以使用注解@Autowired或者@Resource来设置方法,构造方法,字段甚至任意方法自动装配特定的属性,要求jdk1.5以上。

如果要使用注解完成自动装配,首先我们需要在IOC容器中注册一个AutowiredAnnotationBeanPostProcessor实例,当然这个工作只要我们简单的在配置文件中添加<context:annotation-config>就可以完成。

然后我们尝试将@Autowire注解放置在类的set方法上,构造方法上和属性上,spring容器都可以为我们自动的装配。

5、其他配置

(1)Bean的继承

Spring允许子bean继承父bean,子bean从父bean继承bean配置,包括bean属性和<bean>元素的属性,避免重复配置。例如,定义一个类Son,有两个属性id和name,通过依赖注入将name注入,而id继承自父bean,父bean可以是一个不存在的bean。

(2)自动扫描组件

自动扫描组件可以利用特殊的注解,从classpath中自动的扫描,检测和实例化你的组件,指示spring管理组件的基本注解是@Component 其他特殊的典型化注解包括@Repository @Service @Controller 他们分为持久层 服务层和表现层。

@Service用于标注业务层组件

@Controller用于标注控制层组件,比如struts中的action

@Repository用于标注数据访问组件,如DAO组件

@Component泛指组件,当组件不好归类的时候,我们可以使用它进行标注

要完成自动扫描,我们好需要在xml配置中引入以下信息:

a) context命名空间以及这个命名空间的schema文件

b)<context:component-scan base-package=”com.lvpeng” /> 打开组件扫描配置项base-package表示自动扫描com.lvpeng包以及它的子包。

<context:annotation-config /> 可以不必打开,因为<context:component-scan>完成了annotation处理的注册

详解SpringIOC容器的基本配置

小结:

在本篇文章中,我们学习了springIOC容器的基本bean配置,从一开始的应用上下文的创建,到bean的基本配置,集合的配置,然后我们学习了对FactoryBean的扩展和使用,随后我们学习和认识了关于xml和注解两种装配bean的方式,可以看出xml是比较容易读的,但注解的功能也是非常强大的,配置也非常方便。最后我们补充了其他一些配置包括bean的继承和自动扫描等功能。SpringIOC中还有很多的知识需要我们来学习,这一章的目的只是为大家展示一个大体的框架,有机会我们会重点的介绍关于IOC的高级特性与内部机制。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/hiz1990/article/details/69666290
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-01 23:14:42
  • 阅读 ( 1867 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢