Bean自动装配-XML最小化配置
上一个讲了怎样用xml配置所有的Bean以及进行依赖注入,但是这样太麻烦了,对于每一个bean都要写一个xml,可以有几种方式进行自动装配。
- 四种装配方式
- byName(通过名字装配,这时属性的名字必须与bean名字一致)
- byType(通过类型,匹配与interface或class相同的类型),这种是找到对应的方法,然后进行setter方法进行注入的
- constructor(也是通过类型匹配,但是是通过new的进行装配的)
- 最佳自动装配(先用constructor装配,然后再用byType)
但是自动装配有两个问题。要是有多个bean,就用这个。
primary="false" 和 autowire-candicate='false'
public interface Food { public String foodName(); } public class BeefFood implements Food { private String name; public BeefFood() { } public BeefFood(String name) { this.name = name; } public String foodName(){ return name; } public void setName(String name) { this.name = name; } } public interface Dinner { public void foodList(); } public class BigDinner implements Dinner{ private Food food; private String position; public BigDinner() { } public BigDinner(Food food) { this.food = food; } public BigDinner(String position, Food food) { this.position = position; this.food = food; } public void setPosition(String position) { this.position = position; } public void setFood(Food food) { this.food = food; } public void foodList(){ System.out.println("今晚在" + position + "吃" + food.foodName()); } }
插入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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--传统XML方式--> <bean id="dinnerTranditional" class="spring.in.action.bean.beanAutoWire.BigDinner"> <constructor-arg name="position" value="我和亲共同的家里"/> <constructor-arg name="food" ref="yellowBeef"/> </bean> <bean id="yellowBeef" class="spring.in.action.bean.beanAutoWire.BeefFood"> <property name="name" value="黄牛肉"/> </bean> <!--自动装配byName 少了food,不用写,直接装配,但是名字要对应--> <bean id="dinnerByName" class="spring.in.action.bean.beanAutoWire.BigDinner" autowire="byName"> <property name="position" value="我和亲共同的家里"/> </bean> <bean id="food" class="spring.in.action.bean.beanAutoWire.BeefFood" autowire-candidate="false"> <!--autowire-candidate在bytype和constuctor时起忽略作用--> <property name="name" value="干煸大肠"/> </bean> <!--自动装配byType 在这里排除了food,因为autowire-candidate="false"--> <bean id="dinnerByType" class="spring.in.action.bean.beanAutoWire.BigDinner" autowire="byType"> <property name="position" value="我和亲共同的家里"/> </bean> <!--自动装配constructor--> <bean id="dinnerConstructor" class="spring.in.action.bean.beanAutoWire.BigDinner" autowire="constructor"> <constructor-arg name="position" value="我和亲共同的家里"/> <!--<constructor-arg name="food" ref="yellowBeef"/>--> </bean> <!--自动装配constructor 没搞懂--> <!--<bean id="dinnerAutoDetect" class="spring.in.action.bean.beanAutoWire.BigDinner"--> <!--autowire="default">--> <!--<!–<constructor-arg name="position" value="我和亲共同的家里"/>–>--> <!--<!–<constructor-arg name="food" ref="yellowBeef"/>–>--> <!--</bean>--> </beans>
其实只是少了一些<constractor-arg>和<property>配置
测试类为
public class TestBeanAutowire { public static void main(String[] args) { //传统依赖注入方式 Food beef = new BeefFood("黄牛肉"); System.out.println("传统依赖注入方式" + " =========>>>>>>> yellowBeef " + "Test"); Dinner dinner = new BigDinner("家里",beef); dinner.foodList(); //context ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean-autowire.xml"); //传统xml DI方式 Dinner dinnerTranditional = (Dinner) context.getBean("dinnerTranditional"); System.out.println("传统xml DI方式" + " =========>>>>>>> yellowBeef " + "Test"); dinnerTranditional.foodList(); //autowire byName方式 Dinner dinnerByName = (Dinner) context.getBean("dinnerByName"); System.out.println("autowire byName方式" + " =========>>>>>>> 干煸大肠 " + "Test"); dinnerByName.foodList(); //autowire byType方式 Dinner dinnerByType = (Dinner) context.getBean("dinnerByType"); System.out.println("autowire byType方式" + " =========>>>>>>> yellowBeef " + "Test"); dinnerByType.foodList(); //autowire constructor方式 Dinner dinnerConstructor = (Dinner) context.getBean("dinnerConstructor"); System.out.println("autowire constructor方式" + " =========>>>>>>> yellowBeef " + "Test"); dinnerConstructor.foodList(); // //autowire autoDetect方式 // Dinner dinnerAutoDetect = (Dinner) context.getBean("dinnerAutoDetect"); // System.out.println("autowire autoDetect方式" + " =========>>>>>>> yellowBeef " + "Test"); // dinnerAutoDetect.foodList(); } }
传统依赖注入方式 =========>>>>>>> yellowBeef Test 今晚在家里吃黄牛肉 十一月 29, 2015 10:47:29 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6f6827b5: startup date [Sun Nov 29 22:47:29 CST 2015]; root of context hierarchy 十一月 29, 2015 10:47:29 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [spring-bean-autowire.xml] 传统xml DI方式 =========>>>>>>> yellowBeef Test 今晚在我和亲共同的家里吃黄牛肉 autowire byName方式 =========>>>>>>> 干煸大肠 Test 今晚在我和亲共同的家里吃干煸大肠 autowire byType方式 =========>>>>>>> yellowBeef Test 今晚在我和亲共同的家里吃黄牛肉 autowire constructor方式 =========>>>>>>> yellowBeef Test 今晚在我和亲共同的家里吃黄牛肉 Process finished with exit code 0
这个是测试结果。
- 然后这种不用注解的方式也必须要声明好多bean,只是之间的关系可以进行少一点,说白了就是少了点<constractor-arg>和<property>
所以这种基于注解的方式就比较方便了。
这样也存在问题,一是没有bean,解决方式@Autowired(required=false)
二是有好几个bean,用这个@Qualifier("name"),这个名字小写就行,也可以自己定义一个限定器,见代码。
-
- 还有一个问题是扫描组件,@Component这样就自动扫描。
public interface Food { public String foodName(); } @Component @DefineRib public class RibFood implements Food{ private String name = "排骨"; public String foodName(){ return name; } public void setName(String name) { this.name = name; } } @Component public class BeefFood implements Food { private String name = "黄牛肉"; public String foodName(){ return name; } public void setName(String name) { this.name = name; } } public interface Dinner { public void foodList(); } @Component public class BigDinner implements Dinner { @Autowired // @Qualifier("beefFood")//按class的小写名字 @DefineRib//按限定器来注解 private Food food ; @Value("和亲的小屋里") private String position; // @Autowired // public BigDinner(Food food, String position) { // this.food = food; // this.position = "和亲的家里"; // } public void setPosition(String position) { this.position = position; } public void setFood(Food food) { this.food = food; } public void foodList(){ System.out.println("今晚在" + position + "吃" + food.foodName()); } } @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.PARAMETER,ElementType.FIELD}) @Qualifier public @interface DefineRib{ }
<?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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="spring.in.action"/> <bean id="dinnerAuto" class="spring.in.action.bean.beanAnnotaiton.BigDinner"> </bean> <!--<bean id="yellowBeef" class="spring.in.action.bean.beanAnnotaiton.BeefFood">--> <!--<property name="name" value="黄牛肉"/>--> <!--</bean>--> <!--<bean id="rib" class="spring.in.action.bean.beanAnnotaiton.BeefFood">--> <!--<property name="name" value="排骨"/>--> <!--</bean>--> </beans>
public class TestBeanAnnotation { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean-annotation.xml"); Dinner dinner = (Dinner)context.getBean("dinnerAuto"); dinner.foodList(); } }
这样xml就很小了