Spring 注入 Bean 的 7 种方式,还有谁不会?-

Spring 注入 Bean 的 7 种方式,还有谁不会?-,第1张

我们谈到Spring的时候一定会提到IOC容器、DI依赖注入,Spring通过将一个个类标注为Bean的方法注入到IOC容器中,达到了控制反转的效果。那么我们刚开始接触Bean的时候,一定是使用xml文件,一个一个的注入,就例如下面这样。

我们的项目一般很大的话,就需要成千上百个Bean去使用,这样写起来就很繁琐。那么Spring就帮我们实现了一种通过注解来实现注入的方法。只需要在你需要注入的类前面加上相应的注解,Spring就会帮助我们扫描到他们去实现注入。

一般情况下,注入Bean有一个最直白,最易懂的方式去实现注入,下面废话先不多说,先贴代码。

与xml有一点不同,这里在Test中,实例化的不再是ClassPathXmlApplicationContext,而是获取的AnnotationConfigApplicationContext实例。

上面的代码中MyBean也就是我们需要Spring去管理的一个Bean,他只是一个简单的类。而MyConfiguration中,我们首先用@Configuration注解去标记了该类,这样标明该类是一个Spring的一个配置类,在加载配置的时候会去加载他。

在MyConfiguration中我们可以看到有一个方法返回的是一个MyBean的实例,并且该方法上标注着@Bean的注解,标明这是一个注入Bean的方法,会将下面的返回的Bean注入IOC。

我们在生成一个Bean实例的时候,可以使用Bean的构造方法将Bean实现注入。直接看代码

这里我们可以发现,和一般方式注入的代码不一样了,我们来看看新的注解都是什么意思:

简单粗暴,直接翻译过来的意思就是自动装配:wrench:,还不理解为什么叫自动装配:wrench:?看了下一个注解的解释你就知道了。若是在这里注入的时候指定一个Bean的id就要使用@Qualifier注解

什么??这翻译过来是零件,怎么感觉像是修 汽车 ??是的,Spring管理Bean的方法就是修 汽车 的方式。我们在需要将一个类变成一个Bean被Spring可以注入的时候加上注解零件@Conmonent,那么我们就可以在加载Bean的时候把他像零件一样装配:wrench:到这个IOC 汽车 上了

在这里我们还有几个其他的注解也可以实现这个功能,也就是细化的@Component:

还是翻译,零件扫描,我们去看看括号里的“零件仓库”里面,哪些“零件”(类)需要被装载,Spring就会去扫描这个包,将里面所有标注了@Component的类进行注入。

这里的通过构造方法进行注入就很好理解了,我们在装配MyBean这个零件的时候,突然发现他必须在AnotherBean的基础上才能安装到IOC里面,那么我们就在每次装配MyBean的时候自动装配:wrench:一个AnotherBean进去。举个:chestnut:吧:

还是以 汽车 为例,我们在踩油门出发之前,是不是必须发车??这里的AutoWired的内容就像发车,你不发车,这个油门你踩断都没有用,他都不会走。

我们可以在一个属性的set方法中去将Bean实现注入,看代码吧

同上一个,就不贴了

这里我们发现在setter方法上我们有一个@AutoWired,与上面不同的是,我们不会在实例化该类时就自动装配:wrench:这个对象,而是在显式调用setter的时候去装配。

我们前面两种注入的方式诸如时间不同,并且代码较多,若是通过属性,即就是

这里我们可以看到我们这个类中需要使用AnotherBean这个实例对象,我们可以通过@AutoWired去自动装配它。

这里我们将MyBeanList进行了注入,对List中的元素会逐一注入。下面介绍另一种方式注入List

注入与List中泛型一样的类型,会自动去匹配类型,及时这里没有任何List的感觉,只是String的类型,但他会去通过List的Bean的方式去注入。

同样这里也具有两种方式去注入Map类型Bean,且第二种的优先值高于第一种

以上就是Bean通过注解注入的几种方式,大家可以对比着xml注入的方式去看。

beans包提供了以编程方式管理和 *** 作bean的基本功能 而context包增加了ApplicationContext 它以一种更加面向框架的方式增强了BeanFactory的功能

context包的基础是位于ntext包中的ApplicationContext接口 它是由BeanFactory接口派生而来的 提供了BeanFactory的所有功能 为了以一种更面向框架的方式工作 使用分层和继承关系的上下文 context包还提供了一下的功能

a MessageSource 对I N消息的访问

