Spring學習筆記(五、Bean裝配(下))

上一篇:Spring學習筆記(四、Bean裝配(上))

這篇講解Bean管理的注解實現及例子

主要內容有:

  • Classpath掃描與組件管理
  • 類的自動檢測和注冊Bean
  • <context:annotation-config/>
  • @Component、@Repository、@Service、@Controller
  • @required
  • @Autowired
  • @Qualifier
  • @Resource

一、classpath掃描與組件管理

  • 從Spring3.0開始,SpringJavaConfig項目提供了很多特性,包括使用Java而不是xml定義bean,比如@Configuration、@Bean、@Import、@DependsOn等等。之所以使用注解,主要是為了降低使用xml設置bean的工作量。
  • @Component是一個通用注解,可用于任何bean;
  • @Repository、@Service、@Controller是更有針對性的注解,也是@Component的子注解:
    • @Repository通常用于注解Dao類,即持久層
    • @Service通常用于注解Service類,即服務層
    • @Controller通常用于注解Controller類,即控制層(MVC)

元注解(Meta-annotations)

  • 許多Spring提供的注解可以作為自己的代碼,即“元數據注解”,元注解是一個簡單的注解,可以應用到另一個注解。
Paste_Image.png
  • 除了value(),元注解還可以有其他屬性,允許自定義
Paste_Image.png

關于注解可以參考,我之前寫的一篇文章:理解java注解

類的自動檢測及bean的注冊

  • Spring可以自動檢測類并注冊bean到ApplicationContext中。其中注解可以注冊在類上也可以注冊在方法、變量上。

<context:annotation-config/>

  • 通過在基于XML的Spring配置如下標簽(請注意包含上下文命名空間)
  • <context:annotation-config/>僅會查找在同一個ApplicaitonContext中的bean注解
  • 可以掃描已經注冊在IoC容器中的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.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       ">
      <context:annotation-config/>
</beans>
  • 為了能夠檢測這些類并注冊相應的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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">

    <context:component-scan base-package="org.example"/>
</beans>
  • <context:component-scan>可以掃描基于類的注解
  • <context:component-scan>包含<context:annotation-config>,通常在使用<context:component-scan>后,就不再使用<context:annotation-config>
  • AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor也會被包含進來

使用過濾器進行自定義掃描

  • 默認情況下,類被自動發現并注冊bean的條件是:使用@Component,@Repository,@Service,@Controller注解或者使用@Component的自定義注解
  • 可以通過過濾器修改上面的行為,如,下面的例子的xml配置忽略所有的@Repository注解并用“Stub”代替。
<beans>  
      <context:component-scan base-package="org.example">
        <context:include-filter type="regex"
                                expression=".*Stub.*Repository"/>
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Repository"/>
      </context:component-scan>
</beans>
  • 還可以使用use-default-filters="false"禁用自動發現與注冊。
過濾類別 示例 說明
annotation org.example.SomeAnnotation 所有標注了SomeAnnotation的類。該類型采用目標類是否標注了某個注解進行過濾
assignable org.example.SomeClass 所有繼承或擴展SomeClass的類。該類型采用目標類是否繼承或擴展某個特定類進行過濾
aspectj org.example..*Service+ 所有類名以Service結束的類及繼承或擴展了它們的類。該類型采用AspectJ表達式進行過濾
regex org\.example\.Default.* 所有org.example.Default包下的類。該類型采用正則表達式根據類的類名進行過濾
custom org.example.MyTypeFiflter 采用MyTypeFiflter通過代碼的方式定義過濾規則。該類必須實現org.springframework.core.type.TypeFiflter接口

理解spring注解,參考:JAVA 注解的學習和對Spring注解的理解

定義BeanName(IoC容器總的beanId)

  • 掃描過程中組件被自動檢測,那么Bean名稱是由BeanNameGenerator生成的(@Component、@repository、@Service、@Controller都會有個name屬性用于顯式設置Bean Name)
    例如:
    顯式設置beanName,也就是直接設置IoC文件中的beanId:
@Service("TestResourceService")
public class TestResource implements ApplicationContextAware {
//……
 }

不顯式設置beanName的話,BeanNameGenerator會根據一定規則生成beanName,即類名首字母小寫:

@Service
public class TestResource implements ApplicationContextAware {
//……
 }
  • 可自定義bean命名策略,實現BeanNameGenerator接口,并一定要包含一個無參數構造器。
    記得在IoC注冊,例如:
<beans>
      <context:component-scan base-package="org.example"
        name-generator="org.example.MyNameGenerator"/>
