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分