b 资源访问 例如URL和文件

c 事件传递给是吸纳了ApplicationListener接口的bean

d 载入多个(有继承关系)上下文 使得每一个上下文都专注于一个特定的层是 比如应用的web层

国际化支持

ApplicationContext扩展了MessageSource接口 因而提供了messaging的功能(I N或者国际化) 同NestingMessageSource一起使用 还能处理分级的信息 这些是spring提供的处理信息的基本接口

当一个ApplicationContext被加载时 它会自动查找在context中定义的MessageSource bean 这个bean必须交做messageSource 如果找了这样一个bean 所有对上述方法的调用将被委托给找到的messageSource 如果没有找到messageSource ApplicationContext将会尝试查找他的父亲是否包含有同名的bean 如果有 它将把找到的bean作为MessageSource 如果他没有找到任何的信息处理源 他会创建一个StaticMessageSource

Spring目前提供了两个MessageSource的实现 他们是

ResourceBundleMessageSource和StaticMessageSource 两者都实现了NestingMessageSource一边能够处理嵌套的信息 StaticMessageSource很少被使用 但是他提供了编程的方式向source增加信息 我们经常使用的是ResourceBundleMessageSource

在Spring中使用资源

ApplicationContext继承了ResourceLoader接口 在这个接口中 定义了getResource()方法 如下

Resource getResource(String location)

该方法返回一个资源句柄 这个句柄应该总是一个可重复使用的资源描述符 允许多次调用getInputStream()

getResource()方法的参数是一个资源访问地址 例如

file:\c:/test data

classpath:test data(从classpath路径中查找test dat文件并返回他的资源句柄)

WEB INF/test dat

注意 getResource()方法返回的Resource句柄并不意味着资源实际存在 你需要调用Resource接口的exists()方法判断资源是否存在

Resource提供了与协议无关的特性

事件传递

ApplicationContext中的时间处理是通过AppcationEvent类和ApplicationListener接口来提供的 如果上下文中部署了一个实现了ApplicationListener接口的bean 每次一个ApplicationEvent发布到ApplicationContext时 那个bean就会被通知 实质撒谎功能 这是标准的Observer设计模式

Spring提供的三个标准事件

a ContextRefreshedEvent

当ApplicationContext已经初始化或刷新后发送的事件 这里初始化意味着 所有的bean被装载 singleton被预实例化 以及ApplicationContext已经准备好

b ContextClosedEvent

当使用ApplicationContext的close()方法结束上下文的时候发送的事件 这里意味着 singleton被销毁

c RequestHandledEvent

一个与web相关的事件 告诉所有的bean一个HTTP请求已经被响应了(这个时间将会在一个请求结束后被发送—) 注意 这个时间只能应用于使用了Spring的DispatcherServlet的web应用

=========================================================================================

LifeCycle

InitializingBean/init method

实现 springframework beans factory InitializingBean接口允许一个bean在他的所有必需的属性被BeanFactory设置后 来执行初始化的工作

当然可以使用init method来取代实现这个接口 以让应用不与sprin *** 生耦合

如果一个bean既实现了InitializingBean 又指定了init method 则spring会先调InitializingBean的方法 在调init method指定的方法

DisposableBean/destroy method

实现 springframework beans factory DisposableBean接口允许一个bean 可以在包含他的BeanFactory销毁的时候得到一个回调

注意 BeanFactory对bean的管理默认是单实例的 如果bean不是单示例的 spring就不能管理他的生命周期

BeanFactoryAware

对于实现了 springframework beans factory BeanFactoryAware接口的类 当它被BeanFactory创建后 它会拥有一个指向创建他的BeanFactory的引用

BeanNameAware

如果一个bean实现了 springframework beans factory BeanNameAware接口 并且被部署到一个BeanFactory中 那么BeanFactory就会通过这个接口来调用bean 以便通知这个bean他被部署的id 这个回调发生在普通的bean属性设置之后 在初始化回调之前 比如InitializingBean的afterProperteis方法(或者自定义的init method)

Bean的生命周期如下

Bean的构造

调用setXXX()方法设置Bean的属性

调用BeanNameAware的setBeanName()

调用BeanFactoryAware的setBeanFactory()方法

调用BeanPostProcessor的postProcessBeforeInitialization()方法

调用InitializingBean的afterPropertiesSet()方法

调用自定义的初始化方法

调用BeanPostProcessor类的postProcessAfterInitialization()方法

