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

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