spring bean的介紹以及xml和注解的配置方法


 

5.Bean

下邊我們來了解一下Bean的:
Bean的作用域
Bean的生命周期
Bean的自動裝配
Resources和ResourceLoader
 

5.1Bean容器的初始化

  Bean容器的初始化
  兩個基礎包:
    org.springframework.beans
    org.springframework.context
    BeanFactory提供配置結構和基本功能,加載並初始化Bean
    ApplicationContext保存了Bean對象並在spring中被廣泛使用

 

  集中常用的使用場景:

  常用的文件初始化方式:

  FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("F:/workspace/appcontext.xml");
  ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap1/coll.xml");
  BeanFactory factory = new ClassPathXmlApplicationContext("com/xxxspring/chap1/ioc.xml");

 

  1.在webapp中的我們一般配置到web.xml文件中

1     <!-- 配置contextConfigLocation指定spring將要使用的配置文件 -->
2     <context-param>
3         <param-name>contextConfigLocation</param-name>
4         <param-value>classpath:action.xml,classpath:dao.xml,classpath:service.xml</param-value>
5     </context-param>
6     <!--  配置listner讓spring讀取配置文件-->
7     <listener>
8         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
9     </listener>

  2.load-on-startup標簽指定啟動順序,1為指在啟動服務器的時候初始化容器

 1 <listener>
 2     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 3 </listener>
 4  
 5     <servlet>
 6         <servlet-name>remoting</servlet-name>
 7         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 8         <init-param>
 9             <param-name>contextConfigLocation</param-name>
10             <param-value>classpath:spring-remoting-servlet.xml</param-value>
11         </init-param>          
12         <load-on-startup>1</load-on-startup>
13     </servlet>

3Bean的兩種注入方式

  a.設置值注入

  b.構造注入

  設置值注入案例:

  基本類型的注入: 通過<property name="屬性名", value="屬性值/">為對應類對象初始化的值,這種方式必須在類中為對應的屬性提供getxxx,setxx方法

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4   xsi:schemaLocation="http://www.springframework.org/schema/beans
 5   http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
 6     <bean name="user,user2" class="com.xxx.spring.ioc.bean.User">
 7         <property name="id" value="1"/>
 8         <property name="name" value="tom"/>
 9         <property name="age" value="20"/>
10         <property name="gender" value="male"/>
11     </bean>    
12 </beans>

  引用類型的注入:<property name="屬性名" ref="引用的bean"></property>,被引入的bean和引入處可以不在同一個xml文件中,因為所有bean都會被容器初始化並保存到容器中

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4 xsi:schemaLocation="http://www.springframework.org/schema/beans
 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
 6     <bean name="memberService" class="com.xxx.run.service.impl.IMemberServiceImpl">
 7         <property name="memberDao" ref="memberDao"></property>
 8     </bean>
 9     <bean name="memberDao" class="com.xxx.run.dao.impl.IMemberDaoImpl"></bean>
10 </beans>

  構造注入

  顧名思義,使用構造器對對象的初始化注入對應的值,實現方式有如下3種  

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4 xsi:schemaLocation="http://www.springframework.org/schema/beans
 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
 6     <bean name="teacher" class="com.xxx.spring.ioc.bean.Teacher">
 7         <!--  1.按照屬性名賦值 ,調用有參數的構造器,順序是參數順序-->
 8         <constructor-arg name="id" value="1"/> <!-- person(int id,String name, String gender) -->
 9         <constructor-arg name="name" value="tom"/>
10         <constructor-arg name="gender" value="male"/>
11         <!-- 2.index從0開始,按照屬性在構造器中出現的順序賦值 索引值是構造器中的屬性順序 -->
12    <!-- <constructor-arg index="0" value="2"/>
13         <constructor-arg index="1" value="jack"/>
14         <constructor-arg index="2" value="male"/> -->
15         <!-- 3.按照類型進行賦值,如果出現相同的類型,按照屬性在構造器中出現的順序進行復制 -->
16     <!--<constructor-arg type="int" value="3"/>
17         <constructor-arg type="String" value="rose"/>
18         <constructor-arg type="String" value="female"/> -->
19     </bean>
20 </beans>

  Teacher.java  

 1 public class Teacher implements Serializable{
 2     private static final long serialVersionUID = 1L;
 3     private int id;
 4     private String name;
 5     private String gender;
 6  
 7     public Teacher(int id, String name, String gender) {
 8         super();
 9         this.id = id;
10         this.name = name;
11         this.gender = gender;
12     }
13  
14     @Override
15     public String toString() {
16         return "Teacher [id=" + id + ", name=" + name + ", gender=" + gender
17                 + "]";
18     }
19 }

  測試

