- 類型:ACT動(dòng)作游戲大。72.9M語(yǔ)言:中文 評(píng)分:10.0
- 標(biāo)簽:
@Service與@Component有什么不同?那天被問(wèn)到這個(gè)問(wèn)題,一時(shí)之間卻想不起來(lái),就利用這篇文章來(lái)紀(jì)錄spring3.0中常用的annotation。
從spring2.5開(kāi)始,annotation結(jié)合BeanPostProcessor成了擴(kuò)展Spring IoC容器的常用方法。Spring2.5增加了對(duì)JSR-250中@Resource, @PostConstruct, @PreDestroy的支持,Spring 3.0又增加了對(duì)JSR-330 (Dependency Injection for Java)中 @Inject,@Qualifier, @Named, @Provider的支持。將相關(guān)的jsr jar包丟到classpath,并注冊(cè)相應(yīng)的BeanPostProcessor,其它的一切spring會(huì)幫你完成。spring還提供了一個(gè)簡(jiǎn)便的方法,通過(guò)在context的XML配置文件中加入:Xml代碼
<context:annotation-config/>
<context:annotation-config/>
spring 會(huì)自動(dòng)注冊(cè)AutowiredAnnotationBeanPostProcessor, CommonAnnotationBeanPostProcessor, RequiredAnnotationBeanPostProcessor,代碼中就可以使用@Autowired, @Required等annotaion了。
再回到文章開(kāi)頭的問(wèn)題吧。spring從2.5開(kāi)始加入了classpath scanning的功能,來(lái)代替之前在xml中定義Bean。首先在context的XML配置文件中加入:Xml代碼
<context:component-scan base-package="org.example"/>
<context:component-scan base-package="org.example"/>
spring 便會(huì)在org.example以及它的子package中查找所有的類,將符合條件的Bean注冊(cè)在IoC容器當(dāng)中。到3.0,spring引入了4種原型annotation(stereotype annotaion),分別為@Component, @Serivce, @Controller, @Repository。一般情況下只在將類加上@Componet,spring在掃描classpath的時(shí)候會(huì)自動(dòng)檢測(cè)到,并將這個(gè)類注冊(cè)到IoC 容器中,在代碼的其它部分,便可以借助@Autowired來(lái)注入這個(gè)Bean。后面的三種原型分別是特殊的@Conponet,適用于更加特殊的場(chǎng)合,比如Service層,Spring MVC, DAO等。這一點(diǎn)從源碼上也可以看出:
Java代碼
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
String value() default "";
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
String value() default "";
}
@Service本身就是被@Componet這個(gè)元注解(meta annotaion)標(biāo)注的。因此對(duì)于這三個(gè)層的Bean, spring的文檔也推薦將它們標(biāo)注為@Service, @Controller與@Repository,因?yàn)檫@樣更方便其它工具對(duì)這些特殊Bean的處理以及為它們加上相關(guān)AOP的 aspects,spring在后續(xù)版本的升級(jí)上也可能對(duì)它們?cè)黾痈嗟奶厥庹Z(yǔ)義。至于它們到底比普通的@Componet多了哪些 aspects,spring的文檔上并沒(méi)有詳細(xì)說(shuō)明,只簡(jiǎn)單地提到了對(duì)于@Repository,spring會(huì)自動(dòng)加上exception translation,用于轉(zhuǎn)化持久層拋出的異常。我google了一下,包括spring論壇的帖子,也沒(méi)能找到這方面的詳細(xì)信息,這點(diǎn)希望熟悉spring源代碼的朋友能夠說(shuō)說(shuō)。
現(xiàn)在通過(guò)classpath scanning以及@Component,@Autowired等annotation,我們已無(wú)須通過(guò)xml來(lái)定義Bean了。但還必須在application context的xml中添加<context:annotation-config/>與<context:component-scan base-package="org.example"/>。再進(jìn)一步想,能不能把這個(gè)配置文件也去掉,實(shí)現(xiàn)真正的零配置?spring3.0原先Spring JavaConfig項(xiàng)目的功能移到了Spring Core里面,從而實(shí)現(xiàn)了利用Java代碼來(lái)代替?zhèn)鹘y(tǒng)的XML配置文件,這個(gè)功能是通過(guò)@Configuration, @Bean, @Import, @DependsOn等annotation實(shí)現(xiàn)的。
Java代碼
@Configuration
public class AppConfig {
@Bean
public GreetingDao greetingDao() {
return new GreetingDao();
}
}
public class GreetingDao {
public String getGreeting(){
return "Hi";
}
}
@Configuration
public class AppConfig {
@Bean
public GreetingDao greetingDao() {
return new GreetingDao();
}
}
public class GreetingDao {
public String getGreeting(){
return "Hi";
}
}
@configuration表明這個(gè)類包含Bean的定義,@Bean在這里就相當(dāng)于原先的配置:<bean id="greetingDao" class="septem.demo.GreetingDao"/>。通過(guò)AnnotationConfigApplicationContext就可以使用這個(gè)Bean了:
Java代碼
@Test
public void test_java_config(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
GreetingDao dao = ctx.getBean(GreetingDao.class);
assertEquals("Hi", dao.getGreeting());
}
@Test
public void test_java_config(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
GreetingDao dao = ctx.getBean(GreetingDao.class);
assertEquals("Hi", dao.getGreeting());
}
注意AppConfig里面的greetingDao雖然是是直接new出來(lái)的,但它的默認(rèn)scope仍是singleton,跟采用配置文件的情況是一樣的,如果需要prototype,則可以另外為它加上@Scope("prototype")。上面采用的方法是手工將Bean定義在 @Configuration里面,我們同樣可以讓spring自動(dòng)檢測(cè)Bean,比如下面的GreetingSerivce:
Java代碼
@Service
public class GreetingService {
public String sayHello(){
return "Hello";
}
}
@Service
public class GreetingService {
public String sayHello(){
return "Hello";
}
}
將GreetingService標(biāo)注為@Service,就不需要在AppConfig里面注冊(cè)了:
Java代碼
@Test
public void test_service(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("septem.demo");
ctx.refresh();
GreetingService service = ctx.getBean(GreetingService.class);
assertEquals("Hello", service.sayHello());
}
@Test
public void test_service(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("septem.demo");
ctx.refresh();
GreetingService service = ctx.getBean(GreetingService.class);
assertEquals("Hello", service.sayHello());
}
以上的ctx.scan("septem.demo")就相當(dāng)于配置文件:<context:component-scan base-package="septem.demo"/>。注意因?yàn)锧Configuration本身也是被@Component這個(gè)meta-annotation標(biāo)注的,所以AppConfig也不需要手工在 AnnotationConfigApplicationContext里注冊(cè),它同@Service一樣會(huì)被自動(dòng)檢測(cè)到。Spring3.0還提供了 AnnotationConfigWebApplicationContext用來(lái)代替原先web項(xiàng)目中的 XmlWebApplicationContext,這樣在web項(xiàng)目中同樣可以實(shí)現(xiàn)真正的零配置了。Spring的官方文檔還提供了針對(duì)更復(fù)雜情況的處理方法,有興趣的朋友可以看看。