12.3? 注解實(shí)現(xiàn)Bean定義
12.3.1? 概述
前邊介紹的Bean定義全是基于XML方式定義配置元數(shù)據(jù),且在【12.2注解實(shí)現(xiàn)Bean依賴注入】一節(jié)中介紹了通過注解來減少配置數(shù)量,但并沒有完全消除在XML配置文件中的Bean定義,因此有沒有方式完全消除XML配置Bean定義呢?
?
Spring提供通過掃描類路徑中的特殊注解類來自動(dòng)注冊(cè)Bean定義。同注解驅(qū)動(dòng)事務(wù)一樣需要開啟自動(dòng)掃描并注冊(cè)Bean定義支持,使用方式如下(resources/chapter12/ componentDefinitionWithAnnotation.xml):
?
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <aop:aspectj-autoproxy /> <context:component-scan base-package="cn.javass.spring.chapter12"/> </beans>
?
?????? 使用<context:component-scan>標(biāo)簽來表示需要要自動(dòng)注冊(cè)Bean定義,而通過base-package屬性指定掃描的類路徑位置。
?????? <context:component-scan>標(biāo)簽將自動(dòng)開啟“ 注解實(shí)現(xiàn) Bean 依賴注入 ”支持。
?????? 此處我們還通過<aop:aspectj-autoproxy/>用于開啟Spring對(duì)@AspectJ風(fēng)格切面的支持。
?
Spring基于注解實(shí)現(xiàn)Bean定義支持如下三種注解:
- Spring 自帶的@Component 注解及擴(kuò)展 @Repository 、@Service 、@Controller ,如圖12-1所示;
- JSR-250 1.1 版本中中定義的@ManagedBean 注解 ,是Java EE 6標(biāo)準(zhǔn)規(guī)范之一,不包括在JDK中,需要在應(yīng)用服務(wù)器環(huán)境使用(如Jboss),如圖12-2所示;
- JSR-330 的@Named 注解 ,如圖12-3所示。
圖12-1 Spring自帶的@Component注解及擴(kuò)展
?
圖12-2 JSR-250中定義的@ManagedBean注解及自定義擴(kuò)展
?
圖12-3 JSR-330的@Named注解及自定義擴(kuò)展
?
圖12-2和圖12-3中的自定義擴(kuò)展部分是為了配合Spring自帶的模式注解擴(kuò)展自定義的,并不包含在Java EE 6規(guī)范中,在Java EE 6中相應(yīng)的服務(wù)層、DAO層功能由EJB來完成。
?
在Java EE中有些注解運(yùn)行放置在多個(gè)地方,如@Named允許放置在類型、字段、方法參數(shù)上等,因此一般情況下放置在類型上表示定義,放置在參數(shù)、方法等上邊一般代表使用(如依賴注入等等)。
?
?
12.3.2? Spring自帶的@Component注解及擴(kuò)展
一、@Component :定義Spring 管理Bean , 使用方式如下:
?
@Component("標(biāo)識(shí)符") POJO類
? 在類上使用@Component注解,表示該類定義為Spring管理Bean,使用默認(rèn)value(可選)屬性表示Bean標(biāo)識(shí)符。
?
1、定義測試Bean類:
?
package cn.javass.spring.chapter12; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component("component") public class TestCompoment { @Autowired private ApplicationContext ctx; public ApplicationContext getCtx() { return ctx; } }
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
3、定義測試類和測試方法:
?
package cn.javass.spring.chapter12; //省略import public class ComponentDefinitionWithAnnotationTest { private static String configLocation = "classpath:chapter12/componentDefinitionWithAnnotation.xml"; private static ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation); @Test public void testComponent() { TestCompoment component = ctx.getBean("component", TestCompoment.class); Assert.assertNotNull(component.getCtx()); } }
? ? 測試成功說明被@Component注解的POJO類將自動(dòng)被Spring識(shí)別并注冊(cè)到Spring容器中,且自動(dòng)支持自動(dòng)裝配。
?
@AspectJ 風(fēng)格的切面可以通過@Compenent 注解標(biāo)識(shí)其為Spring 管理Bean ,而@Aspect 注解不能被Spring 自動(dòng)識(shí)別并注冊(cè)為Bean ,必須通過@Component 注解來完成,示例如下:
?
package cn.javass.spring.chapter12.aop; //省略import @Component @Aspect public class TestAspect { @Pointcut(value="execution(* *(..))") private void pointcut() {} @Before(value="pointcut()") public void before() { System.out.println("=======before"); } }
?
?
通過@Component 將切面定義為Spring 管理Bean 。
?
?
二、@Repository :@Component 擴(kuò)展,被@Repository 注解的POJO 類表示DAO 層實(shí)現(xiàn),從而見到該注解就想到DAO 層實(shí)現(xiàn),使用方式和@Component 相同;
??????
1、定義測試Bean類:
?
package cn.javass.spring.chapter12.dao.hibernate; import org.springframework.stereotype.Repository; @Repository("testHibernateDao") public class TestHibernateDaoImpl { }
?
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
3、定義測試方法:
?
@Test public void testDao() { TestHibernateDaoImpl dao = ctx.getBean("testHibernateDao", TestHibernateDaoImpl.class); Assert.assertNotNull(dao); }
? ? 測試成功說明被@Repository注解的POJO類將自動(dòng)被Spring識(shí)別并注冊(cè)到Spring容器中,且自動(dòng)支持自動(dòng)裝配,并且被@Repository注解的類表示DAO層實(shí)現(xiàn)。
?
?
三、@Service :@Component 擴(kuò)展,被@Service 注解的POJO 類表示Service 層實(shí)現(xiàn),從而見到該注解就想到Service 層實(shí)現(xiàn),使用方式和@Component 相同;
?
1、定義測試Bean類:
?
package cn.javass.spring.chapter12.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import cn.javass.spring.chapter12.dao.hibernate.TestHibernateDaoImpl; @Service("testService") public class TestServiceImpl { @Autowired @Qualifier("testHibernateDao") private TestHibernateDaoImpl dao; public TestHibernateDaoImpl getDao() { return dao; } }
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
?
3、定義測試方法:
?
@Test public void testService() { TestServiceImpl service = ctx.getBean("testService", TestServiceImpl.class); Assert.assertNotNull(service.getDao()); }
?
測試成功說明被@Service注解的POJO類將自動(dòng)被Spring識(shí)別并注冊(cè)到Spring容器中,且自動(dòng)支持自動(dòng)裝配,并且被@Service注解的類表示Service層實(shí)現(xiàn)。
?
?
四、@Controller :@Component 擴(kuò)展,被@Controller 注解的類表示W(wǎng)eb 層實(shí)現(xiàn),從而見到該注解就想到Web 層實(shí)現(xiàn),使用方式和@Component 相同;
?
1、定義測試Bean類:
?
package cn.javass.spring.chapter12.action; //省略import @Controller public class TestAction { @Autowired private TestServiceImpl testService; public void list() { //調(diào)用業(yè)務(wù)邏輯層方法 } }
?
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
3、定義測試方法:
?
@Test public void testWeb() { TestAction action = ctx.getBean("testAction", TestAction.class); Assert.assertNotNull(action); }
? ? 測試成功說明被@Controller注解的類將自動(dòng)被Spring識(shí)別并注冊(cè)到Spring容器中,且自動(dòng)支持自動(dòng)裝配,并且被@Controller注解的類表示W(wǎng)eb層實(shí)現(xiàn)。
?
大家是否注意到@Controller中并沒有定義Bean的標(biāo)識(shí)符,那么默認(rèn)Bean的名字將是以小寫開頭的類名(不包括包名),即如“TestAction”類的Bean標(biāo)識(shí)符為“testAction”。
?
?
?
六、自定義擴(kuò)展:Spring 內(nèi)置了三種通用的擴(kuò)展注解@Repository 、@Service 、@Controller? ,大多數(shù)情況下沒必要定義自己的擴(kuò)展,在此我們演示下如何擴(kuò)展@Component 注解來滿足某些特殊規(guī)約的需要;
?
在此我們可能需要一個(gè)緩存層用于定義緩存Bean,因此我們需要自定義一個(gè)@Cache的注解來表示緩存類。
?
?
1、擴(kuò)展@Component:
?
package cn.javass.spring.chapter12.stereotype; //省略import @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Cache{ String value() default ""; }
? ? 擴(kuò)展十分簡單,只需要在擴(kuò)展的注解上注解@Component即可, @Repository 、 @Service、@Controller也是通過該方式實(shí)現(xiàn)的,沒什么特別之處
?
2、定義測試Bean類:
?
package cn.javass.spring.chapter12.cache; @Cache("cache") public class TestCache { }
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
?
3、定義測試方法:
?
@Test public void testCache() { TestCache cache = ctx.getBean("cache", TestCache.class); Assert.assertNotNull(cache); }
? ? 測試成功說明自定義的@Cache注解也能很好的工作,而且實(shí)現(xiàn)了我們的目的,使用@Cache來表示被注解的類是Cache層Bean。
?
?
12.3.3? JSR-250中定義的@ManagedBean注解
@javax.annotation.ManagedBean需要在實(shí)現(xiàn)Java EE 6規(guī)范的應(yīng)用服務(wù)器上使用,雖然Spring3實(shí)現(xiàn)了,但@javax.annotation.ManagedBean只有在Java EE 6環(huán)境中才有定義,因此測試前需要我們定義ManagedBean類。
?
?
1、定義javax.annotation.ManagedBean注解類:
?
package javax.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface ManagedBean { String value() default ""; }
其和@Component完全相同,唯一不同的就是名字和創(chuàng)建者(一個(gè)是Spring,一個(gè)是Java EE規(guī)范)。
?
?
2、定義測試Bean類:
?
package cn.javass.spring.chapter12; import javax.annotation.Resource; import org.springframework.context.ApplicationContext; @javax.annotation.ManagedBean("managedBean") public class TestManagedBean { @Resource private ApplicationContext ctx; public ApplicationContext getCtx() { return ctx; } }
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
?
3、定義測試方法:
?
@Test public void testManagedBean() { TestManagedBean testManagedBean = ctx.getBean("managedBean", TestManagedBean.class); Assert.assertNotNull(testManagedBean.getCtx()); }
? ? 測試成功說明被@ManagedBean注解類也能正常工作。
?
自定義擴(kuò)展就不介紹了,大家可以參考@Component來完成如圖12-2所示的自定義擴(kuò)展部分。
?
?
12.3.4? JSR-330的@Named注解
@Named不僅可以用于依賴注入來指定注入的Bean的標(biāo)識(shí)符,還可以用于定義Bean。即注解在類型上表示定義Bean,注解在非類型上(如字段)表示指定依賴注入的Bean標(biāo)識(shí)符。
?
1、定義測試Bean類:
?
package cn.javass.spring.chapter12; //省略import @Named("namedBean") public class TestNamedBean { @Inject private ApplicationContext ctx; public ApplicationContext getCtx() { return ctx; } }
?
2、Spring配置文件使用chapter12/ componentDefinitionWithAnnotation.xml即可且無需修改;
?
?
3、定義測試方法:
?
@Test public void testNamedBean() { TestNamedBean testNamedBean = ctx.getBean("namedBean", TestNamedBean.class); Assert.assertNotNull(testNamedBean.getCtx()); }
?
測試成功說明被@Named注解類也能正常工作。
?
自定義擴(kuò)展就不介紹了,大家可以參考@Component來完成如圖12-3所示的自定義擴(kuò)展部分。
?
?
12.3.5? 細(xì)粒度控制Bean定義掃描
在XML配置中完全消除了Bean定義,而是只有一個(gè)<context:component-scan>標(biāo)簽來支持注解Bean定義掃描。
?
?
前邊的示例完全采用默認(rèn)掃描設(shè)置,如果我們有幾個(gè)組件不想被掃描并自動(dòng)注冊(cè)、我們想更改默認(rèn)的Bean標(biāo)識(shí)符生成策略該如何做呢?接下來讓我們看一下如何細(xì)粒度的控制Bean定義掃描,具體定義如下:
?
<context:component-scan base-package="" resource-pattern="**/*.class" name-generator="org.springframework.context.annotation.AnnotationBeanNameGenerator" use-default-filters="true" annotation-config="true"> <context:include-filter type="aspectj" expression=""/> <context:exclude-filter type="regex" expression=""/> </context:component-scan>
- base-package : 表示掃描注解類的開始位置,即將在指定的包中掃描,其他包中的注解類將不被掃描,默認(rèn)將掃描所有類路徑;
- resource-pattern : 表示掃描注解類的后綴匹配模式,即“base-package+resource-pattern”將組成匹配模式用于匹配類路徑中的組件,默認(rèn)后綴為“**/*.class”,即指定包下的所有以.class結(jié)尾的類文件;
- name-generator :默認(rèn)情況下的Bean 標(biāo)識(shí)符生成策略,默認(rèn)是 AnnotationBeanNameGenerator,其將生成以小寫開頭的類名(不包括包名);可以自定義自己的標(biāo)識(shí)符生成策略;
- use-default-filters : 默認(rèn)為true表示過濾@Component、@ManagedBean、@Named注解的類,如果改為false默認(rèn)將不過濾這些默認(rèn)的注解來定義Bean,即這些注解類不能被過濾到,即不能通過這些注解進(jìn)行Bean定義;
- annotation-config : 表示是否自動(dòng)支持注解實(shí)現(xiàn)Bean依賴注入,默認(rèn)支持,如果設(shè)置為false,將關(guān)閉支持注解的依賴注入,需要通過<context:annotation-config/>開啟。
默認(rèn)情況下將自動(dòng)過濾@Component、@ManagedBean、@Named注解的類并將其注冊(cè)為Spring管理Bean,可以通過在<context:component-scan>標(biāo)簽中指定自定義過濾器將過濾到匹配條件的類注冊(cè)為Spring管理Bean,具體定義方式如下:
?
<context:include-filter type="aspectj" expression=""/> <context:exclude-filter type="regex" expression=""/>
- <context:include-filter> : 表示過濾到的類將被注冊(cè)為Spring管理Bean;
- <context:exclude-filter> : 表示過濾到的類將不被注冊(cè)為Spring管理Bean,它比<context:include-filter>具有更高優(yōu)先級(jí);
- type : 表示過濾器類型,目前支持注解類型、類類型、正則表達(dá)式、aspectj表達(dá)式過濾器,當(dāng)然也可以自定義自己的過濾器,實(shí)現(xiàn)org.springframework.core.type.filter.TypeFilter即可;
- expression : 表示過濾器表達(dá)式。
?
一般情況下沒必要進(jìn)行自定義過濾,如果需要請(qǐng)參考如下示例:
?
1、cn.javass.spring.chapter12.TestBean14自動(dòng)注冊(cè)為Spring管理Bean:
?
<context:include-filter type="assignable" expression="cn.javass.spring.chapter12.TestBean14"/>
?
2、把所有注解為org.aspectj.lang.annotation.Aspect自動(dòng)注冊(cè)為Spring管理Bean:
?
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
?
3、將把匹配到正則表達(dá)式“cn\.javass\.spring\.chapter12\.TestBean2*”排除,不注冊(cè)為Spring管理Bean:
?
<context:exclude-filter type="regex" expression="cn\.javass\.spring\.chapter12\.TestBean2*"/>
?
?
4、將把匹配到aspectj表達(dá)式“cn.javass.spring.chapter12.TestBean3*”排除,不注冊(cè)為Spring管理Bean:
?
<context:exclude-filter type="aspectj" expression="cn.javass.spring.chapter12.TestBean3*"/>
?
具體使用就要看項(xiàng)目需要了,如果以上都不滿足需要請(qǐng)考慮使用自定義過濾器。
?
?
12.3.6? 提供更多的配置元數(shù)據(jù)
1 、@Lazy : 定義Bean將延遲初始化,使用方式如下:
?
@Component("component") @Lazy(true) public class TestCompoment { …… }
? ? 使用@Lazy注解指定Bean需要延遲初始化。
?
?
2、 @DependsOn : 定義Bean初始化及銷毀時(shí)的順序,使用方式如下:
?
@Component("component") @DependsOn({"managedBean"}) public class TestCompoment { …… }
?
?
3 、@Scope :定義Bean作用域,默認(rèn)單例,使用方式如下:
?
@Component("component") @Scope("singleton") public class TestCompoment { …… }
?
?
?
4 、@Qualifier : 指定限定描述符,對(duì)應(yīng)于基于XML配置中的<qualifier>標(biāo)簽,使用方式如下:
?
@Component("component") @Qualifier("component") public class TestCompoment { …… }
? ? 可以使用復(fù)雜的擴(kuò)展,如@Mysql等等。
?
?
5 、@Primary : 自動(dòng)裝配時(shí)當(dāng)出現(xiàn)多個(gè)Bean候選者時(shí),被注解為@Primary的Bean將作為首選者,否則將拋出異常,使用方式如下:
?
@Component("component") @Primary public class TestCompoment { …… }
?
?
?
原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明私塾在線【http://sishuok.com/forum/blogPost/list/2547.html】
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
