java接口import_Spring中@Import的各种用法以及ImportAware接口

@import 注解

@import注解提供了和xml中元素等价的功能,实现导入的一个或多个配置类。@import即可以在类上使用,也可以作为元注解使用。

@target(elementtype.type)

@retention(retentionpolicy.runtime)

@documented

public @interface import {

/**

* {@link configuration}, {@link importselector}, {@link importbeandefinitionregistrar}

* or regular component classes to import.

*/

class>[] value();

}

注解中只有一个value();。支持导入@configuration标注的配置类,实现importselector接口的类、实现importbeandefinitionregistrar接口的类和普通的@component类。

作为元注解使用

@import可以作为元注解使用,可以在@import的继承上封装一层。我的理解是,这样做不会对外(使用方)暴露我内部的具体实现细节。

举个例子:例如@enableaspectjautoproxy注解。

@import(aspectjautoproxyregistrar.class)

public @interface enableaspectjautoproxy {

@enableaspectjautoproxy就是被@import这个元注解所标志了,我们(程序员)通过使用@enableaspectjautoproxy来开启aspectjautoproxy,而spring底层是通过@import导入相应的配置类来实现的。

导入实现importselector接口的类

先来看一下importselector接口,该接口中只有一个方法:

public interface importselector {

string[] selectimports(annotationmetadata importingclassmetadata);

}

importselector,输入选择器。该接口就是用来根据给定的条件,选择导入哪些配置类。

举个例子:例如@enabletransactionmanagement注解。

@import(transactionmanagementconfigurationselector.class)

public @interface enabletransactionmanagement {

在@enabletransactionmanagement注解中使用了@import(transactionmanagementconfigurationselector.class)注解,其中transactionmanagementconfigurationselector类就是实现了importselector接口。

public class transactionmanagementconfigurationselector extends advicemodeimportselector {

@override

protected string[] selectimports(advicemode advicemode) {

switch (advicemode) {

case proxy:

return new string[] {autoproxyregistrar.class.getname(),

proxytransactionmanagementconfiguration.class.getname()};

case aspectj:

return new string[] {

transactionmanagementconfigutils.transaction_aspect_configuration_class_name};

default:

return null;

}

}

}

方法的内部实现逻辑也很简单,就是根据不同的advicemode导入不同的配置类,来实现事务管理。

导入实现importbeandefinitionregistrar接口的类

importbeandefinitionregistrar接口中也只有一个方法:

public interface importbeandefinitionregistrar {

void registerbeandefinitions(annotationmetadata importingclassmetadata, beandefinitionregistry registry);

}

该接口允许我们根据所给的注解元数据,按需注册额外的beandefinition。

举个例子:例如@enableaspectjautoproxy注解。

@import(aspectjautoproxyregistrar.class)

public @interface enableaspectjautoproxy {

@enableaspectjautoproxy注解引入了aspectjautoproxyregistrar.class类,这个类就是实现了importbeandefinitionregistrar接口。

class aspectjautoproxyregistrar implements importbeandefinitionregistrar {

@override

public void registerbeandefinitions(

annotationmetadata importingclassmetadata, beandefinitionregistry registry) {

aopconfigutils.registeraspectjannotationautoproxycreatorifnecessary(registry);

annotationattributes enableaspectjautoproxy =

annotationconfigutils.attributesfor(importingclassmetadata, enableaspectjautoproxy.class);

if (enableaspectjautoproxy != null) {

if (enableaspectjautoproxy.getboolean("proxytargetclass")) {

aopconfigutils.forceautoproxycreatortouseclassproxying(registry);

}

if (enableaspectjautoproxy.getboolean("exposeproxy")) {

aopconfigutils.forceautoproxycreatortoexposeproxy(registry);

}

}

}

}

registerbeandefinitions中调用了aopconfigutils.registeraspectjannotationautoproxycreatorifnecessary(registry);方法,这个方法就是在往传入的beandefinitionregistry registry中注册beandefinition。注册了beandefinition之后,spring就会去实例化这个bean,从而达到aspectjautoproxy作用。

导入@configuration类

这次@import最常见是使用方法。我们可以拆分配置类,然后在程序中按需导入相应的配置。

举个例子:例如@enableretry注解。使用这个注解可以开启retry功能。

@enableaspectjautoproxy(proxytargetclass = false)

@import(retryconfiguration.class)

public @interface enableretry {

其内部就是导入了retryconfiguration这个配置类。

importaware接口

importaware接口是需要和@import一起使用的。在@import作为元注解使用时,通过@import导入的配置类如果实现了importaware接口就可以获取到导入该配置类接口的数据配置。有点绕,我们直接上代码。

举个例子:@enableasync注解。

@import(asyncconfigurationselector.class)

public @interface enableasync {

//asyncconfigurationselector源码

public class asyncconfigurationselector extends advicemodeimportselector {

private static final string async_execution_aspect_configuration_class_name =

"org.springframework.scheduling.aspectj.aspectjasyncconfiguration";

@override

@nullable

public string[] selectimports(advicemode advicemode) {

switch (advicemode) {

case proxy:

return new string[] {proxyasyncconfiguration.class.getname()};

case aspectj:

return new string[] {async_execution_aspect_configuration_class_name};

default:

return null;

}

}

}

默认情况下使用advicemode为proxy,导入了proxyasyncconfiguration类。

@configuration

@role(beandefinition.role_infrastructure)

public class proxyasyncconfiguration extends abstractasyncconfiguration {

@bean(name = taskmanagementconfigutils.async_annotation_processor_bean_name)

@role(beandefinition.role_infrastructure)

public asyncannotationbeanpostprocessor asyncadvisor() {

assert.notnull(this.enableasync, "@enableasync annotation metadata was not injected");

asyncannotationbeanpostprocessor bpp = new asyncannotationbeanpostprocessor();

class extends annotation> customasyncannotation = this.enableasync.getclass("annotation");

if (customasyncannotation != annotationutils.getdefaultvalue(enableasync.class, "annotation")) {

bpp.setasyncannotationtype(customasyncannotation);

}

if (this.executor != null) {

bpp.setexecutor(this.executor);

}

if (this.exceptionhandler != null) {

bpp.setexceptionhandler(this.exceptionhandler);

}

bpp.setproxytargetclass(this.enableasync.getboolean("proxytargetclass"));

bpp.setorder(this.enableasync.getnumber("order"));

return bpp;

}

}

在proxyasyncconfiguration的asyncadvisor方法中需要获取到@enableasync上的一些设置值,例如:this.enableasync.getboolean("proxytargetclass"),this.enableasync.getnumber("order")。

this.enableasync是其父类abstractasyncconfiguration的属性。abstractasyncconfiguration实现了importaware接口,从而就可以获取到@enableasync上的信息了。

// abstractasyncconfiguration#setimportmetadata 源码

public void setimportmetadata(annotationmetadata importmetadata) {

this.enableasync = annotationattributes.frommap(

importmetadata.getannotationattributes(enableasync.class.getname(), false));

if (this.enableasync == null) {

throw new illegalargumentexception(

"@enableasync is not present on importing class " + importmetadata.getclassname());

}

}

可能这个例子有点复杂的,还有一个稍微简单一点的例子:enableredishttpsession。关于这个,读者可以自己去看一下源码debug学习一下。

欢迎关注公众号,大家一起学习成长。

希望与广大网友互动??

点此进行留言吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值