理解Spring中的getBean()

理解Spring中的getBean(),第1张

在本文中,我们将详细介绍从BeanFactory中获取bean的多种方式。

简单地说,正如方法的名称所表达的, getBean() 负责从Spring IOC容器中获取bean实例。

首先,让我们定义一些用于测试的Spring bean。创建spring IOC容器有多种方式,但是在本文中,我们将使用基于注释的Java配置:

我们创建了两个bean。 Lion 具有默认的单例作用域。Tiger被显式地设置为 prototype 。另外,我们为每个bean定义了名称,这些名称将在后边的实例中使用。

BeanFactory提供了getBean()方法的5个方法,我们将在下面的小节中研究。

让我们看看如何使用名称获取 Lion Bean实例:

在此方法中,我们根据bean名称获取bean,如果在spring ico容器中存在和bean,则返回 Object 类的实例。否则,抛出如下异常NoSuchBeanDefinitionException。

主要的缺点是,在获取bean之后,我们必须将它转换为所需的类型。如果返回的bean的类型与我们期望的不同,则可能会产生异常。

假设我们试图用“tiger”这个名字来得到“lion”。当我们将结果转换为lion时,它会抛出一个ClassCastException:

在这里,我们需要指定所请求bean的名称和类型:

与31的方法相比,此方法更安全,因为我们可以编译阶段就发现错误而不是在运行阶段。

使用 getBean() 的第三种方式, 仅指定bean类型就足够了

在这种情况下,我们需要 特别注意可能存在的歧义

在上面的示例中,由于 Lion 和 Tiger都 实现了 Animal 接口,因此仅指定类型不足以明确确定结果。因此,我们得到一个 NoUniqueBeanDefinitionException 。即在同一个IOC 容器中,如果有相同类型的多个bean,则不能通过类型获取bean。

除了bean名称,我们还可以传递构造函数参数:

这个方法有点不同,因为它只适用于具有原型作用域的bean。

在单例的情况下,我们将得到BeanDefinitionStoreException异常。

因为原型bean,每次从spring ioc容器中获取bean都会返回一个新创建的实例,所以我们可以在调用getBean()时动态地提供构造函数参数:

正如我们所看到的,根据我们在请求bean时指定的第二个参数,每个Tiger都有不同的名称。

此方法类似于上一个方法,但是我们需要将类型而不是名称作为第一个参数传递:

与34相似, 此方法仅适用于具有原型作用域的bean

getBean()尽管是在BeanFactory接口中定义的,但是getBean()方法大部分是通过ApplicationContext访问。通常,我们在应用程序中不希望直接使用getBean()方法。

Bean应该由容器管理。如果我们想使用它们中的一个,我们应该依赖依赖注入,而不是直接调用ApplicationContextgetBean()。这样,我们就可以避免将应用程序逻辑与与框架相关的细节混合在一起。

在本快速教程中,我们从 BeanFactory 接口浏览了 getBean() 方法的所有实现,并描述了每种方法的优缺点。

new calculate();

应该写成

SimpleCalculator calculate = new SimpleCalculator();

然后给 calculate 赋值

然后调用 calculatecalculate()

最后的

Systemoutprintln(calculateresult);

要写成 calculategetResult()

楼主你这错误太多了,还是别着急研究 bean,先把 java 构造相关的基础搞明白吧,要不然告诉你你都不知道怎么改……

1jsp页面如果想要根据id直接查询信息的话,可能会需要这样的代码

2而应用类Spring框架之后如上图的NewsService里面是没有实例化过的NewsDao的,这样上面图中的方法就执行不了

3那假如想要使用NewsServcie中的方法,就需要去找Spring,在Action因为设置了setter方法注入所以可以直接获得实例化好的对象,那在jsp中呢?

4首先你需要有一个jar包,形如spring-web-320M2jar,将此包加入build Path并部署或者直接复制到WEB-INF/lib下,这是spring应用在web项目时需要用到的jar包

然后在jsp页面中导入相关的工具类:

<%@ page import="orgspringframeworkwebcontextsupportWebApplicationContextUtils"%><%@ page import="orgspringframeworkwebcontextWebApplicationContext"%>