</beans>

作用域(Scope)

  • 通常情況下自動查找的Spring組件,其scope是singleton,Spring2.5提供了一個標識scope的注解@Scope。
@Scope("prototype")
@Service("TestResourceService")
public class TestResource implements ApplicationContextAware {
      //……
}
  • 也可以自定義scope策略,實現ScopeMetadataResolver接口并提供一個無參構造器。
<beans>
      <context:component-scan base-package="org.example"
        scope-resolver="org.example.MyScopeResolver"/>
</beans>

代理方式

  • 可以使用scoped-proxy屬性指定代理,有三個值可選:no、interfaces、targetClass
<beans>
      <context:component-scan base-package="org.example"
        scope-proxy="interfaces"/>
</beans>

寫個示例:

  1. IoC容器中添加<context:component-scan>:
<?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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">

        <context:component-scan base-package="test9"></context:component-scan>
</beans>
  1. 在test9包下新增一個BeanAnnotation類并使用@Component注解:
package test9;
import org.springframework.stereotype.Component;
@Component
public class BeanAnnotation {
    public void say(String str) {
        System.out.println("BeanAnnotation:" + str);
    }
}
  1. junit測試:
 @Test
    public void test9(){
        BeanAnnotation beanAnnotation=super.getBean("beanAnnotation");
        beanAnnotation.say("類的自動檢測及bean的注冊");

    }
  1. 顯式指定beanName:
@Component("myBeanAnnotation")
public class BeanAnnotation {

    public void say(String str) {
        System.out.println("BeanAnnotation:" + str);
    }
}
  1. junit測試:
  @Test
    public void test9(){
        BeanAnnotation beanAnnotation=super.getBean("myBeanAnnotation");
        beanAnnotation.say("類的自動檢測及bean的注冊");
    }
  1. 在類中增加@Scope注解和showHashCode()方法
@Scope("prototype")
@Component("myBeanAnnotation")
public class BeanAnnotation {

    public void say(String str) {
        System.out.println("BeanAnnotation:" + str);
    }
    public void showHashCode(){
        System.out.println("HashCode:" + hashCode());
    }
}
  1. junit測試:
 @Test
    public void test9(){
        BeanAnnotation beanAnnotation=super.getBean("myBeanAnnotation");
        beanAnnotation.showHashCode();

        BeanAnnotation beanAnnotation2=super.getBean("myBeanAnnotation");
        beanAnnotation2.showHashCode();
    }
  1. 結果如下圖,使用@Scope注解修改作用域成功~:


    Paste_Image.png
  2. 將@Scope的值去掉,還原它本身的樣子

@Scope
@Component("myBeanAnnotation")
public class BeanAnnotation {

    public void say(String str) {
        System.out.println("BeanAnnotation:" + str);
    }
    public void showHashCode(){
        System.out.println("HashCode:" + hashCode());
    }
}
  1. 再次執行junit測試,結果如圖:


    Paste_Image.png

@Required

  • @Required注解適用于bean屬性的setter方法。
  • 這個注解僅僅表示,受影響的bean屬性必須在配置時被填充,通過在bean的定義或通過自動裝配的一個明確屬性值。
@Component("myBeanAnnotation")
public class BeanAnnotation {

      private TestResource testResource;

      @Required
      public void setTestResource(TestResource testResource) {
        this.testResource = testResource;
      }
}

@Autowired

  • 可以將@Autowired注解理解為“傳統”的setter方法。
@Component("myBeanAnnotation")
public class BeanAnnotation {
    private TestResource testResource;

    @Autowired
    public void setTestResource(TestResource testResource) {
        this.testResource = testResource;
    }
  • 可用于構造器或成員變量
@Component("myBeanAnnotation")
public class BeanAnnotation {
        @Autowired
        private TestResource testResource;
 
         private AutoWiringDao autoWiringDao;

        @Autowired
        public BeanAnnotation(AutoWiringDao autoWiringDao) {

    }
}
  • 默認情況下,如果因找不到合適的bean將會導致autowiring失敗拋出異常,可以通過下面的方式避免。
@Component("myBeanAnnotation")
public class BeanAnnotation {

        private TestResource testResource;

        @Autowired(required = false)
        public void setTestResource(TestResource testResource) {
            this.testResource = testResource;
        }
}
  • 每個類只能有一個構造器被標記為required=true
  • @Autowired的必要屬性,建議使用@Required注解

關于Spring自動裝配可以參考:spring的自動裝配

關于Autowired自動裝配的示例:

  1. service層實現類:
@Service
public class TestServiceImpl implements TestService {

    //@Autowired用于成員變量(不需要寫setter方法了)
    @Autowired
    private TestDao testDao;

    @Override
    public void save(String str) {
        //模擬業務操作
        System.out.println("TestServiceImpl接收參數:" + str);
        str = str + ":" + this.hashCode();

        testDao.save(str);
    }
}
  1. junit測試:
   @Test
    public void test10() {
        TestServiceImpl testService = super.getBean("testServiceImpl");
        testService.save("this is autowired");
    }
  1. 結果:


    Paste_Image.png
  2. 修改service層,將@Autowire設置在setTestDao()方法上:
@Service
public class TestServiceImpl implements TestService {
    private TestDao testDao;

    //@Autowired用于setter方法和用于變量是一個意思
    @Autowired
    public void setTestDao(TestDao testDao) {
        this.testDao = testDao;
    }

    @Override
    public void save(String str) {
        //模擬業務操作
        System.out.println("TestServiceImpl接收參數:" + str);
        str = str + ":" + this.hashCode();

        testDao.save(str);
    }
}
  1. 結果:


    Paste_Image.png
  2. 修改service層,將@Autowire設置在構造器方法上:

@Service
public class TestServiceImpl implements TestService {
    private TestDao testDao;

    //@Autowired用構造
    @Autowired
    public TestServiceImpl(TestDao testDao) {
        this.testDao = testDao;
    }

    @Override
    public void save(String str) {
        //模擬業務操作
        System.out.println("TestServiceImpl接收參數:" + str);
        str = str + ":" + this.hashCode();

        testDao.save(str);
    }
}
  1. 結果:


    Paste_Image.png

繼續學習@Autowired

  • 可以使用@Autowired注解那些眾所周知的解析依賴性接口。比如:BeanFactory、ApplicationContext、Environment、resourceLoader、ApplicationEventPublisher、MessageSource。
  • 可以給集合添加@Autowired注解,例如List<interface>,ApplicationContext中所有符合條件的此接口的實現類(bean)會傳入到List中。
 @Autowired
    private List<BeanInterface> list;
  • 可以給Map<String,Interface>添加@Autowired注解,例如:Map<String,BeanInterface>,在ApplicationContext中符合條件的此接口實現類會自動被加入到map中。其中key為beanId,Value是bean本身。
 @Autowired
    private Map<String,BeanInterface> map;
  • 如果希望集合有序,可以讓bean實現org.springframework.core.Ordered接口或使用@Order注解
  • @Antowired是由Spring BeanPostProcessor處理的,所以不能在自己的BeanPostProcessor或BeanFactoryPostProcessor類型應用這些注解,這些類型必須通過xml或者Spring的@Bean注解加載。

數組及Map的自動注入例子

  1. 準備工作
    • 新建一個接口
package test11;
/**
 * Created by amber on 2017/6/15.
 */
public interface BeanInterface {
}
* 新建兩個它的實現類BeanImplOne 、BeanImplTwo 并添加通用注解@Component
package test11;
import org.springframework.stereotype.Component;
/**
 * Created by amber on 2017/6/15.
 */
@Component
public class BeanImplOne implements BeanInterface {
}
package test11;
import org.springframework.stereotype.Component;
/**
 * Created by amber on 2017/6/15.
 */
@Component
public class BeanImplTwo implements BeanInterface {
}
  • 新建一個調用類BeanInvoker 在其類上添加了注解@Component,兩個屬性 List<BeanInterface>和Map<String,BeanInterface>也添加了@Autowired注解。
package test11;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
/**
 * Created by amber on 2017/6/15.
 */
@Component
public class BeanInvoker {
   @Autowired
    private List<BeanInterface> list;
    @Autowired
    private Map<String,BeanInterface> map;
    public void say(){
        if(list!=null){
            System.out.println("list is not null! ");
            for(BeanInterface item : list){
                System.out.println("className: "+item.getClass().getName());
            }
        }else {
            System.out.println("list is null! ");
        }
       if(map!=null){
            System.out.println("map is not null! ");
            for(Map.Entry item : map.entrySet()){
                System.out.println("key: "+item.getKey()+ " className: "+item.getValue().getClass().getName());
            }
        }else {
            System.out.println("map is null! ");
        }
   }
}
  1. 測試函數:
 @Test
    public void test11() {
        BeanInvoker invoker=super.getBean("beanInvoker");
        invoker.say();
    }
  1. 結果:


    Paste_Image.png
  2. 增加集合類型的排序,在兩個實現類上使用@Order
package test11;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
 * Created by amber on 2017/6/15.
 */
@Order(2)
@Component
public class BeanImplOne implements BeanInterface {
}
package test11;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
 * Created by amber on 2017/6/15.
 */
@Order(1)
@Component
public class BeanImplTwo implements BeanInterface {
}

經過排序,BeanImplTwo 就對照@Order(1),先被加入到list中了。


Paste_Image.png

Qualifier

  • 因為@Autowired默認是按類型查找注入的,所以可能多個bean實例的情況,這時可以使用Spring的Qualifier注解(變成按名稱查找)縮小范圍或指定唯一,也可以用于指定單獨的構造器參數或方法參數。
  • 可用于注解集合類型變量。
  • 如果通過名字進行注解注入,主要使用的不是@Autowired(即使在技術上能夠通過@Qualifier指定bean的名字),替代方式是使用JSR-250@Resource注解,它是通過其獨特的名稱來定義來識別特定的目標(這是一個與所聲明類型無關的匹配過程)。
  • 因語義的差異,集合或Map類型的bean,無法通過@Autowired來注入,因為沒有類型匹配到這樣的bean,為這些bean使用@Resource注解,通過唯一名稱引用集合或者Map的bean。
  • @Autowired適用于局部變量、構造、多參數方法這些允許在參數級別使用@Qualifier注解縮小范圍的情況。
  • @Resource適用于成員變量、只有一個參數的setter方法,所以在目標是構造器或一個多參數的方法時,最好的方式是使用@Qualifier。

在xml配置文件中使用qualifier ,就相當于beanid:

 <bean class="test11.BeanImplOne">
        <qualifier value="main"/>
  </bean>

上一個測試得知BeanInterface 有兩個實現類,我現在使用@Qualifier注解指定只注入其中一個:

 @Autowired
    @Qualifier("beanImplOne")
    private BeanInterface beanInterface;
  public void say(){
        if(beanInterface!=null){
            System.out.println("name: "+beanInterface.getClass().getName());
        }else {
            System.out.println("beanInterface is null! ");
        }
   }

結果:


Paste_Image.png

基于Java容器的注解@Bean

  • @Bean標識一個用于配置和初始化一個由ApringIoC容器管理的新對象的方法,類似于xml配置文件的<bean/>。
  • 可以在Spring的@Componet注解的類中使用@Bean注解任何方法(僅僅是可以)。
  • 通常和@Bean結合使用的是@Configuration。
  • @Bean在方法上注解,方法名是bean默認的id。

示例:

  1. 創建一個Store接口:
package test12;
/**
 * Created by amber on 2017/6/15.
 */
public interface Store {
}
  1. 創建一個它的是實現類,StringStore:
package test12;
/**
 * Created by amber on 2017/6/15.
 */
public class StringStore implements Store {
}
  1. 創建StringConfig
package test12;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * Created by amber on 2017/6/15.
 */
@Configuration
public class StringConfig {
   @Bean
    public Store getStringStore(){
        return  new StringStore();
    }
}
  1. 測試方法:
   @Test
    public void test12() {
        Store store=super.getBean("getStringStore");
        System.out.println("store name: "+store.getClass().getName());
    }

結果:


Paste_Image.png
  1. 指定@Bean(name="xx")
package test12;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * Created by amber on 2017/6/15.
 */
@Configuration
public class StringConfig {
    @Bean(name = "stringStore")
    public Store getStringStore(){
        return  new StringStore();
    }
}
 @Test
    public void test12() {
        Store store=super.getBean("stringStore");
        System.out.println("store name: "+store.getClass().getName());
    }

結果:


Paste_Image.png
  1. 指定這個bean的init和destroy方法
@Bean(name = "stringStore",initMethod="init",destroyMethod = "destroy")
    public Store getStringStore(){
        return  new StringStore();
    }

StringStore類添加init和destroy方法:

package test12;
/**
 * Created by amber on 2017/6/15.
 */
public class StringStore implements Store {
    
    public void init(){
        System.out.println("StringStore初始化");     
    }

    public void destroy(){
        System.out.println("StringStore銷毀");
   }
}

運行結果:


Paste_Image.png

基于Java容器的注解@ImportResource和@Value注解進行資源文件讀取并把結果注入到對應屬性