1   @Test
2     public void test3() throws Exception {
3         ApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap1/constructor.xml");
4         Teacher teacher = (Teacher) ac.getBean("teacher");
5         System.out.println(teacher);//Teacher [id=1, name=tom, gender=male]
6     }

5.2Bean的生命周期

  Spring中Bean的聲明周期的創建和初始化都是由Spring管理創建的,如下Life實現BeanNameAware,BeanFacotryAware,可以獲取到一些對應的資源
 1 import org.springframework.beans.BeansException;
 2 import org.springframework.beans.factory.BeanFactory;
 3 import org.springframework.beans.factory.BeanFactoryAware;
 4 import org.springframework.beans.factory.BeanNameAware;
 5  
 6 public class Life implements BeanNameAware,BeanFactoryAware{
 7     private String name;
 8     
 9     public Life(){//一加載就會調到用
10         System.out.println("調用無參構造器");
11     }
12  
13     public String getName() {
14         return name;
15     }
16  
17     public void setName(String name) {
18         System.out.println("調用setName方法");
19         this.name = name;
20     }
21     
22     public void myInit() {
23         System.out.println("調用myInit方法");
24     }
25     
26     public void myDestory(){
27         System.out.println("調用myDestory方法");
28     }
29  
30     @Override
31     public void setBeanFactory(BeanFactory arg0) throws BeansException {
32         System.out.println("調用setBeanFactory方法");
33         
34     }
35  
36     @Override
37     public void setBeanName(String arg0) {
38         System.out.println("調用setBeanName方法");
39     }
40 }
  life.xml文件配置
  init-method指明bean初始化需要執行的方法,
  destory-method指明bean銷毀需要執行的方法
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:u="http://www.springframework.org/schema/util"
 5        xsi:schemaLocation="http://www.springframework.org/schema/beans
 6            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 7            http://www.springframework.org/schema/util
 8            http://www.springframework.org/schema/util/spring-util-3.2.xsd">
 9            <!-- 調用set方法賦值后會調用myInit方法    myDestory方法最后調用-->
10     <bean name="life" class="com.xxx.spring.ioc.bean.Life" init-method="myInit" destroy-method="myDestory">
11         <property name="name" value="tom"></property>
12     </bean>
13 </beans>
  測試:
  注意:在xml文件中指明destory-method需要執行的方法后,bean生命周期並不會自動去掉用myDestory方法,需要ac.detstory(),才會調用
1     @Test
2     public void life(){//springBean的生命周期    
3         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/life.xml");
4         Life life = ac.getBean("life",Life.class);
5         System.out.println(life);
6         ac.destroy();
7     }
  結果:
    調用無參構造器
    調用setName方法
    調用setBeanName方法
    調用setBeanFactory方法
    調用myInit方法
    com.briup.spring.ioc.bean.Life@4f0b5b
    調用myDestory方法
    AfterClass 標注的方法 會最后執行

5.3Bean作用域

  介紹兩個常用的
  scope="prototype"原型模式,該模式下每次都會創建一個新的對象
  <bean id="user" class="com.briup.spring.ioc.bean.User" scope="prototype"></bean>
  scope = "singleton" 單例模式,該模式下容器中只會存在一個這樣的對象
  <bean id="user" class="com.briup.spring.ioc.bean.User" scope="singleton"></bean>
 
  其他的參考:
  http://blog.csdn.net/fengruifang/article/details/6522262

