再學一遍Spring IOC 注入會有新的認識--樂字節微服務

Spring IOC 注入

手動實例化與外部引入html

圖一:
Spring-07.png
圖二:
Spring-08.pngjava

​ 對比發現:圖二中對於 UserDao 對象的建立並無像圖一那樣主動的去實例化,而是經過帶參方法形式將UserDao 傳入過來,從而實現 UserService 對UserDao類 的依賴。spring

而實際建立對象的幕後對象便是交給了外部來建立。ide

Spring IOC 手動裝配(注入)

​ Spring 支持的注入方式共有四種:set 注入、構造器注入、靜態工廠注入、實例化工廠注入。函數

set方法注入

注:測試

  • 屬性字段須要提供set方法
  • 四種方式,推薦使用set方法注入
業務對象 JavaBean
  1. 屬性字段提供set方法this

    public class UserService {
    
       // 業務對象UserDao set注入(提供set方法)
       private UserDao userDao;
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
       }
    }
  2. 配置文件的bean標籤設置property標籤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
           https://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <!--
           IOC經過property標籤手動裝配(注入):
               Set方法注入
                   name:bean對象中屬性字段的名稱
                   ref:指定bean標籤的id屬性值
       --> 
       <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
    <bean id="userService" class="com.xxxx.service.UserService">
           <!--業務對象 注入-->
           <property name="userDao" ref="userDao"/>
       </bean>
    </beans>
經常使用對象和基本類型
  1. 屬性字段提供set方法component

    public class UserService {
    
       // 經常使用對象String  set注入(提供set方法)
       private String host;
       public void setHost(String host) {
           this.host = host;
       }
    
       // 基本類型Integer   set注入(提供set方法)
       private Integer port;
       public void setPort(Integer port) {
           this.port = port;
       }
    }
  2. 配置文件的bean標籤設置property標籤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
           https://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <!--
           IOC經過property標籤手動裝配(注入):
               Set方法注入
                   name:bean對象中屬性字段的名稱
                   value:具體的值(基本類型 經常使用對象|日期  集合)
       --> 
    <bean id="userService" class="com.xxxx.service.UserService">
           <!--經常使用對象String 注入-->
           <property name="host" value="127.0.0.1"/>
           <!--基本類型注入-->
           <property name="port" value="8080"/>
       </bean>
    
    </beans>
集合類型和屬性對象
  1. 屬性字段提供set方法

    public class UserService {
    
       // List集合  set注入(提供set方法)
       public List<String> list;
       public void setList(List<String> list) {
           this.list = list;
       }
    
       // Set集合  set注入(提供set方法)
       private Set<String> set;
       public void setSet(Set<String> set) {
           this.set = set;
       }
    
       // Map set注入(提供set方法)
       private Map<String,Object> map;
       public void setMap(Map<String, Object> map) {
           this.map = map;
       }
    
       // Properties set注入(提供set方法)
       private Properties properties;
       public void setProperties(Properties properties) {
           this.properties = properties;
       }
    
    }
  2. 配置文件的bean標籤設置property標籤

    <?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
           https://www.springframework.org/schema/beans/spring-beans.xsd">
    
      <!--
           IOC經過property標籤手動裝配(注入):
               Set方法注入
                   name:bean對象中屬性字段的名稱
                   value:具體的值(基本類型 經常使用對象|日期  集合)
       --> 
    <!--List集合 注入-->
       <property name="list">
           <list>
               <value>上海</value>
               <value>北京</value>
               <value>杭州</value>
           </list>
       </property>
    
       <!--Set集合注入-->
       <property name="set">
           <set>
               <value>上海SH</value>
               <value>北京BJ</value>
               <value>杭州HZ</value>
           </set>
       </property>
    
       <!--Map注入-->
       <property name="map">
           <map>
               <entry>
                   <key><value>周杰倫</value></key>
                   <value>我是如此相信</value>
               </entry>
               <entry>
                   <key><value>林俊杰</value></key>
                   <value>惋惜沒若是</value>
               </entry>
               <entry>
                   <key><value>陳奕迅</value></key>
                   <value>十年</value>
               </entry>
           </map>
       </property>
    
       <!--Properties注入-->
       <property name="properties">
           <props>
               <prop key="上海">東方明珠</prop>
               <prop key="北京">天安門</prop>
               <prop key="杭州">西湖</prop>
           </props>
       </property>
    
    </beans>
