spring-注入/装配

本文深入讲解Spring框架中的依赖注入机制,包括BeanFactory和ApplicationContext容器的使用,构造函数和属性注入的特点,以及集合类型注入的方法。此外,还介绍了Spring提供的自动装配功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

good
原文地址:spring-注入/装配 作者:无极天宗
注入

以前,对象对自己负责,如果他要用到其他类,则直接保存它的实例.

这样做后,类和工具就被绑在一起,如果工具改变了,就不得不改变类,最快想到的解决办法是利用抽象,将工具抽象,但抽象类无法实例化,如何才能得到工具类的实例呢,答案是从外部传入,也就是说在类里有一工具类的引用,然后对外公开setter方法,从外部将工具的实例传进去.这种方式就叫依赖注入.

Spring,我们在配置文件来声明要对某个类注入哪个类.然后在代码中,我们可以获得配置文件中所有已配置的类的实例.因为配置文件被解析成容器,配置的类全在容器中.

Spring容器有两种,一种是基本的容器,提供简单的应用:BeanFactory.另一种是BeanFactory的扩展:ApplicationContext.


 

BeanFactory

它采用工厂设计模式.负责创建和分发Bean,但工厂模式只能创建一个基类的类.BeanFactory可以管理所有类型的类,只要在配置文件中声明了.声明方式就不介绍了.

Spring中有多种BeanFactory的实现,其中最常用的是:org.springframework.beans.factory.xml.XmlBeanFactory,它根据XML文件中的定义装载Bean.XmlBeanFactory需要一个org.springframework.core.io.Resource的实例给构造函数.Resource对象提供XML文件给工厂.而在Spring,Resource也有很多实现:

Org.springframework.core.io.ByteArrayResource----配置内容由一组字节给定

Org.springframework.core.io.ClassPathResource---- 配置从classpath提取

Org.springframework.core.io.DescriptiveResource----可以忽略

Org.springframework.core.io.FileSystemResource----从文件中读取

Org.springframework.core.io.InputStreamResource----从输入流读入

Org.springframework.core.io.UrlResource---从给定URL读取

Org.springframework.web.portlet.context.PortletContextResource----portlet上下文中的定义

Org.springframework.web.context.support.ServletContextResource---- servlet上下文中

因为在项目中我们都是把配置放在xml文件中,所以常用的应该是ClassPathResource,FileSystemResource,InputStreamResource.:

BeanFactory factory = new XmlBeanFactory(new FileSystemResource(“c:/config.xml”))

这里是获得工厂,但这时候还不会实例化bean,它只是把bean的相关信息载入进来.只有在我们获得bean时才会实例化具体的类,:

MyBean mybean = (MyBean)factory.getBean(“myBean”);

 

ApplicationContext

applicationContextBeanFactory多了三个功能:国际化,载入文件资源(如图片),事件

在大多数情况下应该使用ApplicationContext.它有三个经常用到的实现:

1.       ClassPathXmlApplicationContext:从类路径中的XML中载入信息.

2.       FileSystemXmlApplicationContext:从文件系统中的XML文件载入信息.

3.       XmlWebApplicationContext:Web系统中的XML文件载入信息.

:

ApplicationContext context = new FileSystemXmlApplicationContext(“c:/config.xml”);

ApplicationContext context = new ClassPathXmlAplicationContext(“config.xml”);

从上面可以看出,前者是在电脑中的具体文件地址.后者是一个相对目录的文件.而这个文件处的地方就是整个项目的类路径,包括引入的jar文件.所以一般将文件放在项目classpath的根目录下,这样免得它去找其他地方花时间.

上下文和工厂的另一个重要区别是工厂是在我们要获得对象时才实例化.而上下文是启动后预载入所有的对象,当我们要获得对象时就更快.


 

构造函数/属性注入
构造函数优点

1.       构造函数是强制使用的,因为不满足它的条件就无法实例化.

2.       不必写多余的set方法,可以减少代码.

3.       只能通过构造函数设置属性,这样就不用担心外部通过set方法动态改变一些我们不想让它改变的东西.

属性注入优点

1.       如果依赖很多,构造函数的参数列表会很长.

2.       如果已经有很多构造方式了,那么很难再提出不同的构造函数,因为构造函数只能通过参数的个数和类型来区分.

3.       如果构造函数参数中有两个以上是相同类型的,就很难确定参数的用途,可读性差.

4.       不利于继承.构造函数为了给父类的私有变量赋值,必须super传值.

 

前面已经介绍过了.通过构造函数或属性注入,都有几种情况:注入原始类型的值,注入对象.

具体用法查看上面Spring Core里的内容.

另一种特殊的注入是内部Bean注入:

<property name=””>

         <bean class=”” >

</property>

装配集合

上面说了可以注入基本类型(通过value)和自定义类(通过ref).但这两个只能传递单一值,如果要传递集合,就必须用其他标签,Spring提供四种:<list>,<set>,<map>,<props>.

List set在类中的依赖属性是数组或Collection接口的某个实现时非常有用.注意的是,这里的listset标签并不表示它们只能传递给java中的ListSet.

