Spring第三篇【Core模塊之對象依賴】

前言

在Spring的第二篇中主要講解了Spring Core模塊的使用IOC容器建立對象的問題,Spring Core模塊主要是解決對象的建立和對象之間的依賴關係,所以本博文主要講解如何使用IOC容器來解決對象之間的依賴關係php

回顧之前對象依賴

咱們來看一下咱們之前關於對象依賴,是怎麼的歷程java

直接new對象

  • 在最開始,咱們是直接new對象給serice的userDao屬性賦值…
class UserService{
    UserDao userDao = new UserDao();
}

寫DaoFactory,用字符串來維護依賴關係

  • 後來,咱們發現service層牢牢耦合了dao層。咱們就寫了DaoFactory,在service層只要經過字符串就可以建立對應的dao層的對象了。spring

  • 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);
        }
    }

}
  • serivce
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);

DaoFactory讀取配置文件

  • 再後來,咱們發現要修改Dao的實現類,仍是得修改service層的源代碼呀..因而咱們就在DaoFactory中讀取關於daoImpl的配置文件,根據配置文件來建立對象,這樣一來,建立的是哪一個daoImpl對service層就是透明的markdown

  • DaoFactoryapp

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; } } 
  • service
UserDao dao = DaoFactory.getInstance().createUserDao();

Spring依賴注入

經過上面的歷程,咱們能夠清晰地發現:對象之間的依賴關係,其實就是給對象上的屬性賦值!由於對象上有其餘對象的變量,所以存在了依賴框架

Spring提供了好幾種的方式來給屬性賦值函數

  • 1) 經過構造函數
  • 2) 經過set方法給屬性注入值
  • 3) p名稱空間
  • 4)自動裝配(瞭解)
  • 5) 註解

搭建測試環境

  • UserService中使用userDao變量來維護與Dao層之間的依賴關係
  • UserAction中使用userService變量來維護與Service層之間的依賴關係測試

  • userDao優化

public class UserDao {

    public void save() {
        System.out.println("DB:保存用戶");
    }
}
  • userService
public class UserService {

    private UserDao userDao; 

    public void save() {
        userDao.save();
    }
}
  • userAnction
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>
  • 測試:能夠成功獲取到userDao對象
// 建立容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

        //獲得service對象
        UserService userService = (UserService) ac.getBean("userService");

這裏寫圖片描述


經過set方法給屬性注入值

咱們這裏也是測試service和dao層的依賴關係就行了…在service層經過set方法來把userDao注入到UserService中

  • 爲UserService添加set方法
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節點來給屬性賦值

  • 引用類型使用ref屬性
  • 基本類型使用value屬性
<!--建立userDao對象-->
    <bean id="userDao" class="UserDao"/>

    <!--建立userService對象-->
    <bean id="userService" class="UserService">
        <property name="userDao" ref="userDao"/>
    </bean>
  • 測試:

這裏寫圖片描述


內部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 名稱空間注入屬性值

p名稱控件這種方式其實就是set方法的一種優化,優化了配置而已…p名稱空間這個內容須要在Spring3版本以上才能使用…咱們來看看:

applicationContext.xml配置文件:使用p名稱空間

<bean id="userDao" class="UserDao"/>

    <!--不用寫property節點了,直接使用p名稱空間-->
    <bean id="userService" class="UserService" p:userDao-ref="userDao"/>
  • 測試

這裏寫圖片描述


自動裝配

Spring還提供了自動裝配的功能,可以很是簡化咱們的配置

自動裝載默認是不打開的,自動裝配經常使用的可分爲兩種:

  • 根據名字來裝配
  • 根據類型類裝配

XML配置根據名字

applicationContext.xml配置文件:使用自動裝配,根據名字

<bean id="userDao" class="UserDao"/>

    <!-- 1.經過名字來自動裝配 2.發現userService中有個叫userDao的屬性 3.看看IOC容器中沒有叫userDao的對象 4.若是有,就裝配進去 -->
    <bean id="userService" class="UserService" autowire="byName"/>
  • 測試

這裏寫圖片描述


XML配置根據類型

applicationContext.xml配置文件:使用自動裝配,根據類型

值得注意的是:若是使用了根據類型來自動裝配,那麼在IOC容器中只能有一個這樣的類型,不然就會報錯!