測試代碼

UserService.java

public class UserService {

    // 業務對象UserDao set注入(提供set方法)
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    // 經常使用對象String  set注入(提供set方法)
    private String host;
    public void setHost(String host) {
        this.host = host;
    }

    // 基本類型Integer   set注入(提供set方法)
    private Integer port;
    public void setPort(Integer port) {
        this.port = port;
    }

    // List集合  set注入(提供set方法)
    public List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    // List集合輸出
    public void printList() {
        list.forEach(s -> System.out.println(s));
    }

    // Set集合  set注入(提供set方法)
    private Set<String> set;
    public void setSet(Set<String> set) {
        this.set = set;
    }
    // Set集合輸出
    public void printSet() {
        set.forEach(s -> System.out.println(s));
    }

    // Map set注入(提供set方法)
    private Map<String,Object> map;
    public void setMap(Map<String, Object> map) {
        this.map = map;
    }
    // Map輸出
    public void printMap() {
        map.forEach((k,v) -> System.out.println(k + "," + v));
    }

    // Properties set注入(提供set方法)
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    // Properties輸出
    public  void printProperties(){
        properties.forEach((k,v) -> System.out.println(k + ","+ v ));
    }

    public  void  test(){
        System.out.println("UserService Test...");

        userDao.test();

        studentDao.test();

        System.out.println("Host:" + host  + ",port:" + port);

        // List集合
        printList();

        // Set集合
        printSet();

        // Map
        printMap();

        // Properties
        printProperties();

    }
}

spring.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        IOC經過property標籤手動裝配(注入):
            Set方法注入
                name:bean對象中屬性字段的名稱
                ref:指定bean標籤的id屬性值
                value:具體的值(基本類型 經常使用對象|日期  集合)

    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
    <bean id="userService" class="com.xxxx.service.UserService">
        <!--業務對象 注入-->
        <property name="userDao" ref="userDao"/>
        <property name="studentDao" ref="studentDao"/>

        <!--經常使用對象String 注入-->
        <property name="host" value="192.168.1.109"/>
        <!--基本類型注入-->
        <property name="port" value="8080"/>

        <!--List集合 注入-->
        <property name="list">
            <list>
                <value>上海</value>
                <value>北京</value>
                <value>杭州</value>
            </list>
        </property>

        <!--Set集合注入-->
        <property name="set">
            <set>
                <value>上海SH</value>
                <value>北京BJ</value>
                <value>杭州HZ</value>
            </set>
        </property>

        <!--Map注入-->
        <property name="map">
            <map>
                <entry>
                    <key><value>周杰倫</value></key>
                    <value>我是如此相信</value>
                </entry>
                <entry>
                    <key><value>林俊杰</value></key>
                    <value>惋惜沒若是</value>
                </entry>
                <entry>
                    <key><value>陳奕迅</value></key>
                    <value>十年</value>
                </entry>
            </map>
        </property>

        <!--Properties注入-->
        <property name="properties">
            <props>
                <prop key="上海">東方明珠</prop>
                <prop key="北京">天安門</prop>
                <prop key="杭州">西湖</prop>
            </props>
        </property>

    </bean>

</beans>

構造器注入

注:

  • 提供帶參構造器
單個Bean對象做爲參數

Java 代碼

public class UserService {

