XML配置里的Bean自动装配
Spring IOC容器可以自动装配Bean。需要做的仅仅是在<bean>的autowire属性里指定自动装配的模式
ByType(根据类型自动装配):若IOC容器中有多个与目标Bean类型一致的的Bean,在这种情况下,Spring将无法判定哪个Bean最适合该属性,所以不能执行自动装配。
byname(根据名称自动装配):必须将目标Bean的名称和属性名设置为完全相同。
Constructor(通过构造器自动转配):当Bean中存在多个构造器时,此种自动装配方式将会很复杂,不推荐使用。
下面看如何配置
package logan.spring.study.autowire;public class Person { private String name; private Address address; private Car car; public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", address=" + address + ", car=" + car + "]"; }}
package logan.spring.study.autowire;public class Address { private String city; private String street; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } @Override public String toString() { return "Address [city=" + city + ", street=" + street + "]"; } }
package logan.spring.study.autowire;public class Car { private String brand; private String price; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getPrice() { return price; } public void setPrice(String price) { this.price = price; } @Override public String toString() { return "Car [brand=" + brand + ", price=" + price + "]"; } }
package logan.spring.study.autowire;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main { public static void main(String[] args) { // TODO Auto-generated method stub ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-autowire.xml"); Person person = (Person) ctx.getBean("person"); System.out.println(person); }}
下面是输出结果
五月 20, 2017 3:41:56 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3eb07fd3: startup date [Sat May 20 15:41:56 CST 2017]; root of context hierarchy五月 20, 2017 3:41:56 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [beans-autowire.xml]Person [name=Tom, address=Address [city=Beijing, street=HuiLongGuan], car=Car [brand=Audi, price=300000]]
如果xml文件改成如下
输出结果为
五月 20, 2017 3:43:15 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3eb07fd3: startup date [Sat May 20 15:43:15 CST 2017]; root of context hierarchy五月 20, 2017 3:43:15 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [beans-autowire.xml]Person [name=Tom, address=null, car=Car [brand=Audi, price=300000]]
可见这是根据名字来自动装配,如果地址address的id不是address就没有办法装配。
还可以根据类型来装配,如下:
输出结果:
五月 20, 2017 3:47:08 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3eb07fd3: startup date [Sat May 20 15:47:08 CST 2017]; root of context hierarchy五月 20, 2017 3:47:08 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [beans-autowire.xml]Person [name=Tom, address=Address [city=Beijing, street=HuiLongGuan], car=Car [brand=Audi, price=300000]]
但是根据类型装配有的时候会有问题,例如在xml里面配置两个相同类型的bean。
报错如下:
五月 20, 2017 3:48:29 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3eb07fd3: startup date [Sat May 20 15:48:29 CST 2017]; root of context hierarchy五月 20, 2017 3:48:29 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions信息: Loading XML bean definitions from class path resource [beans-autowire.xml]五月 20, 2017 3:48:29 下午 org.springframework.context.support.ClassPathXmlApplicationContext refresh警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person' defined in class path resource [beans-autowire.xml]: Unsatisfied dependency expressed through bean property 'address'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'logan.spring.study.autowire.Address' available: expected single matching bean but found 2: address2,address3Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person' defined in class path resource [beans-autowire.xml]: Unsatisfied dependency expressed through bean property 'address'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'logan.spring.study.autowire.Address' available: expected single matching bean but found 2: address2,address3 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1357) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1249) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) 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:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext. (ClassPathXmlApplicationContext.java:83) at logan.spring.study.autowire.Main.main(Main.java:11)Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'logan.spring.study.autowire.Address' available: expected single matching bean but found 2: address2,address3 at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:173) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1342) ... 13 more
XML配置里的Bean自动装配的缺点:
在Bean配置文件里配置autowire属性进行自动装配将会装配Bean的所有属性,然而,若只希望装配个别属性时,autowire就不够灵活了。
autowire属性要么根据类型自动装配,要么根据名称自动装配。不能两者兼而有之。
一般情况下,在实际的项目中很少使用自动装配,因为和自动装配功能所带来的好处比起来,明确清晰的配置文档更有说服力一些。