在Spring的第二篇中主要講解了Spring Core模塊的使用IOC容器建立對象的問題,Spring Core模塊主要是解決對象的建立和對象之間的依賴關係,所以本博文主要講解如何使用IOC容器來解決對象之間的依賴關係!java
咱們來看一下咱們之前關於對象依賴,是怎麼的歷程spring
class UserService{
UserDao userDao = new UserDao();
}
複製代碼
後來,咱們發現service層牢牢耦合了dao層。咱們就寫了DaoFactory,在service層只要經過字符串就可以建立對應的dao層的對象了。服務器
DaoFactory微信
public class DaoFactory {
private static final DaoFactory factory = new DaoFactory();
private DaoFactory(){}
public static DaoFactory getInstance(){
return factory;
}
public <T> T createDao(String className,Class<T> clazz){
try{
T t = (T) Class.forName(className).newInstance();
return t;
}catch (Exception e) {
throw new RuntimeException(e);
}
}
}
複製代碼
private CategoryDao categoryDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.CategoryDAOImpl", CategoryDao.class);
private BookDao bookDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.BookDaoImpl", BookDao.class);
private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class);
private OrderDao orderDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.OrderDaoImpl", OrderDao.class);
複製代碼
再後來,咱們發現要修改Dao的實現類,仍是得修改service層的源代碼呀..因而咱們就在DaoFactory中讀取關於daoImpl的配置文件,根據配置文件來建立對象,這樣一來,建立的是哪一個daoImpl對service層就是透明的app
DaoFactory函數
public class DaoFactory {
private UserDao userdao = null;
private DaoFactory(){
try{
InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");
Properties prop = new Properties();
prop.load(in);
String daoClassName = prop.getProperty("userdao");
userdao = (UserDao)Class.forName(daoClassName).newInstance();
}catch (Exception e) {
throw new RuntimeException(e);
}
}
private static final DaoFactory instance = new DaoFactory();
public static DaoFactory getInstance(){
return instance;
}
public UserDao createUserDao(){
return userdao;
}
}
複製代碼
UserDao dao = DaoFactory.getInstance().createUserDao();
複製代碼
經過上面的歷程,咱們能夠清晰地發現:對象之間的依賴關係,其實就是給對象上的屬性賦值!由於對象上有其餘對象的變量,所以存在了依賴...測試
Spring提供了好幾種的方式來給屬性賦值優化
UserService中使用userDao變量來維護與Dao層之間的依賴關係ui
UserAction中使用userService變量來維護與Service層之間的依賴關係this
userDao
public class UserDao {
public void save() {
System.out.println("DB:保存用戶");
}
}
複製代碼
public class UserService {
private UserDao userDao;
public void save() {
userDao.save();
}
}
複製代碼
public class UserAction {
private UserService userService;
public String execute() {
userService.save();
return null;
}
}
複製代碼
其實咱們在講解建立帶參數的構造函數的時候已經講過了...咱們仍是來回顧一下唄..
咱們測試service和dao的依賴關係就行了....在serice中加入一個構造函數,參數就是userDao
public UserService(UserDao userDao) {
this.userDao = userDao;
//看看有沒有拿到userDao
System.out.println(userDao);
}
複製代碼
applicationContext.xml配置文件
<!--建立userDao對象-->
<bean id="userDao" class="UserDao"/>
<!--建立userService對象-->
<bean id="userService" class="UserService">
<!--要想在userService層中可以引用到userDao,就必須先建立userDao對象-->
<constructor-arg index="0" name="userDao" type="UserDao" ref="userDao"></constructor-arg>
</bean>
複製代碼
// 建立容器對象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//獲得service對象
UserService userService = (UserService) ac.getBean("userService");
複製代碼
咱們這裏也是測試service和dao層的依賴關係就行了...在service層經過set方法來把userDao注入到UserService中
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
//看看有沒有拿到userDao
System.out.println(userDao);
}
public void save() {
userDao.save();
}
}
複製代碼
applicationContext.xml配置文件:經過property節點來給屬性賦值
<!--建立userDao對象-->
<bean id="userDao" class="UserDao"/>
<!--建立userService對象-->
<bean id="userService" class="UserService">
<property name="userDao" ref="userDao"/>
</bean>
複製代碼
咱們剛纔是先建立userDao對象,再由userService對userDao對象進行引用...咱們還有另外一種思惟:先建立userService,發現userService須要userDao的屬性,再建立userDao...咱們來看看這種思惟方式是怎麼配置的:
applicationContext.xml配置文件:property節點內置bean節點
<!-- 1.建立userService,看到有userDao這個屬性 2.而userDao這個屬性又是一個對象 3.在property屬性下又內置了一個bean 4.建立userDao -->
<bean id="userService" class="UserService">
<property name="userDao">
<bean id="userDao" class="UserDao"/>
</property>
</bean>
複製代碼
咱們發現這種思惟方式和服務器訪問的執行順序是同樣的,可是若是userDao要屢次被其餘service使用的話,就要屢次配置了...
p名稱控件這種方式其實就是set方法的一種優化,優化了配置而已...p名稱空間這個內容須要在Spring3版本以上才能使用...咱們來看看:
applicationContext.xml配置文件:使用p名稱空間
<bean id="userDao" class="UserDao"/>
<!--不用寫property節點了,直接使用p名稱空間-->
<bean id="userService" class="UserService" p:userDao-ref="userDao"/>
複製代碼
Spring還提供了自動裝配的功能,可以很是簡化咱們的配置
自動裝載默認是不打開的,自動裝配經常使用的可分爲兩種:
applicationContext.xml配置文件:使用自動裝配,根據名字
<bean id="userDao" class="UserDao"/>
<!-- 1.經過名字來自動裝配 2.發現userService中有個叫userDao的屬性 3.看看IOC容器中沒有叫userDao的對象 4.若是有,就裝配進去 -->
<bean id="userService" class="UserService" autowire="byName"/>
複製代碼
applicationContext.xml配置文件:使用自動裝配,根據類型
值得注意的是:若是使用了根據類型來自動裝配,那麼在IOC容器中只能有一個這樣的類型,不然就會報錯!
<bean id="userDao" class="UserDao"/>
<!-- 1.經過名字來自動裝配 2.發現userService中有個叫userDao的屬性 3.看看IOC容器UserDao類型的對象 4.若是有,就裝配進去 -->
<bean id="userService" class="UserService" autowire="byType"/>
複製代碼
咱們這只是測試兩個對象之間的依賴關係,若是咱們有不少對象,咱們也能夠使用默認自動分配
###使用註解來實現自動裝配###
@Autowired註解來實現自動裝配:
若是沒有匹配到bean,又爲了不異常的出現,咱們可使用required屬性上設置爲false。【謹慎對待】
@Component
public class UserService {
private UserDao userDao ;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
複製代碼
順利拿到userDao的引用
在有兩種方法(但我測試不出來,若是會的請在評論去告訴我.....)
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService() {
//直接調用@bean的方法
return new UserService(userDao());
}
}
複製代碼
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean
public UserService userService(UserDao userDao) {
//經過構造函數依賴注入
return new UserService(userDao);
}
}
複製代碼
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService(UserDao userDao) {
return new UserService(userDao);
}
}
複製代碼
public class Configuration {
@Bean()
public UserDao userDao() {
return new UserDao();
}
@Bean(autowire = Autowire.BY_TYPE)
public UserService userService() {
return new UserService(userDao());
}
}
複製代碼
固然了,最簡單直觀的方法還有一種:在UserService中加入setUser()方法,那麼只要set進去就好了..
public class UserService {
private UserDao userDao ;
public UserService() {
}
public UserService(UserDao userDao) {
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
複製代碼
import org.springframework.context.annotation.Bean;
@org.springframework.context.annotation.Configuration
public class Config1 {
@Bean(name = "userDao")
public UserDao userDao() {
return new UserDao();
}
@Bean(name="userService")
public UserService userService() {
UserService userService = new UserService();
userService.setUserDao(userDao());
return userService;
}
}
複製代碼
擴展閱讀:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y