    private UserDao userDao; // JavaBean 對象

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public  void  test(){
        System.out.println("UserService Test...");

        userDao.test();
    }

}

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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
        IOC經過構造器注入:
            經過constructor-arg標籤進行注入
                name:屬性名稱
                ref:指定bean標籤的id屬性值
    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>

    <bean id="userService" class="com.xxxx.service.UserService">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
    </bean>

</beans>
多個Bean對象做爲參數

Java 代碼

public class UserService {

    private UserDao userDao;  // JavaBean 對象
    private AccountDao accountDao  // JavaBean 對象

    public UserService(UserDao userDao, AccountDao accountDao) {
        this.userDao = userDao;
        this.accountDao = accountDao;
    }

    public  void  test(){
        System.out.println("UserService Test...");

        userDao.test();
        accountDao.test();
    }

}

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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
     <!--
        IOC經過構造器注入:
            經過constructor-arg標籤進行注入
                name:屬性名稱
                ref:指定bean標籤的id屬性值
    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
    <bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>

    <bean id="userService" class="com.xxxx.service.UserService">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
        <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
    </bean>

</beans>
Bean對象和經常使用對象做爲參數

Java 代碼

public class UserService {

    private UserDao userDao;  // JavaBean 對象
    private AccountDao accountDao;  // JavaBean 對象
    private String uname;  // 字符串類型

    public UserService(UserDao userDao, AccountDao accountDao, String uname) {
        this.userDao = userDao;
        this.accountDao = accountDao;
        this.uname = uname;
    }

    public  void  test(){
        System.out.println("UserService Test...");

        userDao.test();
        accountDao.test();
        System.out.println("uname:" + uname);
    }

}

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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
        IOC經過構造器注入:
            經過constructor-arg標籤進行注入
                name:屬性名稱
                ref:指定bean標籤的id屬性值
                value:基本類型 經常使用對象的值
                index:構造器中參數的下標,從0開始
    -->
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
    <bean id="accountDao" class="com.xxxx.dao.AccountDao" ></bean>
    <bean id="userService" class="com.xxxx.service.UserService">
        <constructor-arg name="userDao" ref="userDao"></constructor-arg> 
        <constructor-arg name="accountDao" ref="accountDao"></constructor-arg>
        <constructor-arg name="uname" value="admin"></constructor-arg>
    </bean>

</beans>
循環依賴問題

循環問題產生的緣由:

​ Bean經過構造器注入,之間彼此相互依賴對方致使bean沒法實例化。

問題展現:

  1. Java 代碼

    public class AccountService {
    
       private RoleService roleService;
    
      public AccountService(RoleService roleService) {
           this.roleService = roleService;
       }
    
       public void  test() {
           System.out.println("AccountService Test...");
       }
    }
    
    public class RoleService {
    
       private AccountService accountService;
    
      public RoleService(AccountService accountService) {
           this.accountService = accountService;
       }
    
       public void  test() {
           System.out.println("RoleService Test...");
       }
    }
  2. XML配置

    <!--
        若是多個bean對象中互相注入,則會出現循環依賴的問題
        能夠經過set方法注入解決
    -->
    <bean id="accountService" class="com.xxxx.service.AccountService">
       <constructor-arg name="roleService" ref="roleService"/>
    </bean>
    
    <bean id="roleService" class="com.xxxx.service.RoleService">
       <constructor-arg name="accountService" ref="accountService"/>
    </bean>

若有疑問,可加入羣:10803-55292,輸入暗號13,便可有大佬傳授十年經驗