<bean id="userDao" class="UserDao"/>

    <!-- 1.經過名字來自動裝配 2.發現userService中有個叫userDao的屬性 3.看看IOC容器UserDao類型的對象 4.若是有,就裝配進去 -->
    <bean id="userService" class="UserService" autowire="byType"/>
  • 測試:

這裏寫圖片描述


咱們這只是測試兩個對象之間的依賴關係,若是咱們有不少對象,咱們也能夠使用默認自動分配

這裏寫圖片描述


使用註解來實現自動裝配

@Autowired註解來實現自動裝配:

  • 能夠在構造器上修飾
  • 也能夠在setter方法上修飾
  • 來自java的@Inject的和@AutoWired有相同的功能

若是沒有匹配到bean,又爲了不異常的出現,咱們可使用required屬性上設置爲false。【謹慎對待】

  • 測試代碼
@Component
public class UserService {

    private UserDao userDao ;


    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

順利拿到userDao的引用

這裏寫圖片描述

註解

自從jdk5有了註解這個新特性,咱們能夠看到Struts2框架、Hibernate框架都支持使用註解來配置信息…

經過註解來配置信息就是爲了簡化IOC容器的配置,註解能夠把對象添加到IOC容器中、處理對象依賴關係,咱們來看看怎麼用吧:

使用註解步驟:

  • 1)先引入context名稱空間
    • xmlns:context=」http://www.springframework.org/schema/context」
  • 2)開啓註解掃描器
    • <context:component-scan base-package=""></context:component-scan>
    • 也能夠經過自定義掃描類以@CompoentScan修飾來掃描IOC容器的bean對象
//代表該類是配置類
@Configuration

//啓動掃描器,掃描bb包下的
    //也能夠指定多個基礎包
    //也能夠指定類型
@ComponentScan("bb")
public class AnnotationScan {

}

在使用@ComponentScan()這個註解的時候,在測試類上須要@ContextConfiguration這個註解來加載配置類…

  • @ContextConfiguration這個註解又在Spring的test包下..

建立對象以及處理對象依賴關係,相關的註解:

  • @ComponentScan掃描器
  • @Configuration代表該類是配置類
  • @Component 指定把一個對象加入IOC容器—>@Name也能夠實現相同的效果【通常少用】
  • @Repository 做用同@Component; 在持久層使用
  • @Service 做用同@Component; 在業務邏輯層使用
  • @Controller 做用同@Component; 在控制層使用
  • @Resource 依賴關係
    • 若是@Resource不指定值,那麼就根據類型來找,相同的類型在IOC容器中不能有兩個
    • 若是@Resource指定了值,那麼就根據名字來找

測試代碼

  • UserDao
package aa;

import org.springframework.stereotype.Repository;

/** * Created by ozc on 2017/5/10. */

//把對象添加到容器中,首字母會小寫
@Repository
public class UserDao {

    public void save() {
        System.out.println("DB:保存用戶");
    }


}
  • userService
package aa;


import org.springframework.stereotype.Service;

import javax.annotation.Resource;


//把UserService對象添加到IOC容器中,首字母會小寫
@Service
public class UserService {

    //若是@Resource不指定值,那麼就根據類型來找--->UserDao....固然了,IOC容器不能有兩個UserDao類型的對象
    //@Resource

    //若是指定了值,那麼Spring就在IOC容器找有沒有id爲userDao的對象。
    @Resource(name = "userDao")
    private UserDao userDao;

    public void save() {
        userDao.save();
    }
}
  • userAction
package aa;

import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

/** * Created by ozc on 2017/5/10. */

//把對象添加到IOC容器中,首字母會小寫
@Controller
public class UserAction {

    @Resource(name = "userService")
    private UserService userService;

    public String execute() {
        userService.save();
        return null;
    }
}
  • 測試
package aa;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * Created by ozc on 2017/5/10. */
public class App {

    public static void main(String[] args) {

        // 建立容器對象
        ApplicationContext ac = new ClassPathXmlApplicationContext("aa/applicationContext.xml");

        UserAction userAction = (UserAction) ac.getBean("userAction");

        userAction.execute();
    }
}

這裏寫圖片描述

註解和XML配置是能夠混合使用的…

相關文章
相關標籤/搜索