spring 基于java的配置
2019獨角獸企業重金招聘Python工程師標準>>>
7.10 Classpath scanning and managed componets
文檔地址: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-classpath-scanning 本章中大部分例子是用xml來指定配置元數據,以生成容器里的每個bean定義.上個部分描述了如何通過資源注解來提供大量的配置元數據.但是,這很多例子中,很多bean定義是在xml文件中完成的,而注解只負責依賴注入.本節描述如何通過掃描路徑來檢測可選組件.候選組件都是一些能匹配一些條件的類或者在容器中注冊了相應的bean定義.這移除了使用xml注冊bean的必要,因此你可用使用注解,AspectJ類型表達,又或者你的自定義攔截條件 來選擇容器中注冊的bean定義.
從spring3.0,spring的java配置項目提供了的很多功能已經是spring核心功能的一部分.這允許你使用java而不是xml文件來定義beans.學習@Configuration,@Bean,@Import,@Dependson注解,并學習如何使用.
7.10.1 @Component and further sterertype annotations
@Repository注解是一個任何能完成repository(也就是DAO)角色或模板的類的標志.使用這些標志可以自動轉譯異常,如Section 20.2.2,"Exception translation";
spring提供了很多固定注解:@Component,@Service,@Controller,@Repository.@Component是一個spring管理組件的基本模板類型.@Repository,@Service,@Controller是對@Componet的特殊化,應用于特定的場合,例如,他們分別在持久化,服務層,表現層中使用.因此,你可以用@Component來標志你的組件,但你最好用@Repository,@Service,@Controller來替換,因為這樣可以使這些類更好的而配合工作操作或者和切面協同.例如,這些模板注解都是切入點的理想目標.spring框架在以后的發布版中@Repository,@Service,@Controller可能會攜帶額外的語法.因此,當你考慮用@Service或@Component來標注你的服務層是,@Service是更好的選擇.同上文所示,@Repository已被當為了一個支持持久層自動異常轉譯的標志.
7.10.2 Meta-annotations (元注解)
很多spring提供的注解可以作為元注解在你的代碼里使用.元注解是指可以在其他注解中使用的注解.例如,上文中提到的@Service注解中就有@Component元注解.
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Component // Spring will see this and treat @Service in the same way as @Component public @interface Service {/ / .... }元注解可以被聚合生成組合注解.例如,spring mvc的@RestController注解就是@Controller和@ResponseBody組合而成的.
另外,組合注解可以重新申明元注解的屬性來允許用戶自定義.當你只打算暴露一部分元注解屬性時這將非常有用.例如,spring的@SessionScope以硬編碼的方式控制scope的名字為session,但扔允許自定義proxyMode的值.
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Scope(WebApplicationContext.SCOPE_SESSION) public @interface SessionScope {/*** Alias for {@link Scope#proxyMode}.* <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.*/@AliasFor(annotation = Scope.class)ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}@SessionScope不申明proxyMode屬性仍可以如下使用
@Service @SessionScope(proxyMode = ScopedProxyMode.INTERFACES) public class SessionScopedUserService implements UserService {// ... }更多細節,請查看spring annotaion programming Model
7.10.3 Automatically detectin classes and registering bean definitions(自動檢測類并注冊bean定義)
spring 可以自動檢測模板類并通過ApplicationContext來注冊相應的bean定義.例如,一下兩個類將會代理以實現自動檢測.
@Service public class SimpleMovieLister {private MovieFinder movieFinder;@Autowiredpublic SimpleMovieLister(MovieFinder movieFinder) {this.movieFinder = movieFinder;}}@Repository public class JpaMovieFinder implements MovieFinder {// implementation elided for clarity }要自動檢測這些類并注冊相應的bean,你需要在你的@Configuration類中添加@ComponentScan注解,@ComponentScan中的basePackages屬性應該是兩個類的共同父包.(另外,你可以制定一個逗號,分號,空白分割的列表來包含每個類的父包);
@Configuration @ComponentScan(basePackages = "org.example") public class AppConfig {... }為了簡化,上面的可以直接使用注解你的value屬性,如 @ComponentScan("org.example")
以下是相應的xml
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="org.example"/></beans>-
context:component-scan的隱式的包含了context:annotation-cofig的功能,所以你在使用context:component-scan時不需要使用context:annotation-config;
-
類路徑包的掃描需要相應的目錄實體在類路徑中真實存在.當你用Ant構建JARS時,要保證你沒有開啟你的文件轉化jar包任務.另外,在一些環境里,依據安全策略類路徑目錄將無法暴露.例如,jdk1.7中單獨的應用.
還有,當你使用component-scan元素時,AutowiredAnnotaionBeanPostProcessor,CommonAnnotationBeanPostProcessor都是隱式包含的.這意味著這兩個組件會自動檢測被一起注冊,不需要在xml里提供任何bean配置元數據.
另,你也可以不注冊AutowiredAnnotaionBeanPostProcessor,CommonAnnotationBeanPostProcessor,這需要你在annotation-config元素中將值設為false;
7.10.4 使用過濾器來自定義掃描
一般而言,用@Component,@Repository,@Service,,@Controller,或其他本身標記了@Component注解的注解才能被檢測為可選組件.但是,你可以簡單的通過使用自定義過濾器來修改并擴展這個行為.將他們作為includeFilters或excludeFilters的參數添加到@ComponentScan注解里.下面的表將描述攔截選項.
攔截器類型
annotaion,assignable,aspectj,regex,custom五種. 下面的例子表明所有的@Repository注解都會被排除,并使用以stub結尾的repository替代.
@Configuration @ComponentScan(basePackages = "org.example",includeFilters = @Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),excludeFilters = @Filter(Repository.class)) public class AppConfig {... }等同于
<beans><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> </beans>@Filter,屬性時type,pattern,默認是annotation;你也可以通過設置@ComponentScan的useDefaultFileters=false或設置<component-scan>元素中的use-default-filters="false"來禁用默認過濾器.而受影響的類是標注了@Componnet,@Repository,@Service,@Controller,或者@Configuration的類.
7.10.5 Defining bean medata within components(在components中定義bean的元數據)
spring 的components也可以向容器提供bean定義.你可以像在@Configuration注解類中一樣使用@Bean注解來定義bean的元數據.下面是一個簡單的例子:
@Component public class FactoryMethodComponent {@Bean@Qualifier("public")public TestBean publicInstance() {return new TestBean("publicInstance");}public void doWork() {// Component method implementation omitted}}這個類是一個spring組件類,在它的doWork()方法里有應用特定的代碼.然,它也提供了一個bean定義,用一個工廠方法來指向方法publicInstance().@Bean注解標記著工廠方法或其他bean定義屬性.例如通過@Qualifier提供的一個qualifier值.其他方法級別的注解可以被@Scope,@Lazy或其他自定義注解等來指定.
- 可以使用@Lazy同@Autowired,@Inject標志懶加載.在本上下文中,它將注入懶加載代理.
自動裝配的字段和方法支持上文已經討論了,另外討論的是對@Bean方法自動裝配的支持:
@Component public class FactoryMethodComponent {private static int i;@Bean@Qualifier("public")public TestBean publicInstance() {return new TestBean("publicInstance");}// use of a custom qualifier and autowiring of method parameters@Beanprotected TestBean protectedInstance(@Qualifier("public") TestBean spouse,@Value("#{privateInstance.age}") String country) {TestBean tb = new TestBean("protectedInstance", 1);tb.setSpouse(spouse);tb.setCountry(country);return tb;}@Beanprivate TestBean privateInstance() {return new TestBean("privateInstance", i++);}@Bean@RequestScopepublic TestBean requestScopedInstance() {return new TestBean("requestScopedInstance", 3);}}上面的例子會自動裝配字符串類型的方法參數country的值為一個名為privateInstance的bean的Age屬性.一個spring表達式語言元素通過#{<expression>}的形式定義了表達式的值.對于@Value注解,一個表達式解析器會會再解析表達文本之前前查看bean的名稱. 在spring的Component里的@Bean方法不同于@Configuration類里的@Bean方法的處理.這個不同在于@Component的類沒有通過CGLIB來攔截方法或屬性的調用.CGLIB代理是通過在@Configueration類中定義了指向其他協作對象的bean的元數據@Bean方法來調用相應的方法或字段;這些方法并沒有通過正常的java語義而是通過容器調用的,為的就是當通過調用@Bean方法來引用其他beans時可以提供正常的生命周期管理和spring的代理.相反的,在一個簡單的@Component類里調用@Bean方法的字段或方法會有正常的java語法,而不是一個特殊的CGLIB處理或其他限制條件.
如果你吧一個@bean的方法宣布為static,這可以允許你在bean未實例化之后調用它們.當你定義了后處理器類時,這會非常有意義.因為這些類會再容器生命周期中很早啟動,這樣會避免在此時觸發容器配置的其他部分.
調用@bean的靜態方法不會被容器攔截,即使當你在@Configuration類里調用.這主要是技術的限制:CGLIB子類只能重寫非靜態的方法.結果,直接調用其他的@Bean方法擁有java標準語法,所以工廠方法自身會返回一個獨立的實例.
java語言中@Bean方法的存在并不會對spring容器里的bean定義造成直接的影響.你可以自由的在你認為合適的非@Configuration類里申明工廠方法,也可以將之設置為靜態方法.但是,在@Configuration類里的常規@Bean方法可能需要重寫,所以 他們不能命名為private或final.
@Bean方法可以在一個指定的組件類或配置類里發現,和java 8 發現組件類和配置類中實現接口申明的默認方法一樣.這就允許在組裝復雜的配置組合時有很大的靈活性.即使通過java8的默認方法使混合繼承成為可能.
最后,記住一個單個的class可能對于同一個bean持有多個混合的@Bean方法,混合工廠方法的安排取決于運行時那些依賴是可獲得.這個算法同其他配置場景里選擇最貪婪的工廠方法和構造器一樣:可適依賴數量最多的種類在構造期間獲取,同容器如何選擇混合@Autowired構造器一樣.
7.10.6 命名自動檢測組件 Naming autodected components
當一個組件作為掃描過程的一部分進行自動檢測時,它的bean的名稱是通過BeanNameGenerator策略來告知掃描器的.默認的,spring任何固定類型注解(@Componnet,@Repository,@Service,@Controller)包含一個那么值,并將它提供給對于的bean定義.
如果一個注解沒有包含value值或其他可檢測的組件(可以被自定義攔截器攔截的bean).默認的bean名稱生成器返回一個小寫字母開頭的非限制的類名稱.例如,如果以下兩個組件被檢測,那么它們的名稱應該是myMovieListener或movieFinderImpl;
@Service("myMovieLister") public class SimpleMovieLister {// ... }@Repository public class MovieFinderImpl implements MovieFinder {// ... }如果你不想依賴默認的bean命名策略,你可以提供一個自定義命名策略.首先,實現BeanNameGenerator接口,并確保它有一個無參構造器.另外,在配置掃描器時提供一個全匹配符的類名稱.
@Configuration @ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class) public class AppConfig {... }或者
<beans><context:component-scan base-package="org.example"name-generator="org.example.MyNameGenerator" /> </beans>首先,思考指定注解的值,因為其他組件可能會引用它.另一方面,當容器進行注入時,名稱自動生成策略總是差強人意的.
7.10.7 Providing a scope for autodetected components(為自動檢測組件提供作用域)
一般而言,spring管理的組件默認和通用的自動檢測組件的作用域一般是單例.但是,有時你需要使用@Scope來定義其他的作用域.使用注解提供作用域的名稱來實現.
@Scope("prototype") @Repostitory public class MovieFinderImpl implements MovieFinder{ }web特定的作用域細節,可查看7.4.5章,Request,session,global session,application,and WebSocket scopes
如果你想使用自定義作用域策略而不是使用基于注解方法,你需要實現ScopeMetadataResolver接口,并保證該實現類有一個無參構造器.另外,在配置掃描器時提供一個類的全路徑名稱.
@Configuration @ComponentScan(basePackages = "org.example", scopeResolver = MyScopeResolver.class) public class AppConfig {... }xml配置方法
<beans><context:component-scan base-package="org.example"scope-resolver="org.example.MyScopeResolver" /> </beans>當你使用特定非單例作用域,它可能需要為作用域里的對象提供代理. 這個原因在"scoped beans as dependencies"一節里已經描述.為實現這個目標,component-scan元素提供了一個scoped-proxy元素,它有三個值:no,interfacce,targerClass.例如,下面的配置將會是標準的JDK動態代理:
@Configuration @ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES) public class AppConfig {... }<beans><context:component-scan base-package="org.example"scoped-proxy="interfaces" /> </beans>7.10.8 通過注解提供匹配符元數據
我們在7.9.4這節里考慮過,'Fine-tuning annotation-based autowiring with qualifier'. 本節的例子說明在你要解決自動注入條件問題時,你可以使用@Qualifier注解或自定義注解來獲得更好的控制.因為這些例子都是基于xml的bean定義,這個通配符元數據通過是通過候選的bean定義使用xml里bean元素的qualifier或meta子元素來定義.當你使用類路徑掃描或組件自動檢測,你需要提供在候選類里通過類級別的注解來提供匹配符元數據.以下三個例子說明了這個技術:
@Component @Qualifier("Action") public class ActionMovieCatalog implements MovieCatalog {// ... }@Component @Genre("Action") public class ActionMovieCatalog implements MovieCatalog {// ... }@Component @Offline public class CachingMovieCatalog implements MovieCatalog {// ... }作為大部分基于xml的可替換項,要記住注解元數據是基于類定義自身的,而使用xml可以為同一類型的不同bean定義提供它們相應的配置元數據.因為注解是類級別的,而xml里的bean則是實例級別的.
轉載于:https://my.oschina.net/u/1590027/blog/751623
總結
以上是生活随笔為你收集整理的spring 基于java的配置的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 代码设置Shape和Selector
- 下一篇: 为什么要清除浮动