如何解決:將構造器注入改成set方法注入

  1. Java代碼

    public class AccountService {
    
       private RoleService roleService;
    
      /* public AccountService(RoleService roleService) {
           this.roleService = roleService;
       }*/
    
       public void setRoleService(RoleService roleService) {
           this.roleService = roleService;
       }
    
       public void  test() {
           System.out.println("AccountService Test...");
       }
    }
    
    public class RoleService {
    
       private AccountService accountService;
    
      /* public RoleService(AccountService accountService) {
           this.accountService = accountService;
       }*/
    
       public void setAccountService(AccountService accountService) {
           this.accountService = accountService;
       }
    
       public void  test() {
           System.out.println("RoleService Test...");
       }
    }
  2. XML配置

    <!--
    <bean id="accountService" class="com.xxxx.service.AccountService">
       <constructor-arg name="roleService" ref="roleService"/>
       </bean>
    
       <bean id="roleService" class="com.xxxx.service.RoleService">
           <constructor-arg name="accountService" ref="accountService"/>
       </bean>
    -->
    <!--修改成set方法注入-->
    <bean id="accountService" class="com.xxxx.service.AccountService">
       <property name="roleService" ref="roleService"/>
    </bean>
    
    <bean id="roleService" class="com.xxxx.service.RoleService">
       <property name="accountService" ref="accountService"/>
    </bean>

靜態工廠注入

  1. 定義靜態工廠類

    public class StaticFactory {
    
       // 定義靜態方法
       public static TypeDao createTypeDao() {
           return new TypeDao();
       }
    }
  2. Java代碼

    public class TypeService {
    
       private TypeDao typeDao;
    
       public void setTypeDao(TypeDao typeDao) {
           this.typeDao = typeDao;
       }
    
       public void  test() {
           System.out.println("TypeService Test...");
       }
    }
  3. XML配置

    在配置文件中設置bean標籤,指定工廠對象並設置對應的方法

    <bean id="typeService" class="com.xxxx.service.TypeService">
    <property name="typeDao" ref="typeDao"/>
    </bean>
    <!--
    靜態工廠注入:
        靜態工廠注入也是藉助set方法注入,只是被注入的bean對象的實例化是經過靜態工廠實例化的
    -->
    <bean id="typeDao" class="com.xxxx.factory.StaticFactory" factory-method="createTypeDao"></bean>

實例化工廠注入

  1. 定義工廠類

    public class InstanceFactory {
        public TypeDao createTypeDao() {
           return new TypeDao();
       }
    }
  2. Java代碼

    public class TypeService {
    
       private TypeDao typeDao;
    
       public void setTypeDao(TypeDao typeDao) {
           this.typeDao = typeDao;
       }
    
       public void  test() {
           System.out.println("TypeService Test...");
       }
    }
  3. XML配置

    聲明工廠bean標籤,聲明bean對象,指明工廠對象和工廠方法

    <bean id="typeService" class="com.xxxx.service.TypeService">
    <property name="typeDao" ref="typeDao"/>
    </bean>
    <!--
    實例化工廠注入:
        實例化工廠注入也是藉助set方法注入,只是被注入的bean對象的實例化是經過實例化工廠實例化的
    -->
    <bean id="instanceFactory" class="com.xxxx.factory.InstanceFactory"></bean>
    <bean id="typeDao" factory-bean="instanceFactory" factory-method="createTypeDao"></bean>

    重點掌握set注入和構造器注入,工廠方式瞭解便可。實際開發中基本使用set方式注入bean。

注入方式的選擇

開發項目中set方式注入首選

​ 使用構造注入能夠在構建對象的同時一併完成依賴關係的創建,對象一創建則全部的一切也就準備好了,但若是要創建的對象關係不少,使用構造器注入會在構建函數上留下一長串的參數,且不易記憶,這時使用Set注入會是個不錯的選擇。
  使用Set注入能夠有明確的名稱,能夠了解注入的對象會是什麼,像setXXX()這樣的名稱會比記憶Constructor上某個參數的位置表明某個對象更好。

p名稱空間的使用