5.4Bean的自動裝配

  上邊的Bean不管通過設置值注入,或通過構造器注入,我們都顯示的聲明了需要注入的值
  還有一種方式也比較常用,對應引用類型的注入我們可以通過autowire自動注入
  autowire有三種方式
    1.constructor
      如下邊我們不顯示聲明address屬性的值,autowire=“constructor”,即初Student中提供了
        public Student(Address address) {
          this.address = address;
        }
      構造器,初始化Bean的時候,會去容器中查找Address.class對象是否存在,如果存在,則注入到該bean對象中,如不存在address為null
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4 xsi:schemaLocation="http://www.springframework.org/schema/beans
 5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
 6     <bean name="student" class="com.xxx.spring.ioc.bean.Student" autowire="constructor"><!-- byName byType  constructor(一定要提供一個單參數的構造器)-->
 7         <property name="name" value="tom"/>
 8         <property name="age" value="20"/>
 9     <!--     <property name="address" ref="address"/> -->
10     </bean>
11     <bean name="address" class="com.briup.spring.ioc.bean.Address">
12         <property name="country" value="中國"></property>
13         <property name="province" value="江蘇"></property>
14         <property name="city" value="蘇州"></property>
15     </bean>
16 </beans>
    2.byName
      同理,autowire=“byName”,初始化bean的時候,會去容器中查找名字為address的bean注入到student對象中,Student需要提供對應的getxx,setxx
    3.byType
      autowire=“byType”,初始化bean的時候,會取容器中通過類型查找是否有Class為Address.class類型的對象,查找到則注入到student對象中需要提供getxx,setxx 

5.3 Aware

  spring中提供了許多已Aware結尾的類,這些類可以獲取容器中的一些資源
  比如ApplicationContextAware,可以獲取applicationCcontext中的內容
  BeanNameAware可以獲取到Bean的beanName
  aware.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
6     <bean name="applicationAawareTest" class="com.xxx.spring.aop.bean.AwareTest"></bean>
7 </beans>
  AwareTest.java
 1 import org.springframework.beans.BeansException;
 2 import org.springframework.beans.factory.BeanNameAware;
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.ApplicationContextAware;
 5  
 6 public class AwareTest implements ApplicationContextAware,BeanNameAware{
 7  
 8     @Override
 9     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
10         System.out.println(applicationContext.getBean(AwareTest.class));
11     }
12  
13     @Override
14     public void setBeanName(String beanName) {
15         System.out.println(beanName);
16     }
17  
18
  測試:
1     @Test
2     public void AwareTest(){
3         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap1/aware.xml");
4         AwareTest awareTest = ac.getBean("applicationAawareTest",AwareTest.class);
5         System.out.println(awareTest);
6     }
  結果:
    applicationAawareTest
    com.xxx.spring.aop.bean.AwareTest@1d8fe20
    com.xxx.spring.aop.bean.AwareTest@1d8fe20

5.4Resource統一文件資源接口

  Resources針對文件的統一接口,用於操作本地資源或網絡資源,或其他
    -UrlResource:URL對應的資源,根據一個URL地址既可以構建
    -ClassPathResource:獲取類路徑下的資源文件
    -FileSystemResource:獲取文件系統中的資源文件
    -ServletContextResource:ServletContext封裝資源,用於訪問ServletContext環境下的資源
    -InputStreamResource:針對輸入流封裝的資源
    -ByteArrayResource:針對字節數組封裝的資源

   ResourceLoader
    -所用的application context 實現了ResourceLoader接口

    spring中ResourceLoader定義如下:

1 public interface ResourceLoader{
2     Resource getResource(String location);
3 }

 

     getResource中location的寫法有如下幾種
  prefix前綴 案例     說明
  classpath: classpath:com/briup/spring/chap2/life.xml 從classpath中加載
  file: file:/data/life.xml用URL從文件系統中加載
  http: http://myserver/logoo.png通過URL從網絡加載
  (none) /spring/chap2/life.xml 這種相對路徑的寫法依賴於ApplicationContext

 

  spring中的使用

    Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
    Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
    Resource template = ctx.getResource("file:some/resource/path/myTemplate.txt");

 

  案例:

  resources.xml

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://www.springframework.org/schema/beans
5 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
6     <bean name="resourcetest" class="com.briup.spring.aop.bean.ResourceTest"/>
7 </beans>

 

ResourceTest.java

由於spring中所有的applicationcontext實現了ContextLoader接口, 所以我們實現applicationContext即有了ResourceLoader的能力

