Spring【依賴注入】就是這麼簡單

前言

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

回顧之前對象依賴

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

直接new對象

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

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

  • 後來,咱們發現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);
        }
    }

}
  • 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層就是透明的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;
	}
	
}
  • service
UserDao dao = DaoFactory.getInstance().createUserDao();

Spring依賴注入

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

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

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

搭建測試環境

  • UserService中使用userDao變量來維護與Dao層之間的依賴關係ui

  • UserAction中使用userService變量來維護與Service層之間的依賴關係this

  • 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的依賴關係就行了....在service中加入一個構造函數,參數就是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的引用

 

這裏寫圖片描述

 

使用JavaConfig配置類實現對象依賴

在有兩種方法(但我測試不出來,若是會的請在評論去告訴我.....)

  • 第一種(測試不出來)
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);
    }

}

 

這裏寫圖片描述

 

  • 我測試中只有經過這種方法才能拿到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進去就好了..

  • UserService
public class UserService {

    private UserDao userDao ;

    public UserService() {
    }

    public UserService(UserDao userDao) {


    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}
  • Config
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

相關文章
相關標籤/搜索