5最后通过以下语句获取配置文件中相应的Bean

WebApplicationContext wac = WebApplicationContextUtilsgetRequiredWebApplicationContext(thisgetServletContext()); NewsService service = (NewsService)wacgetBean("newsService");

注意getBean()方法中传入的是配置文件中的Bean的id

这样就可以在页面中访问Spring的Bean了,同时也可以访问service的方法了

基于注解的配置提供了一种XML设置的可替代方式,它依赖于字节码元数据来连接组件,而不是用尖括号声明的方式。代替使用XML来描述bean连接,开发者通过将注解使用在相关的类,方法或字段声明中,将配置移动到了组件类本身的内部。正如在“Example: The RequiredAnnotationBeanPostProcessor”那节提到的那样,使用 BeanPostProcessor 与注解结合是扩展Spring IoC容器的的常见方法。例如,Spring 20引入了 @Required 注解来执行需要的属性的可能性。Spring 25使以同样地通用方法来驱动Spring的依赖注入变为可能。本质上来说, @Autowired 提供了如345小节描述的同样的能力。“Autowiring collaborators”但更细粒度的控制和更广的应用性。Spring 25也添加对JSR-250注解的支持,例如, @PostConstruct 和 @PreDestroy

。Spring 30添加了对JSR-330,包含在 javaxinject 包内的注解(Java的依赖注入)的支持,例如 @Inject 和 @Named 。关于这些注解的细节可以在相关的小节找到。

跟以前一样,你可以作为单独的bean定义来注册它们,但也可以通过在一个基于XML的Spring配置(注入包含上下文命名空间)中包含下面的标签来隐式的注册它们:

(隐式注册的后处理器包括 AutowiredAnnotationBeanPostProcessor , CommonAnnotationBeanPostProcessor , PersistenceAnnotationBeanPostProcessor 和前面提到的 RequiredAnnotationBeanPostProcessor 。)

@Required 注解应用到bean属性的setter方法上,例子如下:

这个注解仅仅是表明受影响的bean属性必须在配置时通过显式的bean定义或自动组装填充。如果受影响的bean属性没有填充,容器会抛出一个异常,这允许及早明确的失败,避免 NullPointerExceptions 或后面出现类似的情况。仍然建议你在bean类本身加入断言,例如,加入到初始化方法中。这样做可以强制这些需要的引用和值,甚至是你在容器外部使用这个类的时候。

你可以将 @Autowired 注解应用到构造函数上。

正如预料的那样,你也可以将 @Autowired 注解应用到“传统的”setter方法上:

你也可以应用注解到具有任何名字和/或多个参数的方法上:

你也可以应用 @Autowired 到字段上,甚至可以与构造函数混合用:

通过给带有数组的字段或方法添加 @Autowired 注解,也可以从 ApplicationContext 中提供一组特定类型的bean:

同样也可以应用到具有同一类型的集合上:

只要期望的key是 String ,那么类型化的Maps就可以自动组装。Map的值将包含所有期望类型的beans,key将包含对应的bean名字:

默认情况下,当没有候选beans可获得时,自动组装会失败;默认的行为是将注解的方法,构造函数和字段看作指明了需要的依赖。这个行为也可以通过下面的方式去改变。

你也可以对那些已知的具有可解析依赖的接口使用 @Autowired : BeanFactory , ApplicationContext , Environment , ResourceLoader , ApplicationEventPublisher 和 MessageSource 。这些接口和它们的扩展接口,例如 ConfigurableApplicationContext 或 ResourcePatternResolver ,可以自动解析,不需要特别的设置。

因为根据类型的自动装配可能会导致多个候选目标,所以在选择过程中进行更多的控制经常是有必要的。一种方式通过Spring的 @Primary 注解来完成。当有个多个候选bean要组装到一个单值的依赖时, @Primary 表明指定的bean应该具有更高的优先级。如果确定一个'primary' bean位于候选目标中间,它将是那个自动装配的值。

假设我们具有如下配置,将 firstMovieCatalog 定义为主要的 MovieCatalog 。

根据这样的配置,下面的 MovieRecommender 将用 firstMovieCatalog 进行自动装配。

对应的bean定义如下:

当有多个实例需要确定一个主要的候选对象时, @Primary 是一种按类型自动装配的有效方式。当需要在选择过程中进行更多的控制时,可以使用Spring的 @Qualifier 注解。为了给每个选择一个特定的bean,你可以将限定符的值与特定的参数联系在一起,减少类型匹配集合。在最简单的情况下,这是一个纯描述性值:

@Qualifier 注解也可以指定单个构造函数参数或方法参数:

对应的bean定义如下。限定符值为"main"的bean被组装到有相同值的构造函数参数中。

对于回退匹配,bean名字被认为是默认的限定符值。因此你可以定义一个id为 main 的bean来代替内嵌的限定符元素,会有同样的匹配结果。然而,尽管你可以使用这个约定根据名字引用特定的beans,但是 @Autowired 从根本上来讲是使用可选的语义限定符来进行类型驱动注入的。这意味着限定符的值,即使回退到bean名称,总是缩小语义类型匹配的集合;它们没有从语义上将一个引用表达为一个唯一的bean id。好的限定符值是"main"或"EMEA"或"persistent",表达一个特定组件的性质,这个组件是独立于bean id 的,即使前面例子中像这个bean一样的匿名bean会自动生成id。

正如前面讨论的那样,限定符也可以应用到类型结合上,例如, Set<MovieCatalog> 。在这个例子中,根据声明的限定符匹配的所有beans作为一个集合进行注入。这意味着限定符不必是唯一的;它们只是构成过滤标准。例如,你可以定义多个具有同样限定符值"action"的 MovieCatalog ,所有的这些都将注入到带有注解 @Qualifier("action") 的 Set<MovieCatalog> 中。

你可以创建自己的定制限定符注解。简单定义一个注解,在你自己的定义中提供 @Qualifier 注解:

然后你可以在自动装配的字段和参数上提供定制的限定符:

接下来,提供候选bean定义的信息。你可以添加 <qualifier/> 标记作为 <bean/> 标记的子元素,然后指定匹配你的定制限定符注解的类型和值。类型用来匹配注解的全限定类名称。或者,如果没有名称冲突的风险,为了方便,你可以使用简写的类名称。下面的例子证实了这些方法。

在310小节,“类路径扫描和管理组件”中,你将看到一个基于注解的替代方法,在XML中提供限定符元数据。特别地,看3108小节,“用注解提供限定符元数据”。

在某些情况下,使用没有值的注解就是足够的。当注解为了通用的目的时,这是非常有用的,可以应用到跨几个不同类型的依赖上。例如,当网络不可用时,你可以提供一个要搜索的离线目录。首先定义一个简单的注解:

然后将注解添加到要自动装配的字段或属性上:

现在bean定义只需要一个限定符类型:

你也可以定义接收命名属性之外的定制限定符注解或代替简单的值属性。如果要注入的字段或参数指定了多个属性值,bean定义必须匹配所有的属性值才会被认为是一个可自动装配的候选目标。作为一个例子,考虑下面的注解定义:

这种情况下 Format 是枚举类型:

要自动装配的字段使用定制限定符进行注解,并且包含了两个属性值: genre 和 format 。

最后,bean定义应该包含匹配的限定符值。这个例子也证实了bean元属性可以用来代替 <qualifier/> 子元素。如果可获得 <qualifier/> ,它和它的属性优先级更高,如果当前没有限定符,自动装配机制会将 <meta/> 内的值作为备用,正如下面的例子中的最后两个bean定义。

除了 @Qualifier 注解外,也可以使用Java的泛型类型作为限定符的一种暗示方式。例如,假设你有如下配置:

假设上面的beans实现了一个泛型接口,例如, Store<String> 和 Store<Integer> ,你可以 @Autowire Store 接口,泛型将作为限定符使用:

当自动装配 Lists , Maps 和 Arrays 时,也会应用泛型限定符:

CustomAutowireConfigurer 是一个能使你注册自己的定制限定符注解类型的 BeanFactoryPostProcessor ,即使它们不使用Spring的 @Qualifier 注解进行注解。

AutowireCandidateResolver 通过下面的方式决定自动装配的候选目标:

当多个beans符合条件成为自动装配的候选目标时,"primary" bean的决定如下:如果在候选目标中某个确定的bean中的 primary 特性被设为 true ,它将被选为目标bean。

Spring也支持使用JSR-250 @Resource 对字段或bean属性setter方法进行注入。这是在Java EE 5和6中的一种通用模式,例如在JSF 12管理的beans或JAX-WS 20的端点。Spring对它管理的对象也支持这种模式。

@Resource 采用名字属性,默认情况下Spring将名字值作为要注入的bean的名字。换句话说,它遵循 by-name 语义,下面的例子证实了这一点:

如果没有显式的指定名字,默认名字从字段名或setter方法中取得。在字段情况下,它采用字段名称;在setter方法情况下,它采用bean的属性名。因此下面的例子将名字为 movieFinder 的bean注入到它的setter方法中:

在 @Resource 特有的没有显式名字指定的情况下,类似于 @Autowired , @Resource 会进行主要的匹配类型来代替指定名字的bean并解析已知的可解析依赖: BeanFactory , ApplicationContext , ResourceLoader , ApplicationEventPublisher 和 MessageSource 接口。

因此在下面的例子中, customerPreferenceDao 字段首先查找名字为 customerPreferenceDao 的bean,然后回退到主要的类型为 CustomerPreferenceDao 的类型匹配。"context"字段会注入基于已知的可解析依赖类型 ApplicationContext 。

CommonAnnotationBeanPostProcessor 不仅识别 @Resource 注解,而且识别JSR-250生命周期注解。在Spring 25引入了对这些注解的支持,也提供了在初始化回调函数和销毁回调函数中描述的那些注解的一种可替代方式。假设 CommonAnnotationBeanPostProcessor 在Spring的 ApplicationContext 中注册,执行这些注解的方法在生命周期的同一点被调用,作为对应的Spring生命周期接口方法或显式声明的回调方法。在下面的例子中,缓存会预先放置接近初始化之前,并在销毁之前清除。

我们将定义在 元素的 或 元素内部的 Bean,称为“内部 Bean”。

我们可以通过 setter 方式注入内部 Bean。此时,我们只需要在 标签下的 元素中,再次使用 元素对内部 Bean 进行定义,格式如下。

注意:内部 Bean 都是匿名的,不需要指定 id 和 name 的。即使制定了,IoC 容器也不会将它作为区分 Bean 的标识符,反而会无视 Bean 的 Scope 标签。因此内部 Bean 几乎总是匿名的,且总会随着外部的 Bean 创建。内部 Bean 是无法被注入到它所在的 Bean 以外的任何其他 Bean 的。

下面我们就通过一个实例,演示下如何使用 setter 方法注入内部 Bean。

1 新建一个名为 my-spring-demo2 的 Java 项目。

2 在 netbianchengc 包中,创建一个名为 Dept 的类,代码如下。

3 在 netbianchengc 包下,创建一个名为 Employee 的类,代码如下。

4 在 src 目录下创建 Spring 配置文件 Beansxml,配置如下。

5 在 netbianchengc 包下,创建一个名为 MainApp 的类,代码如下。

6 执行 MainApp 中的 main() 方法,控制台输出如下。

我们可以通过构造方法注入内部 Bean。此时,我们只需要在 标签下的 元素中,再次使用 元素对内部 Bean 进行定义,格式如下。

下面我们就通过一个实例,演示下如何在通过构造方法的方式注入内部 Bean。

1 新建一个名为 my-spring-demo3 的 Java 项目。

2 在 netbianchengc 包中,创建一个名为 Dept 的类,代码如下。

3 在 netbianchengc 包下,创建一个名为 Employee 的类,代码如下。

4 在 src 目录下创建 Spring 配置文件 Beansxml,配置如下。

5 在 netbianchengc 包下,创建一个名为 MainApp 的类,代码如下。

6 执行 MainApp 中的 main() 方法,控制台输出如下。

以上就是关于理解Spring中的getBean()全部的内容,包括:理解Spring中的getBean()、javabean 初学,怎么加一个Main 测试Bean、如何调用spring配置文件手动注入的bean等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/web/9674058.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-30
下一篇2023-04-30

发表评论

登录后才能评论

评论列表(0条)

    保存