博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring 基于java的配置
阅读量:5950 次
发布时间:2019-06-19

本文共 8455 字,大约阅读时间需要 28 分钟。

hot3.png

7.10 Classpath scanning and managed componets

文档地址: 本章中大部分例子是用xml来指定配置元数据,以生成容器里的每个bean定义.上个部分描述了如何通过资源注解来提供大量的配置元数据.但是,这很多例子中,很多bean定义是在xml文件中完成的,而注解只负责依赖注入.本节描述如何通过扫描路径来检测可选组件.候选组件都是一些能匹配一些条件的类或者在容器中注册了相应的bean定义.这移除了使用xml注册bean的必要,因此你可用使用注解,AspectJ类型表达,又或者你的自定义拦截条件 来选择容器中注册的bean定义.

从spring3.0,spring的java配置项目提供了的很多功能已经是spring核心功能的一部分.这允许你使用java而不是xml文件来定义beans.学习@Configuration,,,@Dependson注解,并学习如何使用.

7.10.1 and further sterertype annotations

@Repository注解是一个任何能完成repository(也就是DAO)角色或模板的类的标志.使用这些标志可以自动转译异常,如;

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 @Componentpublic @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}.     * 

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 {    // ...}

更多细节,请查看

7.10.3 Automatically detectin classes and registering bean definitions(自动检测类并注册bean定义)

spring 可以自动检测模板类并通过ApplicationContext来注册相应的bean定义.例如,一下两个类将会代理以实现自动检测.

@Servicepublic class SimpleMovieLister {    private MovieFinder movieFinder;    @Autowired    public SimpleMovieLister(MovieFinder movieFinder) {        this.movieFinder = movieFinder;    }}@Repositorypublic 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

  • 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,,.

拦截器类型

拦截器类型

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 {    ...}

等同于

@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定义.你可以像在@:

@Componentpublic class FactoryMethodComponent {    @Bean    @Qualifier("public")    public TestBean publicInstance() {        return new TestBean("publicInstance");    }    public void doWork() {        // Component method implementation omitted    }}

这个类是一个spring组件类,在它的doWork()方法里有应用特定的代码.然,它也提供了一个bean定义,用一个工厂方法来指向方法publicInstance().@@Scope,@Lazy或其他自定义注解等来指定.

  • 可以使用@Lazy同@Autowired,@Inject标志懒加载.在本上下文中,它将注入懒加载代理.

自动装配的字段和方法支持上文已经讨论了,另外讨论的是对@Bean方法自动装配的支持:

@Componentpublic 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    @Bean    protected 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;    }    @Bean    private TestBean privateInstance() {        return new TestBean("privateInstance", i++);    }    @Bean    @RequestScope    public TestBean requestScopedInstance() {        return new TestBean("requestScopedInstance", 3);    }}

上面的例子会自动装配字符串类型的方法参数country的值为一个名为privateInstance的bean的Age属性.一个spring表达式语言元素通过#{<expression>}的形式定义了表达式的值.对于@Value注解,一个表达式解析器会会再解析表达文本之前前查看bean的名称. 在spring的Component里的@Bean方法不同于@@Component的类没有通过CGLIB来拦截方法或属性的调用.CGLIB代理是通过在@Configueration类中定义了指向其他协作对象的bean的元数据@Bean方法来调用相应的方法或字段;这些方法并没有通过正常的java语义而是通过容器调用的,,在一个简单的@Component类里调用@Bean方法的字段或方法会有正常的java语法,而不是一个特殊的CGLIB处理或其他限制条件.

如果你吧一个@bean的方法宣布为static,这可以允许你在bean未实例化之后调用它们.当你定义了后处理器类时,这会非常有意义.因为这些类会再容器生命周期中很早启动,这样会避免在此时触发容器配置的其他部分.

调用@bean的静态方法不会被容器拦截,:CGLIB子类只能重写非静态的方法.结果,直接调用其他的@Bean方法拥有java标准语法,所以工厂方法自身会返回一个独立的实例.

@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 {    // ...}@Repositorypublic class MovieFinderImpl implements MovieFinder {    // ...}

如果你不想依赖默认的bean命名策略,你可以提供一个自定义命名策略.首先,实现BeanNameGenerator接口,并确保它有一个无参构造器.另外,在配置扫描器时提供一个全匹配符的类名称.

@Configuration@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)public class AppConfig {    ...}

或者

首先,思考指定注解的值,因为其他组件可能会引用它.另一方面,当容器进行注入时,名称自动生成策略总是差强人意的.

7.10.7 Providing a scope for autodetected components(为自动检测组件提供作用域)

一般而言,spring管理的组件默认和通用的自动检测组件的作用域一般是单例.但是,.

@Scope("prototype")@Repostitorypublic 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配置方法

当你使用特定非单例作用域,它可能需要为作用域里的对象提供代理. 这个原因在一节里已经描述.为实现这个目标,component-scan元素提供了一个scoped-proxy元素,它有三个值:no,interfacce,targerClass.例如,下面的配置将会是标准的JDK动态代理:

@Configuration@ComponentScan(basePackages = "org.example", scopedProxy = ScopedProxyMode.INTERFACES)public class AppConfig {    ...}

7.10.8 通过注解提供匹配符元数据

我们在7.9.4这节里考虑过,. 本节的例子说明在你要解决自动注入条件问题时,,这个通配符元数据通过是通过候选的bean定义使用xml里bean元素的qualifier或meta子元素来定义.当你使用类路径扫描或组件自动检测,你需要提供在候选类里通过类级别的注解来提供匹配符元数据.以下三个例子说明了这个技术:

@Component@Qualifier("Action")public class ActionMovieCatalog implements MovieCatalog {    // ...}@Component@Genre("Action")public class ActionMovieCatalog implements MovieCatalog {    // ...}@Component@Offlinepublic class CachingMovieCatalog implements MovieCatalog {    // ...}

作为大部分基于xml的可替换项,要记住注解元数据是基于类定义自身的,而使用xml可以为同一类型的不同bean定义提供它们相应的配置元数据.因为注解是类级别的,而xml里的bean则是实例级别的.

转载于:https://my.oschina.net/u/1590027/blog/751623

你可能感兴趣的文章
poj_1442 Treap
查看>>
renameTo()方法的用法
查看>>
Java25
查看>>
Delphi BLE 控件
查看>>
Bucket不为空,请检查该Bucket是否包含未删除的Object或者未成功的Multipart碎片
查看>>
Linux mysql
查看>>
产品配件删除,内容保存
查看>>
install 命令用法详解
查看>>
探索性测试学习分享
查看>>
[技术分享] 融云开发案例核心代码分享
查看>>
Enterprise Solution 进销存管理软件 C/S架构,支持64位系统 物流,资金流,信息流全面集成...
查看>>
http://www.cnblogs.com/ITtangtang/archive/2012/05/21/2511749.html
查看>>
Struts2中获取HttpServletRequest,HttpSession等的几种方式
查看>>
【Python五篇慢慢弹】快速上手学python
查看>>
c++ string类型转换为char *类型
查看>>
maven 入门
查看>>
Spring框架学习[IoC容器高级特性]
查看>>
Microsoft.Web.RedisSessionStateProvider 运行异常问题
查看>>
cocos2dx 3.x(让精灵随着重力感应的方向移动而移动)
查看>>
源码安装php时出现configure: error: xml2-config not found. Please check your libxml2 installation...
查看>>