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