spring 自動裝配與注解注入


基於xml的自動裝配

除了上述手動注入的情況,Spring還非常智能地為我們提供自動向Bean注入依賴的功能,這個過程一般被稱為自動裝配(autowiring)

Spring的自動裝配有三種模式:byTpye(根據類型),byName(根據名稱)、constructor(根據構造函數)。

在byTpye模式中,Spring容器會基於反射查看bean定義的類,然后找到與依賴類型相同的bean注入到另外的bean中,這個過程需要借助setter注入來完成,因此必須存在set方法,否則注入失敗。

//dao層
public class UserDaoImpl implements UserDao{
    //.......
    @Override
    public void done(){
        System.out.println("UserDaoImpl.invoke......");
    }
}
//service層
public class UserServiceImpl implements UserService {
    //需要注入的依賴
    private UserDao userDao;

    /**
     * set方法
     * @param userDao
     */
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void done(){
        userDao.done();
    }
}

基於xml的配置如下,通過使用<bean>的autowire屬性啟動名稱為userService的自動裝配功能

<bean id="userDao"  class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<!-- byType 根據類型自動裝配userDao-->
<bean id="userService" autowire="byType" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />
byType模式可能存一種注入失敗的情況,由於是基於類型的注入,因此當xml文件中存在多個相同類型名稱不同的實例Bean時,Spring容器依賴注入仍然會失敗,因為存在多種適合的選項,Spring容器無法知道該注入那種,此時我們需要為Spring容器提供幫助,指定注入那個Bean實例。可以通過<bean>標簽的autowire-candidate設置為false來過濾那些不需要注入的實例Bean
bean id="userDao"  class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />

<!-- autowire-candidate="false" 過濾該類型 -->
<bean id="userDao2" autowire-candidate="false" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />

<!-- byType 根據類型自動裝配userDao-->
<bean id="userService" autowire="byType" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />

除了上述的解決方案外,還可采用byName模式的自動裝配,此時Spring只會嘗試將屬性名與bean名稱進行匹配,如果找到則注入依賴bean。
<bean id="userDao"  class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userDao2" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />

<!-- byName 根據名稱自動裝配,找到UserServiceImpl名為 userDao屬性並注入-->
<bean id="userService" autowire="byName" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />

構造器自動裝配

public class UserServiceImpl implements UserService {

    private UserDao userDao;
    //constructor模式
    public UserServiceImpl(UserDao userDao){
        this.userDao=userDao;
    }

//    /**
//     * set方法
//     * @param userDao
//     */
//    public void setUserDao(UserDao userDao) {
//        this.userDao = userDao;
//    }

    @Override
    public void done(){
        userDao.done();
    }
}

基於xml配置:

<bean id="userDao"  class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<!-- constructor自動裝配userDao-->
<bean id="userService" autowire="constructor" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />
在constructor模式下,存在單個實例則優先按類型進行參數匹配(無論名稱是否匹配),當存在多個類型相同實例時,按名稱優先匹配,如果沒有找到對應名稱,則注入失敗,此時可以使用autowire-candidate=”false” 過濾來解決。

基於注解的自動裝配(@Autowired&@Resource&@Value)

基於@Autowired注解的自動裝配

在Spring 2.5 中引入了 @Autowired 注釋,它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。 通過 @Autowired的使用標注到成員變量時不需要有set方法,請注意@Autowired 默認按類型匹配的

 

<!-- 使用注解時必須啟動注解驅動 -->
<context:annotation-config />
public class UserServiceImpl implements UserService {
    //標注成員變量
    @Autowired
    private UserDao userDao;
    //標注構造方法
    @Autowired
    public UserServiceImpl(UserDao userDao){
        this.userDao=userDao;
    }
    //標注set方法
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void done(){
        userDao.done();
    }
}

顯然上述代碼我們通過3種方式注入userDao實例,xml配置文件只需聲明bean的實例即可,在實際開發中,我們只需選擇其中一種進行注入操作即可,建議使用成員變量注入,這樣可以省略set方法和構造方法,相當簡潔。


@service
public class UserServiceImpl implements UserService {
    //標注成員變量
    @Autowired
    private UserDao userDao;   
 }