  • 使用xml進行配置:
    • 通過<context:property-placeholder location="classpath:jdbc.properties"/>加載配置文件
    • <property name="url" value="${db.url}"></property>通過EL表達式獲取對應屬性的值
      applicationContext.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.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        ">
          <context:component-scan base-package="test12"></context:component-scan>
          <context:property-placeholder location="classpath:jdbc.properties"/>
          <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
              <property name="url" value="${db.url}"></property>
              <property name="username" value="${db.username}"></property>
              <property name="password" value="${db.password}"></property>
          </bean>
</beans>

jdbc.properties文件:

db.driverLocation=I:/IdeaProjects/mysql-connector-java-5.1.6-bin.jar
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/ambermall?characterEncoding=utf-8
db.username=root
db.password=amber
  • 使用注解進行配置:
    創建MyDriverManager類:
package test12;
/**
 * Created by amber on 2017/6/16.
 */
public class MyDriverManager {
    public MyDriverManager(){}
    public MyDriverManager(String url,String userName,String password){
        System.out.println("url: "+url+"\nuserName: "+userName+"\npassword: "+password);
    }
}

修改之前的StringConfig類如下:
因為我加載的是.properties文件,所以注解使用@PropertySource。如果加載xml文件,請使用@ImportResource

package test12;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
/**
 * Created by amber on 2017/6/15.
 */
@Configuration
@PropertySource("classpath:jdbc.properties")
public class StringConfig {
    @Value("${db.url}")
    private String url;
    @Value("${db.username}")
    private String userName;
    @Value("${db.password}")
    private String password;
    @Bean
    public MyDriverManager myDriverManager(){
        return new MyDriverManager(url,userName,password);
    }
}

測試方法:

  @Test
    public void test12() {
        MyDriverManager manager = super.getBean("myDriverManager");
        if(manager!=null)
        System.out.println(manager.getClass().getName());
    }

結果:


Paste_Image.png

@Bean和@Scope

  • 使用@Bean注解,默認是單例模式的。可以通過作用域注解@Scope,更改其他模式。
  • @Scope的取值是:singleton、prototype、request、session、global session。

下面示例:

  1. 更改StringConfig類
package test12;
import org.springframework.context.annotation.*;
/**
 * Created by amber on 2017/6/15.
 */
@Configuration
public class StringConfig {
    @Bean(name = "stringStore",initMethod = "init",destroyMethod = "destroy")
    @Scope("prototype")
    public Store stringStore() {
        return new StringStore();
    }
}
  1. 測試方法:
   @Test
    public void test12() {
        for(int i=0;i<2;i++){
            StringStore store = super.getBean("stringStore");
            System.out.println(store.hashCode());
        }
    }
  1. 結果:細心的小伙伴可能發現,多例之后,沒有執行destroy的方法了,那是因為多例模式,每產生一個實例在使用完成后,都會自動被JVM垃圾回收器回收。
Paste_Image.png

基于泛型的自動裝配

示例:

  1. 修改Store接口:
package test12;
/**
 * Created by amber on 2017/6/15.
 */
public interface Store<T>{
}
  1. 修改實現類StringStore :
package test12;
/**
 * Created by amber on 2017/6/15.
 */
public class StringStore implements Store<String> {
}

增加IntegerStore:

package test12;
/**
 * Created by amber on 2017/6/16.
 */
public class IntegerStore implements Store<Integer> {
}
  1. 更改StringConfig 類:
package test12;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
/**
 * Created by amber on 2017/6/15.
 */
@Configuration
public class StringConfig {
    @Autowired
    private StringStore s1;
    @Autowired
    private IntegerStore s2;
    @Bean
    public Store store() {
        System.out.println("s1: "+s1.getClass().getName());
        System.out.println("s2: "+s2.getClass().getName());
        return new StringStore();
    }
    @Bean
    public StringStore stringStore(){
        return new StringStore();
    }
    @Bean
    public IntegerStore integerStore(){
        return new IntegerStore();
    }
}
  1. 測試
  @Test
    public void test12() {
      super.getBean("store");
    }
  1. 結果:


    Paste_Image.png

CustomAutowireConfigurer

