IoC容器
本章介绍了Spring的控制反转(IoC)容器。java
1.1。Spring IoC容器和Bean简介
本章介绍了反转控制(IoC)原则的Spring框架实现。
IoC也称为依赖注入(DI)。
在此过程当中,对象能够经过①构造函数参数(),②工厂方法的参数③或在构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即,与它们一块儿使用的其余对象) 。 而后,容器在建立bean时注入那些依赖项。linux
什么叫作控制反转? 举例: 定义一个接口 CacheService.java 做为顶级的缓存接口 定义 RedisCacheServiceImpl.java 实现redis缓存 定义 LocalCacheServiceImpl.java 实现本地缓存 这时候,若是没有Spring框架的话那咱们的代码 CacheService cache = new RedisCacheServiceImpl(); cache.set("xxx","xxx") ... ... 等到想替换其余缓存方式的时候就改动代码 CacheService cache = new LocalCacheServiceImpl(); 这也就是咱们说的面向接口编程,咱们写代码须要本身主动建立对象来引用不一样的实现 可是IOC出现以后,代码编写就不同了,咱们直接拿Spring中代码举例: @Service("localCache") public class LocalCacheServiceImpl implements CacheService{} @Service("redisCache") public class RedisCacheServiceImpl implements CacheService{} @Autowired @Qualifier("redisCache") CacheService cache; 这样编写以后,new关键字不见了,多了一些陌生的注解, 简单来讲这些注解, @Service是把被标记了的服务告诉IOC容器, @Autowired是告诉IOC容器我想要引用什么服务 当一个接口有多个实现类的时候咱们就须要 @Qualifier 来指定注入对应名称的服务 经过解释发现,咱们经过注解将服务都报告给了IOC容器,也经过注解引用了想要的服务。 也就是咱们所依赖对象的获取方式被IOC容器控制了, 由以前的咱们主动建立对象到如今的IOC容器给咱们注入,这个过程就是 控制反转
上边只是演示了Spring IOC的一种方式注入对象
在org.springframework.beans和org.springframework.context包是Spring框架的IoC容器的基础。
BeanFactory 接口提供了一种高级配置机制,可以管理任何类型的对象。 ApplicationContext 是BeanFactory的子接口。 它增长了:
与Spring的AOP功能轻松集成
消息资源处理(用于国际化)
事件发布
应用层特定的上下文,例如WebApplicationContext 用于Web应用程序中的。redis
简而言之,BeanFactory提供了配置框架和基本功能,并ApplicationContext增长了更多针对企业的功能。该ApplicationContext是对一个完整的超集BeanFactory,并在Spring的IoC容器的描述本章独占使用。spring
总的来讲ApplicationContext是一个大而全的类,包括不少经常使用的功能, 只要获取到容器中的ApplicationContext的对象就能够直接获取对象,发布消息等,
在Spring中,构成应用程序主干并由SpringIoC容器管理的对象称为bean。Bean是由Spring IoC容器实例化,组装和以其余方式管理的对象。不然,bean仅仅是应用程序中许多对象之一。Bean及其之间的依赖关系反映在容器使用的配置元数据中。编程
注意:注册为bean的对象才能够用Spring的注解来注入它的依赖项
1.2。容器概述
该org.springframework.context.ApplicationContext接口表明Spring IoC容器,并负责实例化,配置和组装Bean。容器经过读取元数据配置来获取有关要实例化,配置和组装哪些对象的指令。配置元数据以XML,注解或Java代码表示。它使您可以表达组成应用程序的对象以及这些对象之间的丰富相互依赖关系。json
几种配置元数据的方式 ①xml <bean id="..." class="..."> ②注解 @Service @Component 等 ③java code @Configuration public class CommonConfig { @Bean public Validator validator(){} }
Spring提供了该接口(ApplicationContext)的几种实现。在独立应用程序中, 一般建立ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext的实例。尽管XML是定义元数据配置的传统格式,可是您能够经过提供少许XML配置来声明性地启用对这些其余元数据格式的支持,从而指示容器将Java注解或代码用做元数据格式。windows
Spring大方向来讲是两部分 首先全部的须要被注册的bean,解析bean 而后实例化bean和解决依赖 ApplicationContext 各类实现类的区别其实就是第一步:查找和解析bean的方式有区别 好比有从xml中解析,有从Configuration类中解析,因此在当前解析方式上增长一些扫描路径来实现其余类型的元数据解析是彻底能够的 好比:经过xml配置下边一行 <context:component-scan base-package="org.springframework.example"/> 可让Spring扫描org.springframework.example包下的带注解的类,从而进行xml和注解的双解析
1.2.1。配置元数据
Spring IoC容器使用元数据配置的方式来实现容器功能。此元数据的配置表示您做为应用程序开发人员如何告诉Spring容器实例化,配置和组装应用程序中的对象。缓存
传统上,配置元数据以简单直观的XML格式提供,这是本章大部份内容用来传达Spring IoC容器的关键概念和功能的内容。app
基于XML的元数据不是配置元数据的惟一容许形式。 Spring IoC容器自己与实际写入此配置元数据的格式彻底脱钩。现在,许多开发人员为他们的Spring应用程序选择基于Java的配置的方式(Spring 3.0开始)。框架
基于注解的配置:Spring 2.5引入了对基于注解的配置元数据的支持。 基于Java的配置:从Spring3.0开始,Spring JavaConfig项目提供的许多功能 成为核心Spring Framework的一部分。 所以,您可使用Java而不是XML文件来定义应用程序类外部的bean。 要使用这些新功能,请参阅 @Configuration, @Bean, @Import,和@DependsOn注释。
如下示例显示了基于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 id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> </beans> 该id属性是标识单个bean定义的字符串。 该class属性定义Bean的类型,并使用彻底限定的类名。 该id属性的值是指协做对象。在此示例中未显示用于引用协做对象的XML。有关更多信息,请参见 依赖项。
1.2.2。实例化容器
提供给ApplicationContext构造函数的一个或多个位置路径是资源字符串,可以让容器从各类外部资源(例如本地文件系统,Java CLASSPATH等)加载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
了解了Spring的IoC容器以后,您可能想了解更多有关Spring的 Resource抽象(如参考资料中所述),它提供了一种方便的机制,用于从URI语法中定义的位置读取InputStream。具体而言,Resource如应用程序上下文和资源路径中所述, 路径用于构造应用程序上下文。
如下示例显示了服务层对象(services.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 id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl"> <property name="accountDao" ref="accountDao"/> <property name="itemDao" ref="itemDao"/> </bean> </beans>
如下示例显示了数据访问对象daos.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 id="accountDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao"> </bean> <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao"> </bean> </beans>
在前面的示例中,服务层的PetStoreServiceImpl类由两个数据访问对象JpaAccountDao和JpaItemDao(基于JPA对象关系映射标准)组成。
该property name元素是指JavaBean属性的名称,以及ref元素指的是另外一个bean定义的名称。id和ref元素之间的这种联系表达了协做对象之间的依赖性。
组装基于XML的配置元数据
拥有多个XML文件可能颇有用。一般,每一个单独的XML配置文件都表明体系结构中的逻辑层或模块。
您可使用应用程序上下文构造函数从全部这些XML片断中加载bean定义。
Resource如上一节中所示,该构造函数具备多个位置。或者,使用一个或多个出现的<import/>元素从另外一个文件中加载bean定义。如下示例显示了如何执行此操做:
<beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>
在前面的例子中,外部bean定义是从三个文件加载: services.xml,messageSource.xml,和themeSource.xml。 全部位置路径是相对于当前的定义文件来讲的,所以services.xml相对于当前的文件路径必须在同一个目录或类路径位置,而messageSource.xml并themeSource.xml必须在resources目录下方的位置。 如您所见,斜杠被忽略。可是,鉴于这些路径是相对的,最好不要使用任何斜线。
能够但不建议使用相对的“../”路径引用父目录中的文件。这样作会建立对当前应用程序外部文件的依赖关系。 特别是,不建议对classpath:URL(例如classpath:../services.xml)使用此引用,在URL 中,运行时解析过程会选择“最近”的类路径根, 而后查看其父目录。类路径配置的更改可能致使选择其余错误的目录。 这段没咋看懂,追了下源码 // <import resource="classpath:../resources/bean.xml"/> //找到 resource 后边的路径 String location = ele.getAttribute("resource"); if (!StringUtils.hasText(location)) { getReaderContext().error("Resource location must not be empty", ele); return; } //补充路径中的 $ 符包括的内容 e.g. "${user.dir}" location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location); Set<Resource> actualResources = new LinkedHashSet<>(4); // 判断当前url是不是绝对路径仍是相对路径 // classpath*: classpath: 开头的都是绝对路径 // 可以成功 new URL(location) 不报错也是绝对路径 // new URI(location).isAbsolute() 返回true也是绝对路径 boolean absoluteLocation = false; try { absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute(); } catch (URISyntaxException ex) { } if (absoluteLocation) { 绝对路径就要判断是否是 classpath*: 开头 是classpath*: 开头 一种解析方法 不然是另外一种解析方法 } else { }
您可使用绝对路径来代替相对路径:例如file:C:/config/services.xml或classpath:/config/services.xml。可是,请注意,您正在将应用程序的配置耦合到特定的绝对位置。最好为这样的绝对位置保留一个间接性—例如,经过“${…}”占位符,这些占位符在运行时根据JVM系统属性解析。
好比应用名称是application 文件为 file.json 在windows下路径为 c:/myApp/application/file.json 在linux下问 /home/xxx/application/file.json 若是在代码不变的状况下,必须将 application文件名前半截的东西配置成可变的 ${prefixPath}/application/file.json 在运行是根据配置不一样的变量找到不一样的文件
命名空间自己提供了导入指令功能。Spring提供的一系列XML名称空间(例如context和util名称空间)中提供了超出普通bean定义的其余配置功能。
beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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"
1.2.3。使用容器
ApplicationContext是一个维护bean定义以及相互依赖的注册表的高级工厂的接口。
使用方法 T getBean(String name, Class<T>requiredType),您能够检索bean的实例。
用ApplicationContext读bean定义和访问它们,以下例所示: // 读取配置文件 建立bean ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml"); // 获取bean对应的实例 PetStoreService service = context.getBean("petStore", PetStoreService.class); // 使用 List<String> userList = service.getUsernameList();
你能够在相同的ApplicationContext上混合和匹配这些阅读器,从不一样的配置源读取bean定义。
这句话我理解为 同一个ApplicationContext 既支持读取xml配置的Bean 也支持读取注解注册的Bean
而后,您能够getBean用来检索bean的实例。该ApplicationContext 接口还有其余几种检索bean的方法,可是理想状况下,您的应用程序代码永远不要使用它们。实际上,您的应用程序代码应该根本不调用该 getBean()方法,所以彻底不依赖于Spring API。例如,Spring与Web框架的集成为各类Web框架组件(例如控制器和JSF管理的Bean)提供了依赖注入,使您能够经过元数据(例如自动装配注释)声明对特定Bean的依赖。
通常状况下开发简单使用 @Autowired 彻底能够作到自动注入了, 只有本身定制功能的时候可能会用到ApplicationContext中的方法
本文由博客群发一文多发等运营工具平台 OpenWrite 发布