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的配置相关推荐

  1. Spring 基于 Java 的配置 - 如何不用Beans.xml照样描述bean之间的依赖关系

    看个具体的例子:首先是配置类,该类的作用相当于Spring常规依赖维护里的Beans.xml: import org.springframework.context.annotation.*; @Co ...

  2. Spring 基于 Java 的配置

    @Configuration 和 @Bean 注解 这两个注解一般配合使用. 带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源.@B ...

  3. spring java配置_Spring基于java的配置

    我们之前都了解过spring基于xml的配置,我们也可以通过配置类来完成基于xml的配置,我们会在下面以一个例子来讲述一下Spring基于java的配置. 首先第一步准备工作: 1)创建一个Dog类 ...

  4. Spring 基于Java配置

    到目前为止,您已经了解了如何配置使用XML配置文件的Spring bean.如果习惯使用XML配置,那么会说,这不是真的需要学习如何进行基于Java的配置,因为你要使用的配置或者可达到相同的结果. 基 ...

  5. 零配置 之Spring基于Java类定义Bean配置元数据

    转载自  [第十二章]零配置 之 12.4 基于Java类定义Bean配置元数据 --跟我学spring3 12.4  基于Java类定义Bean配置元数据 12.4.1  概述 基于Java类定义B ...

  6. spring java配置_Spring:使基于Java的配置更加优雅

    spring java配置 大家好,我很久没有写新文章了. 积累了很多资料,需要在不久的将来在我的博客中发布. 但是现在我想谈谈Spring MVC应用程序配置. 确切地说,我想谈谈基于Java的Sp ...

  7. Spring:使基于Java的配置更加优雅

    大家好,我很久没有写新文章了. 积累了很多资料,需要在不久的将来在我的博客中发布. 但是现在我想谈谈Spring MVC应用程序配置. 确切地说,我想谈谈基于Java的Spring配置. 尽管在3.0 ...

  8. Spring MVC:使用基于Java的配置创建一个简单的Controller

    这是我博客上与Spring MVC相关的第一篇文章. 开端总是令人兴奋的,因此我将尽量简洁明了. Spring MVC允许以最方便,直接和快速的方式创建Web应用程序. 开始使用这项技术意味着需要Sp ...

  9. 使用Spring 3.1和基于Java的配置构建RESTful Web服务,第2部分

    1.概述 本文介绍了如何在Spring中设置REST –控制器和HTTP响应代码,有效负载编组配置和内容协商. 2.在Spring了解REST Spring框架支持两种创建RESTful服务的方式: ...

最新文章

  1. layui 表格内容写temple函数_layui表格-template模板的三种用法
  2. Momenta造“飞轮式”自动驾驶,4年内实现Robotaxi单车盈利,路线图首次公布
  3. mysql 定时同步数据_MySQL数据同步之otter
  4. ML.NET Cookbook:(3)如何从CSV加载包含多个列的数据?
  5. linux格式化ext4分区工具,linux学习笔记-磁盘分区、格式化与挂载
  6. 在Linux下锁住键盘和鼠标而不锁屏
  7. gdb java,调用gdb来调试java程序
  8. 免费 | 开源操作系统年度盛会最新日程曝光,邀您一同开启烧脑模式!
  9. [Python Study Notes]pandas.DataFrame.plot()函数绘图
  10. Python编程:从入门到实践 - matplotlib篇 - plot scatter
  11. Microsoft Store微软应用商店打不开怎么办?完美解决方案!
  12. OpenStack部署(图文详解)
  13. 电子签核系统的设计(一) - Requirements / Design
  14. 【Android】自己动手做个扫雷游戏
  15. [luogu2294] [HNOI2005]狡猾的商人
  16. C# Obsolete、Contional等等一些特性的介绍
  17. 自己做QQ–后台搭建
  18. vsd格式文件如何打开?
  19. QGC地面站二次开发(一)地面站介绍以及软件框架(1)地面站使用介绍和接口介绍
  20. 39.文本颜色设置SetTextColor、SetBkColor、SetCharacterExtra、GetSysColor、InvalidateRect

热门文章

  1. CMDB功能分析与实现方案
  2. 面试--跨域--cors
  3. 谷歌Gboard输入法新增“无痕模式”:仅在Chrome隐身窗口中适用
  4. JS向后台传递json数组对象
  5. 开启AngularJS 1.X的学习之路(1)
  6. Socket编程:之双机通信
  7. Oracle Enterprises Manager 12C安装
  8. 提供程序未返回 ProviderManifestToken 字符串
  9. SQL 查询数据库中包含指定字符串的相关表和相关记录
  10. shell中source与sh区别