Spring学习(四)-Bean的三种装配方式
来源:互联网 发布:网络共享硬盘无法访问 编辑:程序博客网 时间:2024/05/18 01:51
本篇博客主要讲述Spring中Bean的三种主要装配:1、在XML中进行显示配置;2、自动装配方式;3、在Java中进行显示配置。下面分别来研究上述三种装配方式。
在Spring IOC容器中注入依赖资源主要有以下两种基本实现方式:(1)构造器注入:容器实例化Bean时注入一些依赖,通过在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;(2)setter注入:通过setter方法进行注入依赖。
1、在XML中进行显示配置
定义接口:Animal
package com.wygu.spring.animal;public interface Animal { public void walk(); public void call();}
实现类Cat和Dog
package com.wygu.spring.animal;public class Cat implements Animal{ private String catName; public Cat(String catName) { this.catName = catName; } @Override public void walk() { System.out.println("The Cat name: "+catName+" is walking"); } @Override public void call() { System.out.println("The Cat name: "+catName+" is called"); }}package com.wygu.spring.animal;public class Dog implements Animal{ private String dogName; public Dog(String dogName) { this.dogName = dogName; } @Override public void walk() { System.out.println("The Dog name: "+dogName+" is walking"); } @Override public void call() { System.out.println("The Dog name: "+dogName+" is walking"); }}
定义一个工厂AnimalFactory生产动物
package com.wygu.spring.animal;public class AnimalFactory { private Animal animal; public AnimalFactory(){ } public AnimalFactory(Animal animal){ this.animal = animal; } public Animal getAnimal() { return animal; } public void setAnimal(Animal animal) { this.animal = animal; }}
编写spring-application.xml
<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 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- 通过构造器参数名依赖注入 --> <bean id="cat" class="com.wygu.spring.animal.Cat"> <constructor-arg name="catName" value="加菲猫"/> </bean> <!-- 通过构造器参数索引进行注入 --> <bean id="dog" class="com.wygu.spring.animal.Dog"> <constructor-arg index="0" value="欧巴"/> </bean> <!-- 通过构造器参数索引依赖注入 --> <bean id="factory1" class="com.wygu.spring.animal.AnimalFactory"> <constructor-arg name="animal" ref="cat"/> </bean> <!-- 通过setter方式依赖注入 --> <bean id="factory2" class="com.wygu.spring.animal.AnimalFactory"> <property name="animal" ref="dog" /> </bean></beans>
通过上述示例,我们知道,利用构造器注入时,常见的有两种注入方式:(1)根据参数索引注入,使用标签“”来指定注入的依赖,其中“index”表示索引,从0开始,即第一个参数索引为0,“value”来指定注入的常量值;(2)根据参数名进行注入,使用标签“”来指定注入的依赖,其中“name”表示需要匹配的参数名字,“value”来指定注入的常量值。
对于setter方法注入方式,只有一种依赖注入方式: 根据参数名进行注入,语法同上。
但是,当系统非常庞大时,如果Bean之间的依赖关系全部通过XML方式实现,会导致配置文件的可读性与可维护性变得很低。此外,在开发中,开发人员需要在.java文件和.xml文件之间来回的切换,从而降低开发效率。
为了解决上述问题,Spring引入了注解,通过”@XXX”的方式,让注解与Java Bean紧密结合,不仅精简了大量的配置文件,而且还增加了Java Bean的可读性与内聚性。下面给出通过注解方式实现Java Bean的装配。
2、通过注解技术实现Bean的自动装配
(1)@Autowired
1)在AnimalFactory的成员域上标注注解 @Autowired
package com.wygu.spring.animal;import org.springframework.beans.factory.annotation.Autowired;public class AnimalFactory { @Autowired private Animal animal;....}
spring-application.xml
<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 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- 该 BeanPostProcessor 将自动起作用,对标注 @Autowired 的 Bean 进行自动注入 --> <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/> <!-- 通过构造器参数索引进行注入 --> <bean id="dog" class="com.wygu.spring.animal.Dog"> <constructor-arg index="0" value="欧巴"/> </bean> <bean id="factory1" class="com.wygu.spring.animal.AnimalFactory"> </bean></beans>
Spring 通过一个 BeanPostProcessor 对 @utowired 进行解析,所以要让 @Autowired 起作用必须事先在 Spring 容器中如spring-application.xml中声明AutowiredAnnotationBeanPostProcessor Bean。当 Spring 容器启动时,AutowiredAnnotationBeanPostProcessor 将扫描 Spring 容器中所有 Bean,当发现 Bean 中拥有 @Autowired 注释时就找到和其匹配(默认byType)的 Bean,并注入到对应的地方中去。
2) 此外,还可以在AnimalFactory的构造器上标注注解 @Autowired:
package com.wygu.spring.animal;import org.springframework.beans.factory.annotation.Autowired;public class AnimalFactory { private Animal animal; @Autowired public AnimalFactory(Animal animal){ this.animal = animal; } .....}
3)或者在AnimalFactory的setter方法上标注注解 @Autowired:
package com.wygu.spring.animal;import org.springframework.beans.factory.annotation.Autowired;public class AnimalFactory { private Animal animal; public Animal getAnimal() { return animal; } @Autowired public void setAnimal(Animal animal) { this.animal = animal; } ......}
但是,当我们在 Spring 容器中配置了两个类型为Animal类型的 Bean时,在对AnimalFactory中成员域animal自动注入时,Spring 容器将无法确定注入哪一个,就会抛出如下的异常:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'factory1': Unsatisfied dependency expressed through method 'setAnimal' parameter 0: No qualifying bean of type [com.wygu.spring.animal.Animal] is defined: expected single matching bean but found 2: cat,dog; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.wygu.spring.animal.Animal] is defined: expected single matching bean but found 2: cat,dog at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:651) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:350) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.wygu.spring.main.Main.main(Main.java:12)Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.wygu.spring.animal.Animal] is defined: expected single matching bean but found 2: cat,dog at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:172) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1059) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1018) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ... 15 more
通过上述异常,很容易看出是由于同时存在两个满足注入条件的Bean(同一种类型Animal),从而使得IOC容器抛出异常。
Spring中 允许我们通过 @Qualifier 注解指定注入 Bean 的名称,这样歧义就消除了。
(2)@Qualifier
@Autowired @Qualifier("cat") public void setAnimal(Animal animal) { this.animal = animal; }
仍然报上述错误,不知道为什么,网上各种方法都试了,仍然没有消除二义性?????
然后在spring-application.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:annotation-config/> <bean id="factory1" class="com.wygu.spring.animal.AnimalFactory"/> <!-- 通过构造器参数索引进行注入 --> <bean id="cat" class="com.wygu.spring.animal.Cat"> <constructor-arg index="0" value="加菲猫"/> </bean> <!-- 通过构造器参数索引进行注入 --> <bean id="dog" class="com.wygu.spring.animal.Dog"> <constructor-arg index="0" value="欧巴"/> </bean></beans>
@Autowired 和@Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName 了。@Autowired 和@Qualifier可以结合对构造器和成员域进行标注。
(3)如果不存在Bean匹配,可以在自动注入的地方加上 @Autowired(required = false)
@Autowired(required = false) public void setAnimal(Animal animal) { this.animal = animal; }
但是上述方式不建议使用,因为很有可能出现空指针异常。
3、在Java中进行显示配置
尽管在很多场景下通过自动装配实现实现Spring的自动化配置是更为推荐的,但有时候自动化配置的方案是行不通的,因此我们需要明确配置Spring。比如想将第三方第三方库中的组件装配到应用中,此时是没有办法自动装配的,因而我们需要采用显示装配方式,比如XML,或者JavaConfig方式。由于JavaConfig是类型安全的而且重构友好,我们更推荐使用JavaConfig方式。
package com.wygu.spring.hello;public interface HelloWorld { public void printHelloWorld(String str);}package com.wygu.spring.hello;public class HelloWorldImp implements HelloWorld{ @Override public void printHelloWorld(String str){ System.out.println("Hello:"+str); }}
创建HelloConfig
package com.wygu.spring.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.wygu.spring.hello.HelloWorld;import com.wygu.spring.hello.HelloWorldImp;@Configurationpublic class HelloConfig { @Bean(name="helloBean") public HelloWorld getHelloWorld(){ return new HelloWorldImp(); }}
package com.wygu.spring.main;import org.springframework.context.ApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import com.wygu.spring.config.HelloConfig;import com.wygu.spring.hello.HelloWorld;public class Main { public static void main(String[] args) { @SuppressWarnings("resource") ApplicationContext context = new AnnotationConfigApplicationContext(HelloConfig.class); HelloWorld helloWorld = (HelloWorld) context.getBean("helloBean"); helloWorld.printHelloWorld("Spring Java Config"); }}
执行结果为:Hello:Spring Java Config
显然,上述代码示例中,没有使用自动装配和XMl实现了装配Bean的功能。
- Spring学习(四)-Bean的三种装配方式
- Spring装配bean的三种方式
- spring装配bean的三种方式
- spring基础-Bean的装配方式(三)自动装配
- Spring自动装配Bean属性的四种方式
- Spring的三种装配Bean的方式
- Spring的自动装配Bean的三种方式
- Spring的自动装配Bean的三种方式
- Spring中装配bean的三种主要方式
- 【spring】1、三种装配bean的方式
- Spring中装配bean的三种主要方式
- spring的bean装配两种方式
- Spring 装配Bean的几种方式
- Spring学习----Bean的装配(4)
- Spring学习-----bean的装配(5)
- Spring学习-----bean的装配(6)
- Spring学习(2)------bean的装配
- 11级_Java_曹建波 05.06 Spring的autowire自动装配bean的四种方式
- Docker
- ECMAScript 2016 (ES7)
- HDU 5974 A Simple Math Problem 数学
- leetcode[Array Partition I]//待整理多种解法
- android 签名打包时去掉log日志打印(仅在debug包中打印log信息)
- Spring学习(四)-Bean的三种装配方式
- 【百度之星】Chess
- ios 网络请求和数据库一起封装,block回调
- request获取数据流
- android RXJava2.0(二)--线程控制
- python学习笔记(三)
- mvc
- sql整理之习题..
- Spring MVC静态资源处理