在@Autowired中還傳遞了一個required=false的屬性,false指明當userDao實例存在就注入不存就忽略,如果為true,就必須注入,若userDao實例不存在,就拋出異常。由於默認情況下@Autowired是按類型匹配的(byType),如果需要按名稱(byName)匹配的話,可以使用@Qualifier注解與@Autowired結合,請注意必須在xml配置中啟動注解驅動 public class UserServiceImpl implements UserService {
    //標注成員變量
    @Autowired
    @Qualifier("userDao1")
    private UserDao userDao;   
 }
使用byName模式,xml配置如下:

<!-- 根據@Qualifier("userDao1")自動識別 -->
<bean id="userDao1" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />
<bean id="userDao2" class="com.zejian.spring.springIoc.dao.impl.UserDaoImpl" />

<bean id="userService" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl" />

 

基於@Resource注解的自動裝配

與@Autowried具備相同功效的還有@Resource,默認按 byName模式 自動注入,由J2EE提供,需導入Package: javax.annotation.Resource,可以標注在成員變量和set方法上,但無法標注構造函數。@Resource有兩個中重要的屬性:name和type。Spring容器對於@Resource注解的name屬性解析為bean的名字,type屬性則解析為bean的類型。因此使用name屬性,則按byName模式的自動注入策略,如果使用type屬性則按 byType模式自動注入策略。倘若既不指定name也不指定type屬性,Spring容器將通過反射技術默認按byName模式注入。

//@Autowired標注成員變量
@Autowired
@Qualifier("userDao")
private UserDao userDao;  
//上述代碼等價於@Resource
@Resource(name=“userDao”)
private UserDao  userDao;//用於成員變量

//也可以用於set方法標注
@Resource(name=“userDao”)
public void setUserDao(UserDao userDao) {
   this.userDao= userDao;
}

基於@Value注解的自動裝配以及properties文件讀取

關於@Autowired和@Resource都分析完了,但這里存在一個問題,上述兩種自動裝配的依賴注入並不適合簡單值類型,如int、boolean、long、String以及Enum等,對於這些類型,Spring容器也提供了@Value注入的方式,這是非常具備人性化的,可以解決很多硬編碼問題。@Value接收一個String的值,該值指定了將要被注入到內置的java類型屬性值,放心,不必關系類型轉換,大多數情況下Spring容器都會自動處理好的。一般情況下@Value會與properties文件結合使用,也分兩種情況一種是SpEL(有點類似於jsp的EL),另外一種是占位符方式,看一個簡單例子jdbc.properties文件如下:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&allowMultiQueries=true
jdbc.username=root
jdbc.password=root

利用注解@Value獲取jdbc.url和jdbc.username的值,實現如下:

/**
 * Created by zejian on 2017/1/18.
 * Blog : http://blog.csdn.net/javazejian [原文地址,請尊重原創]
 */
public class UserServiceImpl implements UserService {
    //標注成員變量
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
    //占位符方式
    @Value("${jdbc.url}")
    private String url;
    //SpEL表達方式,其中代表xml配置文件中的id值configProperties
    @Value("#{configProperties['jdbc.username']}")
    private String userName;

    @Override
    public void done(){
        System.out.println("url:"+url);
        System.out.println("username:"+userName);
        userDao.done();
    }
}

 基於xml的配置如下:

<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"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!--基於占位符方式 配置單個properties -->
    <!--<context:property-placeholder location="conf/jdbc.properties"/>-->
    <!--基於占位符方式 配置多個properties -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
        <property name="location" value="conf/jdbc.properties"/>
    </bean>

    <!--基於SpEL表達式 配置多個properties id值為configProperties 提供java代碼中使用 -->
    <bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="locations">
            <list>
                <value>classpath:/conf/jdbc.properties</value>
            </list>
        </property>
    </bean>

    <!--基於SpEL表達式 配置單個properties -->
    <!--<util:properties id="configProperties" location="classpath:conf/jdbc.properties"/>-->

    <!--注解驅動 -->
    <context:annotation-config/>

     
 

    <bean id="userService" class="com.zejian.spring.springIoc.service.impl.UserServiceImpl"/>
</beans>

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM