详解依赖注入与自动装配

        在我面试的时候,常会问面试者一个问题,就是依赖注入有几种方式,发现面试者的回答五花八门,有回答两种的,也有回答三种的,四种的。其实正确的答案是两种:构造器注入和setter注入。

        提到依赖注入,就不能不说装配。有些初学者总是会把这两个概念搞混,这个博文就是来跟大家讨论这两个概念以及其中详细的原理。

        依赖注入的本质就是装配,装配是依赖注入的具体行为。这就是两者的关系。例如:

        <bean id="hello" class="com.maven.Hello"><constructor-arg value="hello" /></bean>这是使用构造器注入来装配bean。

        <bean id="hello" class="com.maven.Hello" p:hello="hello" />这是使用setter注入,p是spring的名称空间,可以用来代替<property>标签。

        以上就是两种依赖注入方式。上面的注入只是基本类型的注入。下面介绍一下常用的注入配置:

        1.构造器注入对象属性

        <bean id="text" class="com.maven.Text" />

        <bean id="hello" class="com.maven.Hello"><constructor-arg ref="text" /></bean>

        2. 属性注入对象属性

        <bean id="hello" class="com.maven.Hello"><property name="text" ref="text" /></bean>

        3. 属性为List类型或数组类型属性注入

        <bean id="hello" class="com.maven.Hello">

                <property name="persons">

                        <list>

                                <ref bean="zhangsan" />

                                <ref bean="zhangsan" />

                        </list>

                </property>

        </bean>

        list元素的成员也可以是<value>,<bean>,<null />,其中<bean>是用来装配匿名bean的,<null />是用来装配null值的。匿名bean会在下面介绍。

        4.属性为set类型的属性注入

        set类型与list类型注入是一样的,只是标签改成<set>就可以了。并且里面的元素是不能重复的。

       5. 属性为map类型的属性注入

       <bean id="hello" class="com.maven.Hello">

                <property name="article">

                        <map>

                                <entry key="title" value-ref="text" />

                                <entry key="title" value-ref="text" />

                        </map>

                </property>

        </bean>

       map类型的键和值可以是任何类型,key-ref用来引用键是bean的,value-ref用来引用值是bean的

        6. 属性为Properties类型的属性注入

        <bean id="hello" class="com.maven.Hello">

                <property name="article">

                        <props>

                                <prop key="title">I LOVE YOU</prop>

                                <prop key="title">I HATE YOU</prop>

                        </props>

                </property>

        </bean>

       Properties类型的元素为props,每一个键值标签是prop,注意要与property标签进行区分。而且Properties类型的键和值必须都是String类型的。并且值是用<prop>标签内容表示的,而不是用value属性。

