Spring中@Import的各种用法以及ImportAware接口
@Import 注解
@Import
注解提供了和XML中<import/>
元素等价的功能,实现导入的一个或多个配置类。@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<EnableTransactionManagement> {
@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<EnableAsync> {
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.<Integer>getNumber("order"));
return bpp;
}
}
在ProxyAsyncConfiguration
的asyncAdvisor
方法中需要获取到@EnableAsync
上的一些设置值,例如:this.enableAsync.getBoolean("proxyTargetClass")
,this.enableAsync.<Integer>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学习一下。
欢迎关注公众号,大家一起学习成长。
Spring中@Import的各种用法以及ImportAware接口的更多相关文章
- Spring中JdbcTemplate的基础用法
Spring中JdbcTemplate的基础用法 1.在DAO中使用JdbcTemplate 一般都是在DAO类中使用JdbcTimplate,在XML配置文件中配置好后,可以在DAO中注入即可. 在 ...
- Spring中@Import注解的使用
Spring中@Import注解的使用 @Import注解算是SpringBoot自动配置原理中一个很重要的注解 认识@Import注解 先看一下源码 @Target(ElementType.TYPE ...
- spring 中配置sessionFactory及用法
spring 中配置sessionFactory及用法 方法一: 1.在Spring的applicationContext.xml中配置bean <!-- 启用注解注入 --> ...
- 全面解析Spring中@ModelAttribute注解的用法
本文不再更新,可能存在内容过时的情况,实时更新请移步我的新博客:全面解析Spring中@ModelAttribute注解的用法: @ModelAttribute注解用于将方法的参数或方法的返回值绑定到 ...
- EnableAutoConfiguration注解 Spring中@Import注解的作用和使用
EnableAutoConfiguration注解 http://www.51gjie.com/javaweb/1046.html springboot@EnableAutoConfiguration ...
- spring中实现基于注解实现动态的接口限流防刷
本文将介绍在spring项目中自定义注解,借助redis实现接口的限流 自定义注解类 import java.lang.annotation.ElementType; import java.lang ...
- css中import与link用法区别
方式:引入CSS的方法有两种,一种是@import,一种是link @import url('地址');//注意,这种方式可以放在页面也可以放在css文件中<link href="地址 ...
- Spring 中的几个常用的钩子接口
1.Aware接口 Awear 这个单词的意思是知道的,所以可以猜想以Awear 结尾的接口意思可以把他知道的东西告诉我们.常用的Awear接口有 ApplicationContextAware和 B ...
- spring中scope(作用越)理解
今天总结了一下spring中作用域scope的用法.在spring中作用域通过配置文件形式的用法如下. <bean id="role" class="spring. ...
随机推荐
- Webpack安装配置及打包详细过程
引言 前端经过漫长的发展,涌现出了很多实践方法来处理复杂的工作流程,让开发变得更加简便,其中,模块化可以使复杂的程序细化成为各个小的文件,而webpack并不强制你使用某种模块化方案,而是通过兼容所有 ...
- 面试必问的MySQL锁与事务隔离级别
之前多篇文章从mysql的底层结构分析.sql语句的分析器以及sql从优化底层分析, 还有工作中常用的sql优化小知识点.面试各大互联网公司必问的mysql锁和事务隔离级别,这篇文章给你打神助攻,一飞 ...
- Go语言标准库之flag
Go语言内置的flag包实现了命令行参数的解析,flag包使得开发命令行工具更为简单. os.Args 如果你只是简单的想要获取命令行参数,可以像下面的代码示例一样使用os.Args来获取命令行参数. ...
- SSM框架——详细整合教程
SSM框架——详细整合教程(Spring+SpringMVC+MyBatis) 1.基本概念 1.1.Spring Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Jav ...
- Servlet控制台输出乱码问题
在如下图的配置页面: 在此行添加编码格式:
- TestNG(七)组测试
package com.course.testng.groups; import org.testng.annotations.AfterGroups; import org.testng.annot ...
- 一个vue练手的小项目
编程路上的菜鸟一枚 : 最近接触了vue 然后写了一个练手的项目 使用vue-cli脚手架来搭建了的项目 技术: vue2 + vue-router + ES6 + axios 框架有 mint- ...
- C# 10分钟入门基于WebOffice实现在线编辑文档,实时保存到服务器(所有office,兼容WPS)
今天,他来了(weboffice在线编辑文档). 上次写了一个在线预览的博,当然,效果并不是太理想,但是紧急解决了当时的问题. 后来,小编重新查找资料,求助大牛,终于使用新的方式替换了之前的low方法 ...
- 写论文与PPT汇报时matlab图片的背景透明处理
不少同学在使用Word写论文时,将matlab生成的图保存为jpg格式,然后粘贴到文档中.word背景为纯白色,jpg图的缺点没有显示,实际上会存在很大白边,以及放大后不清晰的问题,很影响PPT展示和 ...
- 第六届蓝桥杯java b组第8题
乐羊羊饮料厂正在举办一次促销优惠活动.乐羊羊C型饮料,凭3个瓶盖可以再换一瓶C型饮料,并且可以一直循环下去,但不允许赊账. 请你计算一下,如果小明不浪费瓶盖,尽量地参加活动,那么,对于他初始买入的n瓶 ...