javascript
Spring-基于注解的配置[01定义Bean+扫描Bean]
- 概述
- 使用注解定義Bean
- 掃描注解定義的Bean
- 使用步驟
- 掃描特定的類 resource-pattern
- 實例
- include-filter exclude-filter過濾子元素的使用
- 支持多種類型的過濾表達式
- 實例
- use-default-filters屬性
- 實例
概述
前幾篇博文中主要講述了基于XML的配置。
不管是XML還是注解,他們都是在表達Bean定義的載體,其實質都是為Spring容器提供Bean定義的信息,在表現形式上都是將XML定義的內容通過類注解進行描述。
基于注解的配置方式,在Spring2.0引入,Spring2.5完善,Spring4.0得到了進一步的增強。
我們知道,Spring容器成功啟動的三大要件分別是:
如果采用XML的配置,則Bean的定義信息和Bean的實現類本身是分離的。
而如果采用基于注解的配置方式,則Bean的定義信息通過Bean實現類上標注的注解實現。
使用注解定義Bean
在另外一篇博客中:Spring-Spring MVC + Spring JDBC + Spring Transaction + Maven 構建web登錄模塊
以案例來說明:
// 通過Spring注解定義一個DAO(這里略微改動了下,使用@Component ,更合適的是@Repository,僅僅是為了演示) @Component public class UserDao {.......}使用@Component注解在UserDao類聲明處對類進行標注,它可以被Spring容器識別,Spring容器自動將POJO轉換為容器管理的Bean。
它和下面的XML配置是等效的
<bean id="userDao" class="com.xgj.dao.UserDao">使用注解的方式,默認生成的beanId為類名的首字母小寫,也可指定其id,如:@Service("xgjService")
除了@Component注解外,Spring還提供了3個功能基本和@Component等效的注解,分別用于對DAO、Service和Web層的Controller進行注解
- @Repository用于對DAO實現類進行標注
- @Service用于對Service實現類進行標注
- @Controller用于對Controller實現類進行注解
之所以要在@Component之外提供3個特殊的注解,是為了讓標注類本身的用途清晰化,當然了完全可以用@Component替代這3個特殊的注解, 但是我們推薦使用特定的注解標注特定的Bean,這樣可以明確的了解Bean的真是身份
掃描注解定義的Bean
Spring提供了一個context命名空間,它提供了通過掃描類包以應用注解定義Bean的方式。
如下方式:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- (1)聲明Context命名空間以及Schema文件 (2)掃描類包以及應用注解定義的bean --><context:component-scan base-package="com.xgj.ioc.configuration"/></beans>使用步驟
首先聲明context命名空間和schema文件
然后通過context命名空間的component-scan的base-package屬性指定一個需要掃描的基類包,Spring容器會掃描這個基類包里的所有類,并從類的注解信息中獲取Bean的定義信息。
掃描特定的類 resource-pattern
假設我們希望掃描特定的類,而非基包下所有的類,怎么辦呢?
Spring context命名空間提供了resouce-pattern屬性過濾出特定的類
<!-- 通過resource-pattern使Spring加載特定的Bean --><context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern"resource-pattern="scan/*.class"/>這里設置的基類包為com.xgj.ioc.configuration.resourcePattern,默認情況下resource-pattern屬性的值為 **./*.class,即基類包里所有的類。
如果有設置為scan/*.class,則Spring僅會掃描基類包里scan子包中的類。
實例
通過配置文件指定Spring只加載 scan目錄下的類的注解,測試resource-pattern屬性。
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 通過resource-pattern使Spring加載特定的Bean --><context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern"resource-pattern="scan/*.class"/></beans>scan目錄下的POJO
package com.xgj.ioc.configuration.resourcePattern.scan;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;@Component public class Pilot {@Autowiredprivate Plane plane;public void drivePlane() {plane.fly();} } package com.xgj.ioc.configuration.resourcePattern.scan;import org.springframework.stereotype.Component;@Component public class Plane {private String brand;private String color;private int speed;public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public int getSpeed() {return speed;}public void setSpeed(int speed) {this.speed = speed;}public void introduce() {System.out.println("Plane information【 brand:" + brand + ",color:"+ color + ",speed:" + speed);}public void fly() {System.out.println("Plane begins to fly");} }測試類:
package com.xgj.ioc.configuration.resourcePattern.scan;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class ConfigBeanTest {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/ioc/configuration/resourcePattern/resourcePatternBeans.xml");Pilot pilot = ctx.getBean("pilot", Pilot.class);pilot.drivePlane();Plane plane = ctx.getBean("plane", Plane.class);plane.setBrand("A380");plane.setColor("White");plane.setSpeed(800);plane.introduce();} }NoScan包下的POJO (PilotNoScan、PlaneNoScan)僅僅類名不同(同名的話,默認ID相同,Spring加載會報錯。)
測試類
package com.xgj.ioc.configuration.resourcePattern.noScan;import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class ConfigBeanTest {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/ioc/configuration/resourcePattern/resourcePatternBeans.xml");PilotNoScan pilot = ctx.getBean("pilotNoScan", PilotNoScan.class);pilot.drivePlane();PlaneNoScan plane = ctx.getBean("planeNoScan", PlaneNoScan.class);plane.setBrand("A380-NoScan");plane.setColor("White-NoScan");plane.setSpeed(800);plane.introduce();} }運行scan報下的測試類
運行noScan報下的測試類,報錯
No bean named 'pilotNoScan' available說明,Spring容器并沒有實例化這個類。resource-pattern起了作用。
當我們去掉配置文件中的 resource-pattern="scan/*.class"后,再此運行
可見,Spring容器可以正確加載并實例化Bean
include-filter exclude-filter過濾子元素的使用
通過resource-pattern屬性可以按照資源名稱對基類包中的類進行過濾,如果我們有個需求:僅需過濾基類包中實現了XxxService接口的類或者標注了某個特定注解的類等 ,該怎么辦呢?
Spring的<context:componet-scan>為我們提供了過濾子元素,我們可以輕松的通過其實現上面的需求。
<context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern"resource-pattern="scan/*.class"><context:include-filter type="regex" expression="com\.xgj\.ioc\.configuration\.resourcePattern\.scan.*"/> <context:exclude-filter type="aspectj" expression="com.xgj.ioc.configuration.resourcePattern..*Controller+"/> </context:component-scan>- <context:include-filter>表示要包含的目標類
- <context:exclude-filter>表示要排除的目標類
- 一個<context:component-scan>下可以有多個<context:include-filter>和<context:exclude-filter>元素
支持多種類型的過濾表達式
| annotation | com.xgj.XxxAnnotation | 所有標注了XxxAnnotation的類。該類型采用目標類是否標志了某個注解進行過濾 |
| assignable | com.xgj.XxService | 所有繼承或擴展XXXService的類。該類型采用目標類是否繼承或者擴展了某個特定類進行過濾 |
| aspectj | com.xgj..*Service+ | 所有類名以Service結束的類及繼承或者擴展他們的類。該類型采用AspectJ表達式進行過濾 |
| regex | com.xgj.auto..* | 所有com.xgj.auto類包下的類。該類型采用正則表達式根據目標類的類名進行過濾 |
| custom | com.xgj.XxxTypeFilter | 采用XxxTypeFilter代碼方式實現過濾規則,該類必須實現org.springframework.core.type.TypeFilter接口 |
在所有的過濾類型中,除了custom類型外,aspectj的過濾表達能力是最強的,可以輕易實現其他類型所能表達的過濾規則。
實例
我們先將測試類改下名,保證不重名,否則會拋出如下異常
Annotation-specified bean name 'configBeanTest' for bean class [com.xgj.ioc.configuration.resourcePattern.scan.ConfigBeanTest] conflicts with existing, non-compatible bean definition of same name and class [com.xgj.ioc.configuration.resourcePattern.noScan.ConfigBeanTest]配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!-- 通過resource-pattern使Spring加載特定的Bean <context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern" resource-pattern="scan/*.class"/> --><!-- context:include-filter context:exclude-filter --><context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern"><context:include-filter type="regex"expression="com\.xgj\.ioc\.configuration\.resourcePattern.*" /><context:exclude-filter type="aspectj" expression="com.xgj.ioc.configuration.resourcePattern..*NoScan+"/></context:component-scan></beans>配置文件解析:
<context:include-filter type="regex"expression="com\.xgj\.ioc\.configuration\.resourcePattern.*" />使用<context:include-filter> ,通過regex正則表達式過濾方式,包含com.xgj.configuration.resourcePattern目錄下的所有類,按照項目結果包括scan和noScan子包中的注解類。
<context:exclude-filter type="aspectj" expression="com.xgj.ioc.configuration.resourcePattern..*NoScan+"/>使用<context:exclude-filter>,通過aspectj的過濾方式,排除掉com.xgj.ioc.configuration.resourcePattern包及子包下所有以NoScan+結尾的類,按照項目結構即排除掉noScan子包下的注解類。
其余POJO和測試類同上。
測試scan包下的測試類
測試noScan包下的測試類
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'pilotNoScan' available可見 <context:include-filter> 和 <context:exclude-filter>標簽起了作用。
use-default-filters屬性
use-default-filters屬性默認值為true,表示會對標注@Component、@Controller、@Service、@Reposity的Bean進行掃描。
<context:component-scan>首先根據 exclude-filter列出需要排除的黑名單,然后再根據include-filter流出需要包含的白名單。 但是由于use-default-filters屬性默認值的作用,看下下面的配置片段,不但會對@Controller的bean進行掃描,還會會對@Component、@Service、@Reposity的Bean進行掃描。
<context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern"><context:include-filter type="annotation"expression="org.springframework.stereotype.Controller" /></context:component-scan>換句話講,上面的配置和不加<context:include-filter>的效果是一樣的,如果僅僅想掃描@Controller的bean,必須將use-default-filters屬性設置為false.
如下所示
<context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern" use-default-filters="false"><context:include-filter type="annotation"expression="org.springframework.stereotype.Controller" /> </context:component-scan>實例
配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.xgj.ioc.configuration.resourcePattern" use-default-filters="false"><context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/></context:component-scan></beans>運行測試類 com.xgj.ioc.configuration.resourcePattern.scan.ConfigBeanTest
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'pilot' available如果我們去掉use-default-filters=”false”試下呢?
由此可見 use-default-filters=”false” 起到了只加載或者排除特定注解的功能。
總結
以上是生活随笔為你收集整理的Spring-基于注解的配置[01定义Bean+扫描Bean]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-注入参数详解-[通过uti
- 下一篇: Spring-基于注解的配置[02自动装