1. 程式人生 > >spring之註解(三)Component

spring之註解(三)Component

上篇文章中比較詳細的介紹了依賴注入的相關注解,尤其是@Autowired。但是我們對bean的定義宣告還是放在xml的配置檔案中。Spring當然提供了機制可以自動的掃描類路徑,自動的向容器註冊BeanDefinition。這就是Bean級別的註解。以上機制稱為類路徑掃描(clsspath-sacn),它是有相關注解(如@Component @Named @Bean)和beanFactoryPostProcessor和BeanPostProcessor實現的。本篇文章我們依次對各個註解進行說明。

本篇使用的示例程式碼繼承之前的篇章。首先看註解。

@Component

元註解

這是一個元註解,意思是它可以用於標註其他註解,被它標註的註解和它起到相同或者類似的作用。Spring用它定義了其他具有特定意義的註解如@Controller @Service @Repository。如下是Spring中 @Service的定義:

@Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component // Spring will see this and treat @Service in the same way as @Component
    public @interface Service {
    }

另外@Controller  和 @Repository與之類似。Spring在web專案賦予這些註解特殊的含義。分別表示控制器和 資料訪問層。

自定義

  我們可以自定義註解,如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface MyComponent {
String value();
}

使用

我們現在可以使用(自定義)註解直接標註在某個類上,此類就會自動的被Spring容器註冊為BeanDefinition,我們可以對上篇文章中在xml中定義的bean改也註解的方式進行宣告:

//使用元註解
@Component("user1")
public class UserServiceIml1 implements UserService{
   
    private UserDao userDao;
    @Override
    public List<User> getUser() {
       return userDao.getUser();
    }
    //標註在set方法上。
    @Autowired
    public void setUserDao(@Qualifier("userDao") UserDao userDao) {
       this.userDao = userDao;
    }
}

//使用自定義註解
@MyComponent("user2")
public class UserServiceIml2 implements UserService{
    //標註在欄位上。
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;
    @Override
    public List<User> getUser() {
       return userDao.getUser();
    }
   
}

以上使用註解後,我們需要做一些配置是Spring啟用類路徑掃描(classpath-scan),在XML配置中加入以下配置,這個配置就自動啟用了註解的相關功能:

 <context:component-scan base-package="com.test"/>


以上註解表示自動掃描com.test包及其子包下被@component(或者其擴充套件)表中的類,並把他們註冊為bean。以上配置還有其他屬性,可以定義專門的過濾器做自定義的配置。

以下為一個示例:

<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>

@Bean

在採用XML配置bean的時候,我們可以使用例項工廠來定義一個Bean,採用@Bean註解我們也可以做到類似的形式。在一個Bean中定義另外一個Bean。這通過在@Component的標註類中對某個方法使用@Bean進行註解。

如下所示:

@Bean(name="getService")
   @Qualifier("getService")
   public UserService getService(@Qualifier("userDao") UserDao user){
      UserService ser = new UserServiceIml1();
     
      return ser;
   }

上述定義一個Bean,並定義了Name和Qualifier屬性。還可以定義Scope,Lazy等屬性。見下個小節。

其實@Bean更多的是與@Confuguration一起使用,來構建另外一種不同於基於XML的ApplicationContext,即基於註解的,AnnotationConfigApplicationContext。這個以後討論。

命名和其他屬性

命名

基於@Componet及其擴充套件(如@Servic和自定義等)標註和classpath-scan定義的Bean,註解有一個value屬性,如果提供了,那麼就此Bean的名字。如果不提供。就會使用Spring預設的命名機制,即簡單類名且第一個字母小寫,見如下示例:

@Component("user5")
//Bean的名稱是user5
public class UserServiceIml5 implements UserService{
}
 
@Component()
//Bean的名稱是userServiceIml3
public class UserServiceIml3 implements UserService{
}

 我們可以更新Spring預設的命名機制,只要我們實現了相關介面BeanNameGenerator,並進行配置,如下:

<context:component-scan base-package="org.example"
        name-generator="org.example.MyNameGenerator" />

其他

在基於XML的配置中bean標籤還有很多屬性,如scope、Lazy、init-method、depends-on、Qualifier等。下面通過一個簡單的配置例子說明:

package com.test.service;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
 
import com.test.bo.User;
import com.test.dao.UserDao;
import com.test.dao.UserDaoImp;
import com.test.service.UserService;
//使用元註解
@Component("user1")
@Qualifier("user1")
@Lazy(true)
@DependsOn("userDao")
public class UserServiceIml1 implements UserService{
  
   private UserDao userDao;
   @Override
   public List<User> getUser() {
     
      return userDao.getUser();
   }
   //標註在set方法上。
   @Autowired
   public void setUserDao(@Qualifier("userDao") UserDao userDao) {
      this.userDao = userDao;
   }
  
  
  
   @Bean(name="getService",initMethod="init1",destroyMethod="close1")
   @Qualifier("getService")
   @Scope(value="singleton")
   @Lazy(true)
   @DependsOn("getDao")
   public UserService getService(@Qualifier("getDao") UserDao user){
      System.out.println("------------getService is creted when used--------------");
      System.out.println(user.getClass().toString());
      UserService ser = new UserServiceIml1();
      return ser;
   }
  
  
   @Bean(name = "getDao")
   @Qualifier("getDao")
   @Scope(value="prototype",proxyMode=ScopedProxyMode.TARGET_CLASS)
   @Lazy(true)
   public UserDao getDao(){
      System.out.println("------------getDao is creted when used--------------");
      return new UserDaoImp();
   }
  
  
   private void init1(){
      System.out.println("---------getService init1----------------");
 
   }
  
   private void close1(){
      System.out.println("---------getService close----------------");
   }
   public UserDao getUserDao() {
      return userDao;
   }
  
  
}

上述分別在類上和某個方法上,加入了很多的屬性配置,可以和傳統的XMl的配置比較。主要singleton引用其他型別時,需要生成代理。

@Configuration

Spring提供一種基於註解的applicationContext,實際應用中,它可以和XML的配置聯合使用或者各自單獨使用。當使用時,需要很大的利用的@Bean註解。

下面給一個簡單的例子,其他的詳細例子見Spring官方文件。

首先是一個@Configuration 的配置類,定義了兩個Bean。

@Configuration
public class MyAnnoConfig {
 
   @Bean(name="cDao1")
   public UserDao getConfigDao(){
      return new UserDaoImp();
   }
  
   @Bean(name="cs1")
   public UserService getConfigS(@Qualifier("cDao1") UserDao dao){
     
      UserServiceIml us =new UserServiceIml();
      us.setUserDao(dao);
      return us;
   }
  
  
}

下面是測試函式。

public class TestAnnoContextMain {
 
   public static void main(String[] args) {
      ApplicationContext  ctx = new AnnotationConfigApplicationContext(MyAnnoConfig.class);
     
      UserService us = ctx.getBean("cs1",UserService.class);
      System.out.println(us.getUser());
   }
}

總結

本篇較詳細的說明了Spring支援的Bean級別的註解的使用方法,主要介紹了@Component和@Bean(在@component中使用),並穿插介紹了一些Bean屬性的註解。最後注意舉例說明Spring的基於註解的applicationContext和@configuration。

注意,本篇沒有介紹JSR-330的註解@Named,其和@Component基本一致,但不如前者強大。並且我認為只要比較清楚的一種方式的原理和使用方法,其他的都是舉一反三的例子=,這也是不詳細寫@configuration的原因(其實它和@Bean配合,和基於XML的配置的功能幾乎一樣)。本完整測試程式碼0分