前面幾個章節介紹了bean的定義,在一個完整的應用中,各個bean並非相互獨立的,而是一塊兒工做的,在spring中,經過注入來把這些獨立的bean串起來。java
在xml配置文件中,是經過constructor-arg
標籤來實現注入。
xml配置以下:spring
<?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"> <bean id="byType" class="com.learn.di.Person"> <constructor-arg type="java.lang.String" value="張三"/> <constructor-arg type="int" value="18"/> </bean> <bean id="byName" class="com.learn.di.Person"> <constructor-arg name="name" value="李四"/> <constructor-arg name="age" value="19"/> </bean> <bean id="byIndex" class="com.learn.di.Person"> <constructor-arg index="0" value="王五"/> <constructor-arg index="1" value="20"/> </bean> </beans>
person代碼:app
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
測試代碼ide
@Test public void test() { ApplicationContext app = new ClassPathXmlApplicationContext("di.xml"); Person person1 = app.getBean("byType",Person.class); Person person2 = app.getBean("byName",Person.class); Person person3 = app.getBean("byIndex",Person.class); System.out.println(person1); System.out.println(person2); System.out.println(person3); }
運行結果以下:
第一個是經過類型注入,第二個是經過名稱注入,第三個是經過索引位置注入。函數
在註解中,經常使用的註解是@Autowired。
MyService,MyController測試
@Service public class MyService { } @Controller public class MyController { MyService myService; public MyController(@Autowired MyService myService) { this.myService = myService; } }
MyConfigthis
@Configuration @ComponentScan(value="com.learn.annotation2") public class MyConfig { }
測試代碼:spa
@Test public void test(){ ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class); MyController myController=app.getBean("myController",MyController.class); System.out.println(myController.myService); System.out.println(app.getBean("myService")); }
運行結果以下:
兩次打印的地址是同樣的,說明已經成功注入到myController中。若是想實現上面XML那種基本類型的注入,能夠用@Bean註解,經過return new一個對象來實現。3d
di.xml配置以下:code
<?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"> <bean id="person2" class="com.learn.di.Person2"> <property name="name" value="趙六"/> <property name="age" value="21"/> </bean> </beans>
person2代碼以下:
public class Person2 { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
測試代碼:
@Test public void test2() { ApplicationContext app = new ClassPathXmlApplicationContext("di.xml"); Person2 person2 = app.getBean("person2",Person2.class); System.out.println(person2); }
運行結果以下:
不一樣於構造器注入,setter只能經過名稱注入。
上面註解能夠直接注入容器的對象,在XML配置中,也可使用ref來注入。
di2.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"> <import resource="di.xml"/> <bean id="persons" class="com.learn.di.Persons"> <constructor-arg name="person1" ref="byName"/> <property name="person2" ref="byType"/> </bean> </beans>
Persons代碼以下:
public class Persons { Person person1; Person person2; public Persons(Person person1) { this.person1 = person1; } public Person getPerson2() { return person2; } public void setPerson2(Person person2) { this.person2 = person2; } @Override public String toString() { return "Persons{" + "person1=" + person1 + ", person2=" + person2 + '}'; } }
運行結果以下:
ref後面的值,是bean的標識符。
dim5.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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="person3" class="com.learn.di.Person3" c:tel="13800138000" p:name="張三" p:age="18"/> </beans>
Person3
public class Person3 { private String name; private int age; private String tel; public Person3(String tel) { this.tel = tel; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person3{" + "name='" + name + '\'' + ", age=" + age + ", tel='" + tel + '\'' + '}'; } }
測試代碼:
@Test public void test6() { ApplicationContext app = new ClassPathXmlApplicationContext("di5.xml"); Person3 person3 = app.getBean("person3", Person3.class); System.out.println(person3); }
運行結果
這種寫法,要引入xmlns:p和xmlns:c。p相對於property,c相對於constructor-arg。
在註解中,方法名也不必定要setXXX,並且@Autowired支持直接在成員上面使用。
MyController
@Controller public class MyController { @Autowired MyService myService; MyDao myDao; @Autowired public void myDao(MyDao myDao) { this.myDao = myDao; } }
測試代碼:
@Test public void test(){ ApplicationContext app = new AnnotationConfigApplicationContext(MyConfig.class); MyController myController=app.getBean("myController",MyController.class); System.out.println(myController.myService); System.out.println(myController.myDao); System.out.println(app.getBean("myService")); System.out.println(app.getBean("myDao")); }
運行結果以下:
兩次打印的地址是同樣的,說明已經成功注入到myController中。
在系統中,咱們既能夠用構造器注入,也能夠用setter注入,甚至能夠兩種一塊兒用,均可以達到咱們想要的效果。
構造器注入:強依賴,大量的構造函數參數不是很優雅,沒法解決循環依賴的問題,會拋出BeanCurrentlyInCreationException異常。
setter注入:可選依賴,能夠從新注入。
di3.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"> <bean id="outer" class="com.learn.di.Outer"> <property name="inner"> <bean class="com.learn.di.Outer.Inner"> <property name="name" value="張三"/> <property name="age" value="18"/> </bean> </property> </bean> </beans>
Outer類
public class Outer { private Inner inner; public Inner getInner() { return inner; } public void setInner(Inner inner) { this.inner = inner; } static class Inner{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Inner{" + "name='" + name + '\'' + ", age=" + age + '}'; } } @Override public String toString() { return "Outer{" + "inner=" + inner + '}'; } }
測試代碼
@Test public void test4() { ApplicationContext app = new ClassPathXmlApplicationContext("di3.xml"); Outer outer = app.getBean("outer", Outer.class); System.out.println(outer); }
運行結果:
內部類的bean定義,不須要id和name。由於是內部類,因此即使設置了,容器也會忽略。
di4.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"> <bean id="abstractCollect" abstract="true" class="com.learn.di.AbstractCollect"> <property name="list"> <list merge="true"> <value>aaa</value> <value>bbb</value> <value>ccc</value> </list> </property> <property name="map"> <map merge="true"> <entry value="name" key="張三"/> <entry value="age" key="18"/> </map> </property> <property name="set"> <set merge="true"> <value>aaa</value> <value>bbb</value> <value>ccc</value> </set> </property> <property name="properties"> <props merge="true"> <prop key="name">李四</prop> <prop key="age">20</prop> </props> </property> </bean> <bean id="collect" class="com.learn.di.Collect" parent="abstractCollect"> <property name="list"> <list merge="true"> <value>ddd</value> <value>eee</value> <value>fff</value> </list> </property> <property name="map"> <map merge="true"> <entry value="name" key="王五"/> <entry value="age" key="19"/> </map> </property> <property name="set"> <set merge="true"> <value>ddd</value> <value>eee</value> <value>fff</value> </set> </property> <property name="properties"> <props merge="true"> <prop key="sex">男</prop> <prop key="tel">13800138000</prop> </props> </property> </bean> </beans>
AbstractCollect和Collect
public abstract class AbstractCollect { List<String> list; Set<String> set; Map<String,String> map; Properties properties; public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } public Set<String> getSet() { return set; } public void setSet(Set<String> set) { this.set = set; } public Map<String, String> getMap() { return map; } public void setMap(Map<String, String> map) { this.map = map; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "AbstractCollect{" + "list=" + list + ", set=" + set + ", map=" + map + ", properties=" + properties + '}'; } } public class Collect extends AbstractCollect{ }
測試類:
@Test public void test5() { ApplicationContext app = new ClassPathXmlApplicationContext("di4.xml"); Collect collect = app.getBean("collect", Collect.class); System.out.println(collect); }
運行結果以下:
merge爲true且設置了parent的時候,能夠繼承父類的信息。merge的時候,必須是同一類型的對象。
若是是空字符串,如下是等同的。
<bean class="ExampleBean"> <property name="email" value=""/> </bean>
exampleBean.setEmail("");
若是是null,如下是等同的。
<bean class="ExampleBean"> <property name="email"> <null/> </property> </bean>
exampleBean.setEmail(null);
當A對象包含B對象的時候,A對象初始化時,B對象必須初始完成。若是A對象沒有包含B對象,也須要B對象初始化完成後,才初始化A,那能夠用depends-on。
di6.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:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="one" class="com.learn.di.One" depends-on="two"/> <bean id="two" class="com.learn.di.Two"/> </beans>
One和Two
public class One { public One(){ System.out.println("one init"); } } public class Two { public Two(){ System.out.println("two init"); } }
測試代碼
@Test public void test7() { new ClassPathXmlApplicationContext("di6.xml"); }
當有depends-on="two"的時候,運行結果以下:
不然運行結果以下說明depends-on生效了。@DependsOn這邊就不作例子了。