List

用法:

<property name=”valList”>

         <list>

                   <ref bean=”…..” />

                   <ref bean=”…..” />

                   <ref bean=”…..” />

         </list>

<property>

List元素包含一个或多个值.ref指向配置文件中的其它bean.当然,这里也可以直接用内部bean赋值,对于原始属性,可以直接用value,还可以用空值:<null />,而且一个list还可以包含另外的list,形成多维的列表.

JAVA类的接收端,可以是数组,也可以是任意的Collection 的实现,:

MyType[] valList;

List<MyType> valList;

Set

Set list用法完全一模一样.在所有使用list的地方都可以用set代替.setlist多一个功能:它限制里面的值只有一个,,如果有重复的值,它会忽略:

<property name=”valList”>

         <set>

                   <ref bean=”a” />

                   <ref bean=”a” />

                   <ref bean=”b” />

         </set>

<property>

上面的注入实际上只注入了两个值到列表里,因为a是重复的.

Map

需要 对的集合时用这个.用法:

JAVA类中:

Map<String,MyType> valMap

<property name=”valMap”>

         <map>

                   <entry key=”a” value-ref=”aBean” />

                   <entry key=”b” value-ref=”bBean” />

                   <entry key=”c” value-ref=”cBean” />

         </map>

</property>

要注意的是:

Map标签对键和值都没做类型的限定,也就是说,键和值都可以使用原始类型和扩展类型.

用原始类型时,键和值的表示分别是:

key  ------  value

扩展类型时:

key-ref  ----- value-ref

Props

它和map的用法一样.但不同的是它的键和值都被强制要求为String.:

Java:

Properties valProp

<property name=”valMap”>

         <props>

                   <prop key=”a”>a string</prop>

                   < prop key=”b” >b string</prop>

                   < prop key=”c” >c string</prop>

         </ props>

</property>

自动装配

前面已经知道了如何进行构造函数注入和属性注入,但这些都在在配置文件中显式的写出来的,这样会写大量的XML.Spring提供自动装配机制. 有四种实现方式:

1.       byname

在容器中寻找和需要自动装配的属性名相同的Bean,如果没有找到就无法装配

2.       byType

在容器中寻找和需要自动装配的属性类型相同的Bean,就是和JAVA代码中接收参数类型相同的Bean.如果找不到就无法装配,如果找到多个,就会抛出异常.

3.       Constructor

寻找和自动装配的bean构造函数参数一臻的一个或多个bean.

4.       Autodetect

先尝试用constructor,然后用byType

用法:

<bean id=”toLoad” class=”…..” autowire=”byName”></bean>

上面配置可以看出,我们没有象以前一样,bean里面加入property属性,然后用refvalue注入值.那是因为我们设置了autowire,容器会自动装配它,如果JAVA代码中该类是这样的:

setAProp(MyBeanA mybeana){}

setBProp(MyBeanB mybeanb){}

在类中有两个待注入的属性,但我们在配置文件中设置了按名称自动装配,spring会在容器中自动找ID:mybeanamybeanbbean.

如果自动装配设置为按类型:autowire=”byType”.则会在容器中找class等于MyBeanAMyBeanBbean.

Constructor一般用在我们用构造函数注入的时候和自动装配.

 

 

 

### 关于META-INF与Spring框架的关系 在Spring框架中,`META-INF`目录是一个非常重要的资源位置,它通常用于存储元数据信息以及各种配置文件。以下是具体解释: #### 1. `META-INF/spring.handlers` 该文件定义了XML命名空间处理器(Namespace Handler)。当Spring解析带有特定命名空间的XML配置时,会通过此文件找到对应的处理类。例如,对于`<context:component-scan>`标签,Spring需要知道哪个类负责解析这个标签。这可以通过`spring.handlers`文件中的映射实现[^4]。 #### 2. `META-INF/spring.schemas` 该文件提供了XSD模式的位置映射。Spring框架依赖这些XSD文件来验证XML配置文件的有效性。如果缺少正确的XSD映射或者打包过程中丢失了这些文件,则可能导致类似于`BeanDefinitionParsingException`这样的错误。 #### 3. 自动扫描机制 Spring Boot利用`META-INF/spring.factories`文件实现了自动装配功能。在这个文件中声明的各种组件会被Spring容器加载并初始化。这种设计简化了开发者的配置工作量[^1]。 #### 4. 配置覆盖 为了支持灵活的应用场景,开发者可以在运行期通过设置环境变量或命令行参数等方式动态调整应用行为。比如借助`spring.config.location`属性指定额外的配置文件路径[^2]。 ```java // 示例代码展示如何读取自定义配置项 @Value("${custom.property.name}") private String customProperty; ``` 以上片段展示了基于注解方式注入配置值的方法之一。 --- ### 解决方案建议 针对提到的异常情况——即因找不到对应名称空间处理器而引发的问题,可能是因为构建工具未正确包含必要的资源文件所致。因此需确认Ant脚本是否妥善处理了整个项目的结构及其依赖关系;另外也可以考虑切换至Maven等现代化构建解决方案以减少此类风险发生概率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值