调用DisposableBean的destroy()方法

调用自定义的销毁方法

========================================================================================

扩展Spring的Ioc框架

Spring框架的IoC组件被设计为可扩展的 通常应用开发者并不需要子类化各个BeanFactory或ApplicationContext的实现类 通过插入特定接入接口的实现 Spring的IoC容器就可以不受限制的进行扩展

BeanPostProcessor:在创建bean之后调用

BeanFactoryPostProcessors 在创建bean之前调用

如果想在spring容器完成一个bean的实例化后 再对他进行初始化之前或之后执行一些自定义的逻辑 可以插入一个或多个BeanPostProcessor的实例

springframewonfig BeanPostProcessor接口包含了两个回调方法 当一个类作为容器的后置处理器(post processor)被注册后 对于由容器创建的每个bean实例 在任一个初始化方法(例如afterProperties和利用init method声明的方法)调用前后后置处理器会从容器中分别获取一个回调 后置处理器可以随意对这个bean实例执行他所期望的动作 也包括完全忽略这个回调

BeanFactory和ApplicationContext对待bean后置处理器稍有不同

ApplicationContext会自动检测任何提供给他的在配置元数据中定义实现了BeanPostProcessor接口的bean 并把它们注册为后置处理器 然后在容器创建bean的适当时候调用它 部署一个后置处理器同部署其他的bean并没有什么区别 无需其他的动作 而另一方面 当使用BeanFactory的时候 bean后置处理器鼻息编写代码显示的去注册

我们看到的下一个扩展点是

springframewonfig BeanFactoryPostProcessor 出一个主要的区别外 这个接口的寓意类似于BeanPostProcessor BeanFactoryPostProcessor作用于bean的定义上(例如 提供给容易的配置元数据) 也就是说 Spring IoC容器允许BeanFactoryPostProcessor在容易实际实例化任何bean之前读取配置元数据并可能修改它

Spring包含了许多已有的bean工厂后置处理器 例如PropertyResourceConfigure和PropertyPlaceHolderConfigure以及   BeanNameAutoProxyCreator

在一个BeanFactory中 应用BeanFactoryPostProcessor需要手工编码实现 而ApplicationContext则会检测部署在它之上实现了BeanFactoryPostProcessor接口的bean 并在适当的时候自动把它们用做bean工作后置处理器 部署一个后置处理器同部署其他的bean并没有什么区别 无需其他的动作

PropertyPlaceholderConfigurer

作为一个bean工厂后置处理器的实现 可以用来将BeanFactory定义中的一些属性值放置到另一个单独的Java Properties格式的文件中 这就允许用户在部署应用的时候定制一些关键属性(例如数据库URL 用户名和密码) 而不用对主XML定义文件或容器所用文件进行复杂和危险的修改

PropertyOverrideConfigurer

类似于PropertyPlaceholderConfigurer 但是与后者相比 前者对于bean属性可以有却兴致或者根本没有值 如果起覆盖左右的Properties文件没有某个bean属性的内容 那么将使用却行的上下文定义

bean工厂的定义并不会议室到被覆盖 所以仅仅擦看XML定义文件并不能立刻明显的知道覆盖配置是否被起作用了 在多个PropertyOverrideConfigurer对一个bean属性定义了不同的值的时候 最后一个将取胜

***他使用beanName propertyName来指定值 而且不需要在bean中进行配置

注册用户自定义的PropertyEditors

a 当用字符串值设置bean的属性时 BeanFactory实质上使用了标准的JavaBeans的PropertyEditor将这些String转换为属性的复杂类型 Spring预先注册了很多定制的PropertyEditor(比如 将一个字符串表示我的classname转换成阵阵的Class对象)

b 要编写一个属性编辑器 可以实现PropertyEditor接口 更为简便的方式是从PropertyEditorSupport类继承

要使用自定义的PropertyEditors 必须使用 springframewonfig CustomEditorConfigurer来注册自定义的属性编辑器

FactoryBean可以用来做代理

springframework beans factory FactoryBean

**要想得到FactoryBean本身 需要在beanName前面加上&即&beanName

*********BeanFactory和ApplicationContext的区别*********

ApplicationContext是在ApplicationContext初始化的时候就把所有的bean都创建好了 并存放在缓存中

lishixinzhi/Article/program/Java/ky/201311/28565


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

原文地址: https://outofmemory.cn/bake/7927653.html

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

发表评论

登录后才能评论

评论列表(0条)

保存