發現一篇好文 http://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/ 它給出了比本文更詳細的說明。

springframework 2.5引入了完整的annotaion配置注解,使用這些annotation可以大量的減少bean的定義,也使得程序開發更簡單和容易維護。

當然你要使用annotation就需要使用java5以上版本。

使用annotaion定義一個bean
@Component是一個通用注解,用于說明一個類是一個spring容器管理的類。
除此之外,還有@Controller, @Service, @Repository是@Component的細化,這三個注解比@Component帶有更多的語義,它們分別對應了表現層、服務層、持久層的類。
如果你只是用它們定義bean,你可以僅使用@Component,但是既然spring提供這些細化的注解,那肯定有使用它們的好處,不過在以下的例子中體現不出。

定義了一個接口

package test1;

interface MovieFinder {
    String getData();
}
定義一個實現

package test1;

import org.springframework.stereotype.Repository;

@Repository
public class JpaMovieFinder implements MovieFinder {

    @Override
    public String getData() {
        return "This is JpaMovieFinder implementation!";
    }

}
這里使用了注解@Repository,說明這是一個受spring容器管理的bean定義,這個注解沒有指定bean的名字,默認為小寫開頭的類名,就是jpaMovieFinder,如果你要指定名字,可以這樣寫@Repository("myMovieFinder")。
這里也可以使用@Component這個注解,在這里例子中體現不出用@Repository的好處。
這里沒有指定這個bean的scope,缺省是singleton,如果你要其他scope,可以使用注解@Scope

@Scope("prototype")
@Repository
public class MovieFinderImpl implements MovieFinder {
    // ...
}

spring掃描并注冊注解的bean
JpaMovieFinder只是添加了一個注解,這并不會自動被注冊到spring容器中,我們需要告訴spring容器到那里去尋找這些bean。
配置如下:

<?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
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
              
     <context:component-scan base-package="test1"/>
    
</beans>
<context:component-scan base-package="test1"/>這個配置告訴spring容器到test1這個package下去掃描所有的類,從而找到被注解的類。
由于并不是test1下的所有的類都有注解,全部遍歷效率不高,所以spring定義了過濾器用于減小掃描范圍,這里為了簡單起見沒有使用。

使用注解進行依賴注入

package test1;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class SimpleMovieLister {
   
    @Autowired
    private MovieFinder movieFinder;


    public String getData(String name) {
        return "Hi " + name + "! " + movieFinder.getData();
    }
   
    public MovieFinder getMovieFinder() {
        return movieFinder;
    }


    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}
SimpleMovieLister是一個服務類,它也使用了@Service注解為了bean,這個類用到了MovieFinder,為了注入這個類的實現,這里使用了注解@Autowired,spring容器會自動找到合適的bean注入進去。注意這里并沒有指定被注入bean的名字,因為spring根據只發現了一個實現,那就是jpaMovieFinder。后面,我們會看到有兩個實現會怎樣。

注意,上面代碼使用@Autowired時,public void setMovieFinder(MovieFinder movieFinder) 這個方法是不需要的,你可以把它刪除了試一試。如果你使用xml的配置方式,該方法必須存在。我這里保留該方法,是為了后面測試注解和xml配置混合使用的方式。

測試1

package test1;


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


public class Main {


    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("test1/beans.xml");
        SimpleMovieLister m = (SimpleMovieLister)context.getBean("simpleMovieLister");
        System.out.println(m.getData("Arthur"));
    }


}


控制臺上會打印 Hi Arthur! This is JpaMovieFinder implementation!

增加MovieFinder的第二個實現

package test1;

import org.springframework.stereotype.Repository;

@Repository
public class IbatisMovieFinder implements MovieFinder {

    @Override
    public String getData() {
        return "This is IbatisMovieFinder implementation!";
    }

}


這時運行Main,系統會報錯:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleMovieLister': Injection of resource fields failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test1.MovieFinder] is defined: expected single matching bean but found 2: [jpaMovieFinder, ibatisMovieFinder]
從錯誤信息中我們可以看到現在MovieFinder有兩個bean實現了,一個是jpaMovieFinder,另一個是ibatisMovieFinder,spring容器不知道應該使用哪一個bean。這時可以使用注解@Qualifier指定具體的bean。
//...
@Service
public class SimpleMovieLister {


    @Autowired
    @Qualifier("ibatisMovieFinder")
    private MovieFinder movieFinder;
//...
這里我們指定注入的是ibatisMovieFinder這個bean。
運行Main, 控制臺上會打印 Hi Arthur! This is IbatisMovieFinder implementation!

Java6提供的注入注解
spring也可以使用java6提供的@Resource注解來指定注入哪一個bean。

//...
@Service
public class SimpleMovieLister {

    @Resource(name="ibatisMovieFinder")
    private MovieFinder movieFinder;
//...
這和@Autowired功能是一致的。

使用注解還是xml
使用注解很方便,但從上面的例子我們也可以看出注解的問題,MovieFinder有兩個實現,SimpleMovieLister是在程序中用注解指定了使用哪一個實現,如果要修改,需要修改源程序。所以,注解只適用于固定依賴的情況。如果依賴需要在部署的時候做調整,那還是使用xml的配置方式方便,畢竟只需要修改一下xml文件即可。

實際使用時,我們可以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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd">
              
    <context:component-scan base-package="test1"/>
   
    <bean id="simpleMovieLister1" class="test1.SimpleMovieLister">
        <property name="movieFinder" ref="jpaMovieFinder" />
    </bean>
   
</beans>
使用xml配置方式定義了另外一bean,注入了jpaMovieFinder這個實現。


package test1;


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


public class Main {


    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("test1/beans.xml");
        SimpleMovieLister m = (SimpleMovieLister)context.getBean("simpleMovieLister");
        System.out.println(m.getData("Arthur"));
        SimpleMovieLister m1 = (SimpleMovieLister)context.getBean("simpleMovieLister1");
        System.out.println(m1.getData("Arthur"));
    }


}
simpleMovieLister是從注解來的,simpleMovieLister1是從xml配置來的。運行結果:
Hi Arthur! This is IbatisMovieFinder implementation!
Hi Arthur! This is JpaMovieFinder implementation!

證明混合使用是可行的,你可以繼續測試,用xml重新配置simpleMovieLister。
因此,即使我一開始使用了注解,之后我后悔了,沒有關系,不用修改源程序,以前用xml怎么配置現在還是怎么配置。

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/dqatsh/archive/2008/12/08/3478000.aspx