​ spring2.5之後,爲了簡化setter方法屬性注入,引用p名稱空間的概念,能夠將<property> 子元素,簡化爲<bean>元素屬性配置。

  1. 屬性字段提供 set 方法

    public class UserService {
    
       // 業務對象UserDao set注入(提供set方法)
       private UserDao userDao;
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
       }
    
       // 經常使用對象String  set注入(提供set方法)
       private String host;
       public void setHost(String host) {
           this.host = host;
       }
    }
  2. 在配置文件 spring.xml 引入 p 名稱空間

    xmlns:p="http://www.springframework.org/schema/p"
    <?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:p="http://www.springframework.org/schema/p"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
       <!--
        p:屬性名:="xxx"        引入常量值
        p:屬性名-ref:="xxx"    引入其餘Bean對象的id屬性值
    -->
       <bean id="userService" class="com.xxxx.service.UserService" 
           p:userDao-ref="userDao" 
           p:host="127.0.0.1" />
    
    </beans>

Spring IOC 自動裝配(注入)

註解方式注入 Bean

​ 對於 bean 的注入,除了使用 xml 配置之外,可使用註解配置。註解的配置,能夠簡化配置文件,提升開發的速度,使程序看上去更簡潔。對於註解的解釋,Spring對於註解有專門的解釋器,對定義的註解進行解析,實現對應bean對象的注入。經過反射技術實現

準備環境

  1. 修改配置文件

    <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          https://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
  2. 開啓自動化注入

    <!--開啓自動化裝配(注入)-->
    <context:annotation-config/>
    
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
    <bean id="userService" class="com.xxxx.service.UserService"></bean>
  3. 給注入的bean對象添加註解

@Resource註解

@Resource註解實現自動注入(反射)

  • 默認根據屬性字段名稱查找對應的bean對象 (屬性字段的名稱與bean標籤的id屬性值相等)
  • 若是屬性字段名稱未找到,則會經過類型(Class類型)查找
  • 屬性能夠提供set方法,也能夠不提供set方法
  • 註解能夠聲明在屬性級別 或 set方法級別
  • 能夠設置name屬性,name屬性值必須與bean標籤的id屬性值一致;若是設置了name屬性值,就只會按照name屬性值查找bean對象
  • 當注入接口時,若是接口只有一個實現則正常實例化;若是接口存在多個實現,則須要使用name屬性指定須要被實例化的bean對象

代碼示例

  1. 默認根據屬性字段名稱查找對應的bean對象 (屬性字段的名稱與bean標籤的id屬性值相等)

    /**
    * @Resource註解實現自動注入(反射)
    *  默認根據屬性字段名稱查找對應的bean對象 (屬性字段的名稱與bean標籤的id屬性值相等)
    */
    public class UserService {
    
       @Resource
       private UserDao userDao; // 屬性字段的名稱與bean標籤的id屬性值相等
    
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
       }
    
       public void test() {
           // 調用UserDao的方法
           userDao.test();
       }
    }
  2. 若是屬性字段名稱未找到,則會經過類型(Class類型)查找

    /**
    * @Resource註解實現自動注入(反射)
    *   若是屬性字段名稱未找到,則會經過類型(Class類型)查找
    */
    public class UserService {
    
       @Resource
       private UserDao ud; // 當在配置文件中屬性字段名(ud)未找到,則會查找對應的class(UserDao類型)
    
       public void setUd(UserDao ud) {
           this.ud = ud;
       }
    
       public void test() {
           // 調用UserDao的方法
           ud.test();
       }
    }
  3. 屬性能夠提供set方法,也能夠不提供set方法

    /**
    * @Resource註解實現自動注入(反射)
    *   屬性能夠提供set方法,也能夠不提供set方法
    */
    public class UserService {
    
       @Resource
       private UserDao userDao; // 不提供set方法
    
       public void test() {
           // 調用UserDao的方法
           userDao.test();
       }
    }
  4. 註解能夠聲明在屬性級別 或 set方法級別

    /**
    * @Resource註解實現自動注入(反射)
    *   註解能夠聲明在屬性級別 或 set方法級別
    */
    public class UserService {
    
       private UserDao userDao;
    
       @Resource // 註解也可設置在set方法上
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
       }
    
       public void test() {
           // 調用UserDao的方法
           userDao.test();
       }
    }
  5. 能夠設置name屬性,name屬性值必須與bean標籤的id屬性值一致;若是設置了name屬性值,就只會按照name屬性值查找bean對象

    /**
    * @Resource註解實現自動注入(反射)
    *   能夠設置name屬性,name屬性值必須與bean的id屬性值一致;
    *   若是設置了name屬性值,就只會按照name屬性值查找bean對象
    */
    public class UserService {
    
       @Resource(name = "userDao") // name屬性值與配置文件中bean標籤的id屬性值一致
       private UserDao ud;
    
       public void test() {
           // 調用UserDao的方法
           ud.test();
       }
    }
  6. 當注入接口時,若是接口只有一個實現則正常實例化;若是接口存在多個實現,則須要使用name屬性指定須要被實例化的bean對象

    定義接口類 IUserDao.java

    package com.xxxx.dao;
    
    /**
    * 定義接口類
    */
    public interface IUserDao {
       public void test();
    }

    定義接口實現類 UserDao01.java

    package com.xxxx.dao;
    
    /**
    * 接口實現類
    */
    public class UserDao01 implements IUserDao {
    
       @Override
       public void test(){
           System.out.println("UserDao01...");
       }
    }

    定義接口實現類 UserDao02.java

    package com.xxxx.dao;
    
    /**
    * 接口實現類
    */
    public class UserDao02 implements IUserDao {
    
       @Override
       public void test(){
           System.out.println("UserDao02...");
       }
    }

    XML配置文件

    <!--開啓自動化裝配(注入)-->
    <context:annotation-config/>
    
    <bean id="userService" class="com.xxxx.service.UserService"></bean>
    
    <bean id="userDao01" class="com.xxxx.dao.UserDao01"></bean>
    <bean id="userDao02" class="com.xxxx.dao.UserDao01"></bean>

    使用註解 UserService.java

    /**
    * @Resource註解實現自動注入(反射)
    *   當注入接口時,若是接口只有一個實現則正常實例化;若是接口存在多個實現,則須要使用name屬性指定須要被實例化的bean對象
    */
    public class UserService {
    
       @Resource(name = "userDao01") // name屬性值與其中一個實現類的bean標籤的id屬性值一致
       private IUserDao iUserDao; // 注入接口(接口存在多個實現)
    
       public void test() {
           iUserDao.test();
       }
    }

@Autowired註解

@Autowired註解實現自動化注入:

  • 默認經過類型(Class類型)查找bean對象 與屬性字段的名稱無關
  • 屬性能夠提供set方法,也能夠不提供set方法
  • 註解能夠聲明在屬性級別 或 set方法級別
  • 能夠添加@Qualifier結合使用,經過value屬性值查找bean對象(value屬性值必需要設置,且值要與bean標籤的id屬性值對應)
  1. 默認經過類型(Class類型)查找bean對象 與屬性字段的名稱無關

    /**
    * @Autowired註解實現自動化注入
    *  默認經過類型(Class類型)查找bean對象   與屬性字段的名稱無關
    */
    public class UserService {
    
       @Autowired
       private UserDao userDao; // 默認經過類型(Class類型)查找bean對象  與屬性字段的名稱無關
    
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
       }
    
       public void test() {
           // 調用UserDao的方法
           userDao.test();
       }
    }
  2. 屬性能夠提供set方法,也能夠不提供set方法

    /**
    * @Autowired註解實現自動化注入
    *  屬性能夠提供set方法,也能夠不提供set方法
    */
    public class UserService {
    
       @Autowired
       private UserDao userDao; // 不提供set方法
    
       public void test() {
           // 調用UserDao的方法
           userDao.test();
       }
    }
  3. 註解能夠聲明在屬性級別 或 set方法級別

    /**
    * @Autowired註解實現自動化注入
    *  註解能夠聲明在屬性級別 或 set方法級別
    */
    public class UserService {
    
       private UserDao userDao; 
    
       @Autowired// 註解能夠聲明在set方法級別
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
       }
    
       public void test() {
           // 調用UserDao的方法
           userDao.test();
       }
    }
  4. 能夠添加@Qualifier結合使用,經過value屬性值查找bean對象(value屬性值必需要設置,且值要與bean標籤的id屬性值對應)

    /**
    * @Autowired註解實現自動化注入
    *  能夠添加@Qualifier結合使用,經過value屬性值查找bean對象
            value屬性值必需要設置,且值要與bean標籤的id屬性值對應
    */
    public class UserService {
    
       @Autowired
       @Qualifier(value="userDao") // value屬性值必需要設置,且值要與bean標籤的id屬性值對應
       private UserDao userDao;
    
       public void test() {
           userDao.test();
       }
    }

    推薦使用@Resource 註解是屬於J2EE的,減小了與Spring的耦合。

Spring IOC 掃描器

​ 實際的開發中,bean的數量很是多,採用手動配置bean的方式已沒法知足生產須要,Spring這時候一樣提供了掃描的方式,對掃描到的bean對象統一進行管理,簡化開發配置,提升開發效率。

Spring IOC 掃描器的配置

Spring IOC 掃描器
    做用:bean對象統一進行管理,簡化開發配置,提升開發效率

    一、設置自動化掃描的範圍
             若是bean對象未在指定包範圍,即便聲明瞭註解,也沒法實例化
    二、使用指定的註解(聲明在類級別)    bean對象的id屬性默認是 類的首字母小寫
          Dao層:
             @Repository
          Service層:
             @Service
          Controller層:
             @Controller
          任意類:
             @Component
     注:開發過程當中建議按照指定規則聲明註解
  1. 設置自動化掃描範圍

    <?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:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          https://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
    
       <!-- 設置自動化掃描的範圍 -->
       <context:component-scan base-package="com.xxxx"/>
    
    </beans>
  2. 使用特定的註解

    @Repository (Dao層)

    @Repository
    public class ResourceDao {
    
       public void  test() {
           System.out.println("ResourceDao...");
       }
    }

    @Service(Service層 )

    @Service
    public class ResourceService {
    
       @Resource
       private ResourceDao resourceDao; // service層注入dao層的bean對象
    
       public  void  test() {
           System.out.println("ResourceService...");
           resourceDao.test();
       }
    }

    @Controller (Controller 層 )

    @Controller
    public class ResourceController {
    
       @Autowired
       private ResourceService resourceService; // Controller層注入service層的bean對象
    
       public  void  test() {
           System.out.println("ResourceController...");
           resourceService.test();
       }
    }

    @Component (任意層)

    @Component
    public class PropertyUtils {
       public void test(){
           System.out.println("PropertyUtils...");
       }
    }

Spring 模擬用戶登陸流程

Dao層 (查詢用戶記錄)

  1. 定義JavaBean User.java

    package com.xxxx.po;
    
    /**
    * User 用戶實體類
    */
    public class User {
    
       private String userName; // 用戶名稱
       private String userPwd; // 用戶密碼
    
       public String getUserName() {
           return userName;
       }
    
       public void setUserName(String userName) {
           this.userName = userName;
       }
    
       public String getUserPwd() {
           return userPwd;
       }
    
       public void setUserPwd(String userPwd) {
           this.userPwd = userPwd;
       }
    }
  2. 編寫Dao層 UserDao.java

    package com.xxxx.dao;
    
    import com.xxxx.po.User;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserDao {
    
       private final String USERNAME = "admin";
       private final String USERPWD = "admin";
    
       /**
        * 經過用戶名稱查詢用戶對象
        * @param userName
        * @return
        */
       public User queryUserByUserName(String userName){
           User user = null;
           // 判斷用戶名稱是否正確
           if(!USERNAME.equals(userName)){
               // 若是不正確,返回null
               return null;
           }
           // 若是正確,將用戶名稱和密碼設置到user對象中
           user = new User();
           user.setUserName(USERNAME);
           user.setUserPwd(USERPWD);
    
           return user;
       }
    }