最后说一下匿名bean,这个比较少用。匿名bean跟匿名内部类是一样的,但是匿名bean不需要实现接口,并且也只能用一次,所以<bean>标签中不用写id属性。例如我们用匿名bean来作为属性注入时:

        <property name="text"><bean class="com.maven.Text" /></property>。匿名bean没有id属性,因为匿名bean只能被使用一次,加上id属性没有意义。

        好了,说到这里,大家可以看到用xml装配bean是一件很繁琐的事情,而且我们还要找到对应类型的bean才能装配。

       首先,确定一下装配的概念。《spring实战》中给装配下了一个定义:创建应用对象之间协作关系的行为称为装配。也就是说当一个对象的属性是另一个对象时,实例化时,需要为这个对象属性进行实例化。这就是装配。如果一个对象只通过接口来表明依赖关系,那么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行切换。但是这样会存在一个问题,在传统的依赖注入配置中,我们必须要明确要给属性装配哪一个bean的引用,一旦bean很多,就不好维护了。基于这样的场景,spring使用注解来进行自动装配,解决这个问题。自动装配就是开发人员不必知道具体要装配哪个bean的引用,这个识别的工作会由spring来完成。与自动装配配合的还有“自动检测”,这 个动作会自动识别哪些类需要被配置成bean,进而来进行装配。这样我们就明白了,自动装配是为了将依赖注入“自动化”的一个简化配置的操作。

        装配分为四种:byName, byType, constructor, autodetect。byName就是会将与属性的名字一样的bean进行装配。byType就是将同属性一样类型的bean进行装配。constructor就是通过构造器来将类型与参数相同的bean进行装配。autodetect是constructor与byType的组合,会先进行constructor,如果不成功,再进行byType。具体选择哪一种装配方式,需要配置<bean>标签的autowire属性,如果没有配置,默认是byName类型,就是会根据属性的名字来进行自动装配。上面最常用的还是byName和byType。自动装配时,装配的bean必须是唯一与属性进行吻合的,不能多也不能少,有且只有一个可以进行装配的bean,才能自动装配成功。否则会抛出异常。如果要统一所有bean的自动装配类型,可以在<beans>标签中配置default-autowire属性。当然如果配置了autowire属性,我们依然可以手动装配属性,手动装配会覆盖自动装配。

        以上是通过xml配置的方式实现自动装配的,spring2.5之后提供了注解方式的自动装配。但是要使用这些注解,需要在配置文件中配置<context:annotation-config />。只有加上这一配置,才可以使用注解进行自动装配,默认情况下基于注解的装配是被禁用的。

        常用的自动装配注解有以下几种:@Autowired,@Resource,@Inject,@Qualifier,@Named。@Autowired注解是byType类型的,这个注解可以用在属性上面,setter方面上面以及构造器上面。使用这个注解时,就不需要在类中为属性添加setter方法了。但是这个属性是强制性的,也就是说必须得装配上,如果没有找到合适的bean能够装配上,就会抛出异常。这时可以使用required=false来允许可以不被装配上,默认值为true。当required=true时,@Autowired要求必须装配,但是在没有bean能装配上时,就会抛出异常:NoSuchBeanDefinitionException,如果required=false时,则不会抛出异常。另一种情况是同时有多个bean是一个类型的,也会抛出这个异常。此时需要进一步明确要装配哪一个Bean,这时可以组合使用@Qualifier注解,值为Bean的名字即可。@Qualifier注解使用byName进行装配,这样可以在多个类型一样的bean中,明确使用哪一个名字的bean来进行装配。@Qualifier注解起到了缩小自动装配候选bean的范围的作用。注意:@Autowired注解是spring提供的,所以会依赖spring的包。还有一个byType的注解@Inject,与@Autowired注解作用一样,也是byType类型,而且是java ee提供的,完全可以代替@Autowired注解,但是@Inject必须是强制装配的,没有required属性,也就是不能为null,如果不存在匹配的bean,会抛出异常。@Autowired与@Qualifier可以组合使用,@Inject也有一个组合的注解,就是@Named注解,与@Qualifier作用一样,也是byName,但是不是spring的,是java ee标准的。这样就出现了两套自动装配的注解组合,@Autowired与@Qualifier是spring提供的,@Inject与@Named是java ee的。但是@Qualifier注解在java ee中也有一样,作用与spring的@Qualifier注解一模一样,只是所在的包不一样。不过建议大家使用spring的。最后还有一个@Resouce注解, 这个注解也是java ee的,也是byName类型的,原理同@Qualifier和@Named是一样的。

        最后说一说,自动检测配置,也是springmvc中最牛的一项功能。只要一个配置<context:component-scan base-package="">,base-package属性指定要自动检测扫描的包。

该配置会自动扫描指定的包及其子包下面被构造型注解标注的类,并将这些类注册为spring bean,这样就不用在配置文件一个一个地配置成bean标签。构造型注解包括:@Controller,@Components,@Service,@Repository和使用@Component标注的自定义注解。生成的bean的ID默认为类的非限定名,也就是把类的名字的首字母换成小写。可以在这些注解的值中写名bean id的值,如@Controller("helloworld")。如果你想细化包被扫描的范围,可以使用<context:include-filter>和<context:exclude-filter>。具体使用方法这里不再详说。注意,没有被扫描到的类是不能注册为bean,也就不能被用来装配其他类。所以这个配置的base-package的范围非常重要。

       

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SpringBoot 的自动装配原理是基于 Spring 框架的核心特性之一,即依赖注入(Dependency Injection)和控制反转(Inversion of Control)。通过自动装配SpringBoot 可以根据一定的规则,自动将需要的依赖对象注入到相应的组件中,简化了开发者的配置工作。 在 SpringBoot 中,自动装配主要通过以下几个步骤实现: 1. ComponentScan:SpringBoot 会根据指定的包路径进行组件扫描,找到所有被注解标记的组件,如 @Component、@Service、@Repository 等。 2. ConditionalOnClass/ConditionalOnMissingClass:SpringBoot 会根据类路径中是否存在指定的类来判断是否需要装配某个组件。当类存在时,装配该组件;当类不存在时,跳过该组件。 3. ConditionalOnBean/ConditionalOnMissingBean:SpringBoot 会根据容器中是否存在指定的 Bean 来判断是否需要装配某个组件。当 Bean 存在时,跳过该组件;当 Bean 不存在时,装配该组件。 4. EnableAutoConfiguration:SpringBoot 提供了一系列以 Enable 开头的注解,用于开启特定功能的自动配置。这些注解会在特定条件下加载一些默认的配置类,将默认的配置注入到容器中。 5. 自定义配置:除了 SpringBoot 提供的默认自动配置之外,开发者还可以通过自定义配置文件(application.properties 或 application.yml)来覆盖默认配置,实现个性化的自动装配。 总的来说,SpringBoot 的自动装配原理就是根据一系列的条件和规则,将需要的依赖对象自动注入到相应的组件中,简化了开发者的配置工作,提高了开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值