下邊:classpath:在eclipse中會加載src下的config.txt文件

 1 import java.io.IOException;
 2  
 3 import org.springframework.beans.BeansException;
 4 import org.springframework.context.ApplicationContext;
 5 import org.springframework.context.ApplicationContextAware;
 6 import org.springframework.core.io.Resource;
 7  
 8  
 9 //所有的ApplicationContext實現了ResourceLoader接口
10 public class ResourceTest implements ApplicationContextAware{
11     
12     private ApplicationContext ApplicationContext;
13  
14     @Override
15     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
16         this.ApplicationContext = applicationContext;
17     }
18     
19     public void resource() throws IOException{
20         //Resource resource = ApplicationContext.getResource("config.txt");//默認為classpath
21         //Resource resource = ApplicationContext.getResource("classpath:config.txt");
22         //Resource resource = ApplicationContext.getResource("file:D:\\workspace\\xnxy_spring\\src\\config.txt");
23         Resource resource = ApplicationContext.getResource("url:http://repo.springsource.org/libs-release-local/org/springframework/spring/3.2.4.RELEASE/spring-framework-3.2.4.RELEASE-dist.zip");
24         System.out.println(resource.getFilename());//獲取文件名
25         System.out.println(resource.contentLength()); //獲取文件長度
26         System.out.println(resource.getInputStream());//獲取輸入流
27     }
28 }

 

  測試:

 1   @Test
 2     public void ResourceTest(){
 3         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/briup/spring/chap1/resources.xml");
 4         ResourceTest resourceTest = ac.getBean("resourcetest",ResourceTest.class);
 5         try {
 6             resourceTest.resource();
 7         } catch (IOException e) {
 8             e.printStackTrace();
 9         }
10     }

 

6.Bean容器的注解實現

  下邊我們主要了解如下使用:
    Classpath掃描與組件管理
    類的自動檢測與注冊Bean
    <context:annotation-config/>
    @Component, @Repository, @Service, @Constroller
    @Required
    @Autowired
    @Qualifier
    @Resource

6.1classpath掃描與組件管理

從Spring3.0開始,Spring JavaConfig項目提供了很多特性,包括使用java而不是XML定義Bean,比如
@Configuration, @Bean, @Import, @DependsOn
@Component是Spring中的一個通用注解,可以用於任何Bean,相當於注解的超類,如果不知道位於那個層,一般使用該注解
@Repository, @Service, @Controller是更具有針對性的注解
- @Repository,通常用於注解DAO,即持久層的注解
- @Service,通常用於追注解Service類,即服務層
- @Controller通常用於注解Controller,即控制層(MVC)

6.2類的自動檢測與注冊Bean

我們再xml下配置如下標簽,可以指定某個包路勁,掃描該包以及子包下,使用了spring注解的bean注冊哦容器中,basp-package指向掃描那個包下的注解類
1 <context:component-scan base-package="spring.aop.bean.annotation"></context:component-scan>
我們還可以使用如下標簽,context:annotation-config,不過context:component-scan包含context:annotation-config的全部功能,通常使用前者后,不再使用后者,context:component-scan一般用於基於類的注解(包括成員變量或成員方法的注解),但是context:annotation-config只能在完成bean注冊后,去處理bean類中的成員變量或成員方法的注解.
 
過濾注解:
 1     <!--默認情況下,spring中自動發現並被注冊bean的條件是:
 2         使用@Component, @Repository, @Service, @Constroller其中之一的注解
 3         或者使用基於@Component的自定義注解
 4      
 5         可以通過過濾器修改上邊的行為,如下邊的例子XML配置忽略所有@Repository注解並用“stub”代替
 6         -->
 7     
 8 
 9        <context:component-scan base-package="spring.aop.bean.annotation">
10            <!-- 通過include-filter包含注解,exclude-filter排除注解 -->
11            <context:include-filter type="regex" expression=".*Stub.*Repository"/>
12            <!-- 排除@Repository注解 -->
13            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
14        </context:component-scan>

6.3使用注解管理bean

這里我們先使用 @Bean @Service @Repository @Componet
掃描過程中組件自動檢測,那么Bean名稱是有BeanNameGenerator生成的( @Component, @Repository, @Service, @Controller
都會有個name屬性用於顯示設置BeanName)
 