  • CustomAutowireConfigurer是一個BeanFactoryPostProcessor子類,這個后置處理器可以注冊開發者自己的限定符注解,讓開發者的注解不依賴于Spring限定符注解。
  • 通過CustomAutowireConfigurer可以注冊自己的qualifier注解類型(即使沒有使用Spring的@qualifier注解)
<bean id="customAutowireConfigurer"
        class="org.springframework.beans.factory.annotation.CustomAutowireConfigurer">
        <property name="customQualifierTypes">
          <set>
              <value>example.CustomQualifier</value>
          </set>
    </property>
</bean>

AutowireCandidateResolver用來處理customQualifierTypes的,通過以下的幾種方式來決定自動裝載的候選Bean:
* Bean定義中的autowire-candidate的值
* 任何<beans/>標簽中定義的default-autowire-candidates的值
* @Qualifier注解和任何在CustomAutowireConfigurer中定義的自定義的限定符注解
* 當多個Bean限定為自動裝載的候選時, 前文中提到的primary屬性是優先考慮的。

@Resource

  • Spring還支持使用JSR-250@Resource注解的變量或setter方法,這是一種在java EE 5和6的通用方式,Spring管理的對象也支持這種模式。
  • @Resource有一個name屬性,并且默認Spring解釋該值,作為被注入bean的名稱。
  • 如果沒有顯式地指定@Resource的name,默認的名稱是從屬性名或者setter方法得出。
  • 注解提供的名字,被解析為一個bean名稱,這是由ApplicationContext中的CommonAnnotationBeanPostProcesser發現并處理的。

@PostConstruct 和 @PreDestroy

  • CommonAnnotationBeanPostProcesser類不僅能識別JSR-250中的生命周期注解@Resource,在Spring2.5中引入支持初始化回調(@PostConstruct)和銷毀回調( @PreDestroy),前提是CommonAnnotationBeanPostProcesser類是Spring的ApplicationContext中注冊的。

下面示例:

  1. 創建JsrDao 類:
package test13;
import org.springframework.stereotype.Repository;
/**
 * Created by amber on 2017/6/16.
 */
@Repository
public class JsrDao {
    public void save(){
        System.out.println("JsrDao invoked");
    }
}
  1. 創建JsrService 類:
package test13;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
 * Created by amber on 2017/6/16.
 */
@Service
public class JsrService {
//@Resource注解在成員變量上或者方法上都是一樣的效果,二者選其一即可,此處為了展示才都寫上了。此處也可以替換成@Autowired,效果也是一樣的
    @Resource 
    private JsrDao jsrDao;
//@Resource注解在成員變量上或者方法上都是一樣的效果,二者選其一即可,此處為了展示才都寫上了。此處也可以替換成@Autowired,效果也是一樣的
    @Resource
    public void setJsrDao(JsrDao jsrDao) {
        this.jsrDao = jsrDao;
    }
    public void save(){
        jsrDao.save();
    }
}
  1. 測試:
  @Test
    public void test13() {
        JsrService jsrService=super.getBean("jsrService");
        jsrService.save();
    }
  1. 結果:


    Paste_Image.png
  2. 在JsrService 中添加@PostConstruct 和 @PreDestroy
package test13;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
/**
 * Created by amber on 2017/6/16.
 */
@Service
public class JsrService {
    @Resource
    private JsrDao jsrDao;
    @Resource
    public void setJsrDao(JsrDao jsrDao) {
        this.jsrDao = jsrDao;
    }
    @PreDestroy //銷毀回調
    public void destroy(){
        System.out.println("我是銷毀回調");
    }
    @PostConstruct //初始化回調
    public void init(){
        System.out.println("我是初始化回調");
    }
    public void save(){
        jsrDao.save();
    }
}
  1. 結果:


    Paste_Image.png

使用JSR330標準注解

  • 從Spring3.0開始支持JSR330標準注解(依賴注入注解),其掃描方式與Spring注解一致。
  • 使用JSR330需要依賴javax.inject包
  • 使用Maven引入方式
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

@Inject

  • @Inject等效于@Autowired,可以使用于類、屬性、方法、構造器。

@Named

  • 如果想使用特定名稱進行依賴注入,使用@Named。
  • @Named與@Component是等效的。
  • @Named與@Qualifier類似。

下面示例:

  1. 修改JSRService類的注解@Service改成@Named
package test13;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Named;
/**
 * Created by amber on 2017/6/16.
 */
@Named
public class JsrService {
    @Inject
    private JsrDao jsrDao;
    @Inject
    public void setJsrDao(JsrDao jsrDao) {
        this.jsrDao = jsrDao;
    }
    @PreDestroy //銷毀回調
    public void destroy(){
        System.out.println("我是銷毀回調");
    }
    @PostConstruct //初始化回調
    public void init(){
        System.out.println("我是初始化回調");
    }
    public void save(){
        jsrDao.save();
    }
}
  1. 運行結果:


    Paste_Image.png

下一篇:Spring學習筆記(六、Spring AOP基本概念)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容