设置注入是指IOC容器经过使用属性的setter方法来注入被依赖的实列。仍是使用“人”和“斧子”的列子。java
定义一个Person接口,人都会使用“斧子”:spring
package com.custle.spring; public interface Person { //人使用斧子 public void useAxe(); }
定义一个“斧子”接口,该接口有一个“砍材”动做:app
package com.custle.spring; public interface Axe { //斧子接口有个砍的方法 public String chop(); }
具体的“中国人”实现Person接口:ide
package com.custle.spring; public class Chinese implements Person { private Axe axe; //注入所须要的斧子 public void setAxe(Axe axe) { this.axe = axe; } @Override public void useAxe() { System.out.println(axe.chop()); } }
具体的“石头斧子”实现Axe接口:测试
package com.custle.spring; public class StoneAxe implements Axe { @Override public String chop() { return "使用石斧砍材"; } }
这个时候程序并不知道Chinese使用的斧子是什么类型的斧子,此时须要经过Spring来注入“斧子”至Chinese中,咱们经过setAxe()来设值注入。this
<?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.xs"> <!-- 将stoneAxe注入chinese中的axe属性至关于setAxe(stoneAxe)--> <bean id="chinese" class="com.custle.spring.Chinese"> <property name="axe" ref="stoneAxe"></property> </bean> <!-- 将StoneAxe交给Srping管理,否则Spring怎么知道你要哪一种类型的斧子呢 --> <bean id="stoneAxe" class="com.custle.spring.StoneAxe"/> </beans>
能够看到Spring管理Bean的灵活性,Bean与Bean之间的依赖关系放在配置文件中,而不是经过代码。经过配置文件的指定,Spring能精确的为每一个Bean注入属性。经过配置文件的指定,Spring能精确的为每一个Bean注入属性。所以<bean>里面的class属性不能为接口,必须为实现类。spa
将 Chinese类进行修改,研究Spring具体是怎么实现设值注入的过程: code
package com.custle.spring; public class Chinese implements Person { private Axe axe; private String axe1; //经过property注入必须含有无参构造方法 public Chinese() { } //注入StoneAxe石斧子类型,注意这里为Axe的实现类 public void setAxe(StoneAxe axe) { this.axe = axe; System.out.println("axe="+axe.chop()); } //注入String类型 public void setAxe1(String axe1) { this.axe1 = axe1; System.out.println("axe1="+axe1); } }
测试方法:xml
public static void main(String[] args) throws Exception { //获取Chinese的Class对象 Class chinese = Class.forName("com.custle.spring.Chinese"); Class stoneAxe = Class.forName("com.custle.spring.StoneAxe"); //建立Chinese的默认实列 Object bean = chinese.newInstance(); Object stoneAxebean = stoneAxe.newInstance(); //获取axe属性对应的setAxe1()方法,参数类型为String Method method = chinese.getMethod("setAxe1", String.class); //获取axe属性对应的setAxe()方法,参数类型为StoneAxe Method method1 = chinese.getMethod("setAxe", stoneAxe); //调用bean实列的setAxe1()方法 method.invoke(bean, "hello world"); //调用bean实列的setAxe()方法 method1.invoke(bean, stoneAxebean); }
控制台输出:对象
axe1=hello world axe=使用石斧砍材
若在Chinese类中将setAxe()方法修改成StoneAxe的抽象类Axe,会发现经过反射没法将StoneAxe.Class注入。会报java.lang.NoSuchMethodException异常。
Spring会经过反射自动接管每一个<bean>定义里面的<property>,Spring会调用无参构造方法来构造该bean的实列,经过调用对应的setter方法为程序注入属性值,这也是咱们为bean设置带参构造器时,最好显示声明无参构造器的缘由。每一个bean的id惟一,程序经过bean的id访问该bean,bean与bean之间依赖关系也经过id属性关联。
经过Spring工厂去获取Spring中的bean;
package com.custle.spring; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class GetBeanFactory { private static ApplicationContext applicationContext; static{ applicationContext = new ClassPathXmlApplicationContext("applicationContext-spring.xml"); } private static Chinese getInstance(){ //经过配置文件中bean的ID获取对应的bean Chinese chinese = (Chinese)applicationContext.getBean("chinese"); chinese.useAxe(); return chinese; } }
Chinese实列无须知道斧子的具体建立过程,当须要“跟换钢斧子”时,只须要钢斧子实现斧子接口,将该钢斧子注入chinese中便可。