Service層 (業務邏輯處理)

  1. 定義業務處理返回消息模型 MessageModel.java

    package com.xxxx.po.vo;
    
    /**
    * 定義業務處理返回消息模型
    *     封裝返回結果
    */
    public class MessageModel {
    
       private Integer resultCode = 1; // 結果狀態碼  1=成功,0=失敗
       private String resultMsg = "操做成功!"; // 結果提示信息
    
       public Integer getResultCode() {
           return resultCode;
       }
    
       public void setResultCode(Integer resultCode) {
           this.resultCode = resultCode;
       }
    
       public String getResultMsg() {
           return resultMsg;
       }
    
       public void setResultMsg(String resultMsg) {
           this.resultMsg = resultMsg;
       }
    }
  2. 編寫Service層 UserService.java

    package com.xxxx.service;
    
    import com.xxxx.dao.UserDao1;
    import com.xxxx.po.User;
    import com.xxxx.po.vo.MessageModel;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    
    @Service
    public class UserService {
       @Resource
       private UserDao userDao;
    
       /**
        * 驗證用戶登陸
        * @param userName
        * @param userPwd
        * @return
        */
       public MessageModel userLoginCheck(String userName, String userPwd){
           // 定義業務處理返回消息模型
           MessageModel messageModel = new MessageModel();
           // 判斷用戶名稱是否非空
           if(null == userName || "".equals(userName.trim())){
               messageModel.setResultCode(0);
               messageModel.setResultMsg("用戶名不能爲空!");
               return messageModel;
           }
           // 判斷用戶密碼是否爲空
           if(null == userPwd || "".equals(userPwd.trim())){
               messageModel.setResultCode(0);
               messageModel.setResultMsg("密碼不能爲空!");
               return messageModel;
           }
           // 經過用戶名稱查詢用戶對象
           User user = userDao.queryUserByUserName(userName);
           // 判斷用戶對象是否爲空
           if(null == user){
               messageModel.setResultCode(0);
               messageModel.setResultMsg("該用戶不存在!");
               return messageModel;
           }
           // 若是用戶對象不爲空,判斷密碼是否正確
           if(!user.getUserPwd().equals(userPwd)){
               messageModel.setResultCode(0);
               messageModel.setResultMsg("用戶密碼不正確!");
               return messageModel;
           }
           // 登陸成功
           messageModel.setResultMsg("登陸成功!");
    
           return messageModel;
       }
    }

Controller層 (接收請求)

  1. 編寫Controller層 UserController.java

    package com.xxxx.controller;
    
    import com.xxxx.po.vo.MessageModel;
    import com.xxxx.service.UserService1;
    import org.springframework.stereotype.Controller;
    
    import javax.annotation.Resource;
    
    @Controller
    public class UserController {
       @Resource
       private UserService userService;
    
       /**
        * 用戶登陸
        * @param userName
        * @param userPwd
        * @return
        */
       public MessageModel login(String userName, String userPwd){
           // 調用Dao層判斷用戶登陸操做,返回結果
           MessageModel messageModel = userService.userLoginCheck(userName, userPwd);
           return messageModel;
       }
    }

經過 JUnit 進行測試

package com.xxxx;

import com.xxxx.controller.UserController;
import com.xxxx.po.vo.MessageModel;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestLogin {

    @Test
    public void test() {
        // 獲得Spring容器上下文環境
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
        // 獲得UserController實例化對象
        UserController userController = (UserController) ac.getBean("userController");
        // 傳入參數調用UserController的方法,返回封裝類
        MessageModel messageModel= userController.login("admin", "admin");

        System.out.println("狀態碼:" + messageModel.getResultCode() + ",提示信息:" + messageModel.getResultMsg());
    }
}

image

相關文章
相關標籤/搜索