Service

//顯示設置beanName,相當於在xml配置bean的是id的值
@Service("myMoveLister")
public class simpleLlister{
//..

}

 

Dao

//設置beanName默認使用類名,首字母小寫作為beanName
@Repository
public class MovieFinderImpl implements MovieFinder{

}

6.3.1 作用域scope

作用域的注解Scope
通常情況下自動查找的Spring組件,其Scope是singleton,其Spring2.5提供了Scope的注解 @Scope

@Scope("prototype")  //括號中指定Scope的范圍,默認
@Repository
public class MovieFinderImpl implements MovieFinder{


}


也可以自定義scope策略,實現ScopeMetadataResolver接口並提供一無參數的構造器

 <context:component-scan base-package="spring.aop.bean.MyScopeResolver"></context:component-scan>

6.3.2注解的具體案例使用

//由於不知道其作用於DAO或Service所以使用通用注解,如果知道具體作用在那層,我們一班使用更具體注解方式如@Service,@Repository等

1 //@Component -->默認使用類名小寫作為bean的name
2 @Scope("prototype") //括號中為Scope的范圍,這里設置為原型模式
3 @Component("beanAnnotation")
4 public class BeanAnnotation {
5     
6     public void say(String arg){
7         System.out.println("BeanAnnotation: "+arg);
8     }
9 }

 

測試:

 1 @Test
 2 public void testAnnotation(){
 3     ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/annotation.xml");
 4     //@Component沒有value值的話,默認使用類名首字母小寫作為bean的id,指定value以value值為准作為id
 5     BeanAnnotation beanAnnotation1  = ac.getBean("beanAnnotation",BeanAnnotation.class);
 6     BeanAnnotation beanAnnotation2  = ac.getBean("beanAnnotation",BeanAnnotation.class);
 7     System.out.println(beanAnnotation1);
 8     System.out.println(beanAnnotation2);
 9     //結果
10     //com.xxx.spring.aop.bean.annotation.BeanAnnotation@1598d5f
11     //com.xxx.spring.aop.bean.annotation.BeanAnnotation@505fd8
12 }

 

6.3.3一個不常用的注解@Required
@Required注解使用於注解bean屬性的setter方法
這個注解僅僅標識,受影響的bean屬性必須在配置時被填充,通過bean定義或通過自動裝配一個明確的屬性值
這個注解並不是很常用,更常用的是@Autowired
pulic class simpleMovieLister{
  private MoiveFinder movieFinder;
  @Required
  public void setMovieFinder(MovieFinder movieFinder){
    this.movieFinder  = movieFinder;
  }
  //..
}
6.3.4@Autowired

這個注解相當於我們之前在xml文件中配置的autowire="constructor/byName/byType",只不過我們這里使用@Autowired方式注解方式,且默認是通過類型判斷,意思就是不使用byName,和construtor。通過@Autowired注解,spring會自動去容器中查找對應的類型,注入到該屬性中,且bean類中,使用@Autowired注解其屬性,我們可以不用提供getter,setter方法

使用@Autowired

@Autowried對屬性進行注解的時候,我們可以省略getter,setter方法,通過對應的bean的類型,對屬性值注入
@Autowried對seter方法進行注解的時候,可以注入對應的值
@Autowried對構造器進行注解的時候,可以通過類型找到對應的bean注入
@Autowried可以將 @Autowried為”傳統“的setter方法代替 @Required
@Autowried自動注入,會去容器中按照類型查找對應的bean注入

 

案例:

setter中使用

 1 pulic class simpleMovieLister{
 2     
 3         private MoiveFinder movieFinder;
 4  
 5         @Autowried
 6         public void setMovieFinder(MovieFinder movieFinder){
 7             this.movieFinder  = movieFinder;
 8         }
 9         //..
10 }

 

屬性和構造器中使用

 1 pulic class MovieRreCommender{
 2     
 3         成員變量中
 4         @Autowried
 5         private MovieCatalog movieCatalog;
 6  
 7         private CustomerPreferenceDao customerPreferenceDao;
 8  
 9         //構造器中
10         @Autowried
11         public MovieRreCommender(CustomerPreferenceDao customerPreferenceDao){
12             this.CustomerPreferenceDao  = CustomerPreferenceDao;
13         }
14 }

 

