IOC有幾種類型
兩種,依賴注入和依賴查找
依賴注入分幾種,是哪幾種?
構造器constructor依賴注入和setter依賴注入
Spring的依賴注入的核心是Bean工廠. Bean工廠負責管理組件和它們之間的依賴關系.Spring中,這種bean用來查閱所有容器管理的組件.
你的應用程序需要通過BeanFactory接口來使用Spring的DI容器.也就是說,你的程序必須創建實現了BeanFactory接口的類來配置它的Bean和依賴關系的消息.
在Spring容器內拼湊Bean叫做裝配。裝配Bean的時候,你是在告訴容器需要哪些Bean以及容器如何使用依賴注入將它們 藕合在一起。
我們還是來用例子講吧:
就以最常用的學生、課程、學藉、成績來說:
業務層:
StudentService CourseService
StudentServiceImpl CourseServiceImpl
StudentDao CourseDao
StudentDaoImpl CourseDaoImp
在業務層有兩個業務組件:學生服務和課程服務。學生服務處理所有的和學生有關的事務,而課程服務負責和課程有關的功能。這些服務都通過接口來定義。
StudentService 接口如下:
public interface StudentService{
public Student getStuden(String id);
public void createStudent(Student stu);
public java.util.Set getCompletedCourse(Student stu);
}
CourseService接口如下:
public interface CourseService{
public Student getCourse(String id);
public void createCourse(Course course);
public java.util.Set getAllCourse();
public void enrollStudentInCourse(Course course,Student stu) throws CourseException;
}
StudentServiceImpl是StudentService的實現:
package com.springinaction.service.training;
public class StudentServiceImpl implements StudentService{
private StudentDao stuDao;
public StudentServiceImpl(StudentDao sDao){
stuDao=sDao;
}
public void setStudentDao(StudentDao sDao){
stuDao=sDao;
}
public Student getStudent(String id){
return stuDao.findById(id);
}
public void createStudent(Student stu){
stuDao.create(stu);
}
public java.util.Set getCompletedCourses(Student stu){
return stuDao.getCompletedCourses(stu);
}
}
StudentServiceImpl將很多職責委托給了StudentDao。StudentDao處理與數據庫的交互來讀寫學生信息。StudentDao的實現類叫StudentDaoIpl.
在這裡有兩種方法將StudentDao引用賦給StudentServiceImpl:通過它的構造函數或通過setStudentDao()方法。
CoureseServiceImpl是CoureseService的實現:
package com.springinaction.service.training;
import java.util.iterator;
import java.util.Set;
public class CourseServiceImpl implements CourseService{
private CourseDao courseDao;
private StudentService studentService;
private int maxStudents;
public CourseServiceImpl(CourseDao courDao){
this.courseDao=courDao;
}
public void setStudentService(StudentService stuService){
this.studentService=stuService;
}
public void setMaxStudents(int maxStudents){
this.maxStudents=maxStudents;
}
public int getMaxStudents(){
return maxStudents;
}
public Course getCourse(String id){
return courseDao.findById(id);
}
public void createCourse(Course course){
courseDao.create(course);
}
public void enrollStudentInCourse(Course course,Student stu) throws
CourseException{
if(course.getStudent().size()>=maxStudents){
throws new CourseException("Course is full");
}
enforcePrerequisites(course,student);
course.getStudent().add(student);
courseDao.update(course);
}
private void enforcePrerequisites(Course course,Student student) throws CourseException{
Set completed=
studentService.getCompletedCourse(student);
Set prereqs=course.getPrerequisites();
for(Iternate iter=prereqs.iterator(); iter.hashNext();){
if(!completed.contains(iter.next())){
throws new CourseException("Prerequisites are not met.")
}
}
}
}
和StudentServiceImpl一樣,CoureseServiceImpl是通過它的構造函數接受CourseDao參數。CourseDao的實現是CourseDaoImpl。
enrollStudentInCourse()方法在把學生添加到課程中之前先要調用enforcePrerequisites()方法。如果學生不能滿足先決條件,enforcePrerequisites()方法拋出CourseException,enrollStudentInCourse將重新拋出這個異常。
注意enforcePrerequisites()方法使用了StudentService實現類來獲得一個學生的所有已完成課程。這意味著除了CourseDao,CoureseServiceImpl還要與StudentService合作一滿足先決條件這個業務需求。CoureseServiceImpl通過setStudentService()方法得到它的
StudentService,不象courseDao是通過構造函數得到。這樣做的原因是因為courseDao在CoureseServiceImpl中經常被用到,所以不應該在創建CoureseServiceImpl的時候還沒有設置CourseDao屬性。
使用XML裝配:
在Spring中,有幾種容器都支持使用XML裝配BEAN,包括:
XMLBeanFactory:一種簡單的BeanFactory,它用java.io.InputStream載入上下文定義文件。
ClassPathXmlApplicationContext:一種應用上下文,它從類路徑中載入上下文定義文件。
FileSystemXmlApplicationContext:一種應用上下文,它從文件系統中載入上下文定義文件。
XmlWebApplicationContext:一種基於Spring的Web應用系統上下文,它從Web應用系統上下文中載入上下文定義文件。
所有這些面向XML的容器都使用非常簡單的XML文件來定義BEAN。上下文定義文件的根元素是<beans></beans>.<beans>有多個<bean>子元素。每個<bean>元素定義了一個bean如何被裝配到Spring容器中。
下面就是這個例子的XML配置
<beans>
<bean id="foo"
class="com.springinaction.Foo"/>
<bean id="bar"
class="com.sprionginaction.Bar"/>
</beans>
這是個簡單的BEAN裝配XML文件在Spring配置了兩個BEAN。
添加一個BEAN:
在Spring中對一個BEAN的最基本的配置包括Bean的ID和它的全稱類名。
在上面的學生例子中,我們往文件中添加CourseDao和StudentDao的實現類的定義
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Beans PUBLIC "-//SPRING//DTD BEAN//EN"http://www.springframework.org/dtd/spring-beans.dtd”>
<beans>
<bean id="courseDao" class="com.springinaction.service.training.CourseDaoImpl"/>
<bean id="studentDao" class="com.springinaction.service.training.StudentDaoImpl"/>
</beans>
原型與單實例:
默認情況下,Spring中的所有bean都是單例(singletons),這意味著Spring維護bean的唯一實例,所有的依賴對象引用同一實例。對
bean工廠的getBean()方法的每一次調用都返回同一個實例
<bean id="foo" class="com.springinaction.Foo" singletons="false"/>
在這裡有個屬性singletons,把它設為false就成了原型,如為TRUE,就是單例。
請大家注意每次用bean的名字調用getBean()方法都會獲得一個這個BEAN的新實例,。如果BEAN使用的是有限資源,如數據庫和網絡連接的話這樣使用就不好了。所有盡量不要把singletons設為false。除非確實需要。
通過Set方法注入依賴
public void setMaxStudents(int maxStudents){
this.maxStudents=maxStudents;
}
public int getMaxStudents(){
return maxStudents;
}
Bean配置
<bean id="foo"
class="com.springinactiong.Foo">
<property name="name">
<value>Foo MyFoo</value>
</property>
</bean>
假如為了限制每門課程的注冊學生人數最多30人,
<bean id="courseService">
<property name="maxStudents">
<value>30< /value>
</property>
</bean>
引用其他 bean 我們可以使用 <property>元素來設置指向其他Bean的屬性。
<property>的子元素<ref>可以實現:
<bean id="foo"
class="com.springinactiong.Foo">
<property name="bar">
<ref bean="bar">
</property>
</bean>
<bean id="bar"
class="com.springinactiong.Bar"/>
<bean id="courseService"
class="com.springinaction.service.training.CourseDaoImpl"/>
<property name="studentService">
<ref bean="studentService">
</property>
</bean>
<bean id="studentService"
class="com.springinaction.service.training.studentService"/>
容器賦給courseService Bean 一個studentService實例,這樣courseServiceImpl就不用自己尋找studentService了
內部 bean:
<bean id="courseService"
class="com.springinaction.service.training.CourseServiceImpl"/>
<property name="studentService">
<bean class="com.springinaction.service.training.StudentServiceImpl"/>
</property>
</bean>
這種裝配引用的方式的缺點是你無法在其他地方重用這個StudentServiceImpl實例,因為它是一個專門為courseService Bean建立的實例。
裝配集合:
List
<property name="barList">
<list>
<value>bar1</value>
<ref bean="bar2">
</list>
</property>
Set
<property name="barSet">
<set>
<value>bar1</value>
</set>
</property>
Map
<property name="barMap">
<map>
<entry key="key1">
<value>bar1</value>
</entry>
<entry key="key2">
<ref bean="bar2">
</entry>
</map>
</property>
Properties
<property name="barProps">
<props>
<prop key="key1">bar1</prop>
<prop key="key2">bar2</prop>
</props>
</property>
集合的裝配就完了
下面就講構造函數的注入
<bean id="foo"
class="com.sprininaction.Foo">
<constructor-arg>
<value> 50</value>
</constructor-arg>
</bean>
有兩種方法來處理構造函數的不確定:
序號和類型
<bean id="foo"
class="com.sprininaction.Foo">
<constructor-arg index="1">
<value> ...</value>
</constructor-arg>
<constructor-arg index="0">
<value> ...</value>
</constructor-arg>
</bean>
<bean id="foo"
class="com.sprininaction.Foo">
<constructor-arg type="java.lang.String">
<value>Spring</value>
</constructor-arg>
<constructor-arg type="java.lang.int">
<value> 30</value>
</constructor-arg>
</bean>
end