上邊的seter方式,構造器方式,屬性方式,效果都是一樣的,使用其中任何一種,都可以實現注入。不過由於,@Autowired是通過類型判斷是否注入到使用該注解地方,假如容器中出現兩個以上的相同類型的bean實例,就會報錯,這時我們就必須指定注入那個id名的bean實例,主要有兩種方法解決該問題:

@Autowired(requried=false), @Qualifie("beanName)指定@Autowired注入那個bean實例

6.3.5@Autowried(requried=false)

默認情況下,如果因找不到合適的bean將會導致autowiring失敗拋出異常,可以通過下邊
這種方式避免

pulic class simpleMovieLister{

private MoiveFinder movieFinder;

@Autowried(requried=false)//指明該屬性不是必須的,找不到的情況下不會拋出異常
public void setMovieFinder(MovieFinder movieFinder){
this.movieFinder  = movieFinder;
}
//..
}
提示:每一類中只能有一個構造器被標記為requried=ture建議將 @Autowired的必要屬性時,使用 @Requried注解

6.3.6@Qualifier--配合 @Autowired
如果使用 @Autowired自動裝配可能存在多個相同類型的bean的時候,可以使用spring的 @Qualifier
注解縮小注解范圍(或指定唯一),也可以用於指定單獨的構造參數的方法參數
可以適用於注解集合類型的變量

案例:
 1 public class MovieRecommander{
 2     @Autowired
 3     @Qualifier("beanName")
 4     private MovieCatalog movieCatalog;
 5  
 6     private CustomerPreferenceDao customerPreferenceDao;
 7   //@Qualifier也可以實現參數的注入
 8     public void prepare(@Qualifier("beanName")CustomerPreferenceDao customerPreferenceDao){
 9         this.customerPreferenceDao = customerPreferenceDao;
10     }
11 }
上邊的案例:假設MovieCatalog在容器中存在多個相同的類型的情況下,可以結合使用 @Qualifier("beanName")
指定一個bean的id注入到該屬性中,可以在方法的參數中使用

 6.3.7@Autowired注解可以方便的注解那些眾所周知的解析依賴性接口

比如說:BeanFacotry,ApplicationContext,Environment,ResourceLoader,ApplicaiontEventPublisher, MessageSource等

1     pulic class simpleMovieLister{
2     
3         @Autowired
4         private AplicationContext context;
5  
6         public simpleMovieLister(){}
7     
8     }

 

上邊的案例使用autowired注解ApplicationContext,這樣我們就可以活ApplicatioinContext容器總的bean對象

6.3.8@Autowired將容器中相關類型的bean注入到一個集合或數組中
使用@Autowired注解,可以將容器中的bean實例注入到集合或數組中,如果是注入到數組中通過配合@Order("排序值"),可以實現對數組或list的排序,也只能對數組或list排序,其他的如Map是不需要排序的。
 
案例:接口BeanInfterface
1 public interface BeanInterface {
2  
3  
4 }
實現類1:
1 @Order(1)
2 @Component
3 public class BeanImplOne implements BeanInterface {
4  
5 }

 

實現類2:
1 @Order(2)  //Order排序注解只對list,或數組集合有效括號里邊是排序順序
2 @Component
3 public class BeanImplTwo implements BeanInterface {
4  
5 }
調用類:
 1 import java.util.List;
 2 import java.util.Map;
 3 import java.util.Map.Entry;
 4 import java.util.Set;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.stereotype.Component;
 7  
 8 @Component
 9 public class BeanInvoker {
10     
11     @Autowired //該注解會將所有的BeanInterface類型的bean注入到該list中
12     //如果bean有 @Order注解可以實現排序
13     private List<BeanInterface> list;
14     
15     //該注解會將所有的BeanInterface類型的bean注入到該map中,key值為bean的名字
16     //是String類型,map類型無排序可言
17     @Autowired
18     private Map<String, BeanInterface> map;
19     
20     public void print(){
21         if(list != null && 0 != list.size()){
22             System.out.println("list...");
23             for(BeanInterface beanInterface:list){
24                 System.out.println(beanInterface.getClass().getName());
25             }
26         }
27         if(map != null && 0 != map.size()){
28             System.out.println("map...");
29             Set<Entry<String, BeanInterface>> entrySet = map.entrySet();
30             for(Entry<String, BeanInterface> entry: entrySet){
31                 System.out.println(entry.getKey()+"--"+entry.getValue().getClass().getName());
32             }
33         }
34     }
35 }
測試類:
1 @Test
2 public void testAutowired2(){
3         ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/annotation.xml");
4         BeanInvoker beanInvoker = (BeanInvoker) ac.getBean("beanInvoker");
5         beanInvoker.print();
6 }

 

結果:
list...
com.xxx.spring.aop.bean.annotation.BeanImplOne
com.xxx.spring.aop.bean.annotation.BeanImplTwo
map...
beanImplOne--com.xxx.spring.aop.bean.annotation.BeanImplOne
beanImplTwo--com.xxx.spring.aop.bean.annotation.BeanImplTwo

6.4@Bean注解的使用

@Bean是基於容器的注解,我們可以在使用@Compent注解的地方配合@Bean使用,不過@Bean注解一般不於@Compent注解使用,我們一般使用
@Bean注解配合@Configuration注解使用,相當於我們再xml配置文件中定義了<bean></bean>
 
使用:
 1 @Configuration   //相當於配置文件
 2 public class Appconfig{
 3     
 4     @Bean("myservice")//假如bean的name屬性沒有指定名字的話,注入的是id為方法名的bean,一般我們指定name屬性不容易出錯
 5     public Myservice myservice(){
 6         return new MyServiceImpl();
 7     }
 8     /*
 9         對比基於XML文件中的配置效果類似
10         <bean id="myservice" class="com.xxx.service.MyserviceImpl"></bean>
11     */
12 }
@Bean中的其他他幾個屬性
 
之前我們再配置文件中使用過如下的配置,指定bean的初始化調時會執行的方法,和銷毀會執行的方法
1 <bean name="life" class="com.briup.spring.ioc.bean.Life" init-method="myInit" destroy-method="myDestory">
2         <property name="name" value="tom"></property>
3 </bean>
我們使@Bean配置也可以實現上邊這種效果
 1 public class Foo{
 2     public void init(){
 3     
 4     }
 5 }
 6  
 7 public class Bar{
 8     public void cleanup(){
 9     
10     }
11 }
 1 @Configuration 
 2 public class Appconfig{
 3     
 4     @Bean(name="life")  //定義bean的name
 5     public Life life(){
 6         return new Life();
 7     }
 8  
 9     @Bean(initMethod="init") //在初始化Foo的時候,會調用Foo.java中的init方法
10     public Foo foo(){
11         return new Foo();
12     }    
13     
14     @Bean(destoryMethod=“cleanup”) //在銷毀Bar的時候會調用Bar.java中的cleanup中的方法
15     public Bar bar(){
16         return new Bar();
17     }
18 }

6.5使用注解模擬連接數據庫

db.properties內容如下:
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:XE
jdbc.username=caojx
jdbc.password=caojx
 
config.xml配置如下
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"  
 3  xmlns:context="http://www.springframework.org/schema/context"  
 4  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 5  xsi:schemaLocation="http://www.springframework.org/schema/beans  
 6       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
 7       http://www.springframework.org/schema/context  
 8       http://www.springframework.org/schema/context/spring-context.xsd" >
 9        <!-- 加載db.properties文件 -->
10        <context:property-placeholder location="classpath:db.properties"/>
11        <!--context:component-scan包含context:annotation-config的全部功能,通常使用前者后,不再使用后者
12        <context:component-scan base-package="com.briup.spring.aop.bean.annotation"></context:component-scan>
13  
14 </beans>
 
使用如下類,打印出配置文件中db.properties中的信息
1 public class MyDriverManager {
2     
3     public MyDriverManager(String url, String userName, String password){
4         System.out.println("url :"+url);
5         System.out.println("userName :"+userName);
6         System.out.println("password :"+password);
7     }
8  
9 }
讀取配置文件中的信息
 1 @Configuration
 2 @ImportResource("classpath:com/xxx/spring/chap4/config.xml")  //指定配置文件的路徑
 3 public class MyConnection {
 4     
 5     
 6     @Value("${jdbc.url}")  //基本類型的變量使用@Value注解(括號里邊是注入的值)  ,這是使用${是讀取配db.properties中的值}
 7     private String url;
 8     
 9     @Value("${jdbc.username}")  //如果db.properties中寫法為username默認取的是當前操作系統用戶的名稱,可以在db.properties定義username的時候使用jdbc.username
10     private String userName;
11     
12     @Value("${jdbc.password}")
13     private String password;
14     
15     @Bean(name="myDriverManager")
16     
17     public MyDriverManager MyDriverManager(){
18         return new MyDriverManager(url,userName,password);
19     }
20  
21 }
 
測試:
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/annotation.xml");
System.out.println(ac.getBean("myDriverManager"));
結果:
url :jdbc:oracle:thin:@localhost:1521:XE
userName :caojx
password :caojx
com.briup.spring.aop.bean.annotation.MyDriverManager@152b54b

同時:@Bean注解也可以配置@Scope使用

 1 @Bean(name="myDriverManager")
 2 @Scope("prototype")
 3 public MyDriverManager MyDriverManager(){
 4     return new MyDriverManager(url,userName,password);
 5 }
 6  
 7 @Bean(name="myDriverManager")
 8 @Scope("singleton")
 9 public MyDriverManager MyDriverManager(){
10     return new MyDriverManager(url,userName,password);
11 }

 

提示:spring配置數據庫連接,或事務管理這一塊,將會專門使用一篇來說明。


6.6Spring對JSR的注解支持

JSR常見的注解有如下

@Resource等效於@Autowired與@Inject
@PostConstrct  初始化回掉
@PreDetory   銷毀回調用
@Inject 等效於 @Autowired
@Named 與 @Compenet等效

6.6.1@Resource
@Resource的作用相當於@Autowired,只不過@Autowired按byType自動注入,
而@Resource默認按 byName自動注入罷了。
@Resource有兩個屬性是比較重要的,分是name和type,
Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。
所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
  @Resource裝配順序
  1. 如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
  2. 如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
  3. 如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
  4. 如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配;如果沒有匹配,則回退為一個原始類型進行匹配,如果匹配則自動裝配; 
       5. 如果 @Resource用於方法中,默認使用方法名作為beanName,指定名字則使用名字

 

案例:

DAO

 1 import org.springframework.stereotype.Repository;
 2  
 3 @Repository
 4 public class JsrDAO {
 5     
 6     public void save(){
 7         System.out.println("JsrDao invoker");
 8     }
 9  
10 }

 

Service

 1 import javax.annotation.PostConstruct;
 2 import javax.annotation.PreDestroy;
 3 import javax.annotation.Resource;
 4  
 5 import org.springframework.stereotype.Service;
 6  
 7 import com.briup.spring.aop.bean.annotation.dao.JsrDAO;
 8  
 9 @Service
10 public class JsrService {
11     
12     @Resource
13     private JsrDAO jsrDAO;
14     
15     @Resource  //作用與上邊一樣,二選一都可以
16     public void setJsrDAO(JsrDAO jsrDAO){
17         this.jsrDAO = jsrDAO;
18     }
19     
20     public void save(){
21         jsrDAO.save();
22     }
23     
24     @PostConstruct
25     public void init(){
26         System.out.println("jsr Service init");
27     }
28     
29     @PreDestroy
30     public void destory(){
31         System.out.println("jsr Service destory");
32     }
33     
34 }

 

提示:

@Resource的處理是由ApplicationContext中的CommonAnnotationBeanPostProecssor發現並處理的
CommonAnnotationBeanPostProecssor不僅支持 @Resource注解,還支持 @PostConstruct初始回調
和 @PreDestory銷毀回調,前提是CommonAnnotationBeanPostProecssor是在ApplicationContext中注冊的

測試結果:

@Test
public void testJsr(){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/briup/spring/chap4/annotation.xml");
System.out.println(ac.getBean("jsrService"));
ac.destroy();
}

結果:

jsr Service init
com.briup.spring.aop.bean.annotation.service.JsrService@7dc4cb
jsr Service destory

 

@Resource是一個比比較常用的JSR注解,對於JSR中的其他注解,這里不進行詳細的介紹。


免責聲明!

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



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