Spring Framework#@Enable*详解

发博词

@Enable*的原理其实是根据此注解的各个配置往Spring IOC容器中注册一系列的Bean。在IOC中注册Bean,Spring为我们提供了两种方式,一个是@Configuration注解某个类,一个是实现ImportBeanDefinitionRegistrar接口,直接在容器中添加、删除某个Bean。Spring还为我们提供了一个ImportSelector接口,用于同时应用多个@Configuration注解的类或者实现了ImportBeanDefinitionRegistrar接口的类。

@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();

}

查看JavaDoc可以知道,@Import接受一个Class类型的参数,这个Class可以是一个@Configuration注解的配置用的Class,可以是一个ImportBeanDefinitionRegistrar的接口的实现,可以是ImportSelector接口的实现。
通过查看Spring生态中已有的EnableXXX的实现可以发现,@Import注解引入的类的最终目的都是引导Spring在IOC容器中创建一系列的bean。

@Configuration

@Configuration注解过的Class里会使用@Bean注解直接定义各种Bean。例子:@EnableLoadTimeWeaving

ImportBeanDefinitionRegistrar

ImportBeanDefinitionRegistrar接口的实现中可以在registerBeanDefinitions方法中往容器中注入Bean。例子:@EnableAspectJAutoProxy。在ImportBeanDefinitionRegistrar接口中,可以使用

public interface ImportBeanDefinitionRegistrar {

	/**
	 * Register bean definitions as necessary based on the given annotation metadata of
	 * the importing {@code @Configuration} class.
	 * <p>Note that {@link BeanDefinitionRegistryPostProcessor} types may <em>not</em> be
	 * registered here, due to lifecycle constraints related to {@code @Configuration}
	 * class processing.
	 * @param importingClassMetadata annotation metadata of the importing class
	 * @param registry current bean definition registry
	 */
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

}

各个Spring的ApplicationContext都实现了BeanDefinitionRegistry接口用于管理IOC容器的Bean的注册移除等操作。
@Configuration和ImportBeanDefinitionRegistrar相比发现的一点区别是ImportBeanDefinitionRegistrar不仅可以增量添加Bean,还可以动态删除某个Bean,ImportBeanDefinitionRegistrar这种方式应该是更灵活,功能更强大一些。

ImportSelector

public interface ImportSelector {

	/**
	 * Select and return the names of which class(es) should be imported based on
	 * the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
	 */
	String[] selectImports(AnnotationMetadata importingClassMetadata);

}

ImportSelector接口的selectImports接口用于返回一个@Configuration注解的类的数组或者一个实现了ImportBeanDefinitionRegistrar接口的数组,暂时还没发现Spring的EnableXXX的实现中出现混用的情况;由于返回的数组是具体的类的全路径字符串,所以猜测混用也是可以的。有时间在测试下。感兴趣的同学可以先测试下,看看混用行不行,欢迎测试结果留言。
ImportSelector接口的selectImports方法返回ImportBeanDefinitionRegistrar的例子:@EnableConfigurationProperties
ImportSelector接口的selectImports方法返回@Configuration注解的类的例子:@EnableAsync

总结

刚开始的时候,@Enable* 风格的注解和@Configuration注解过的类,一直分不清他们的关系。其实他们是互相依赖的,@Enable* 的注解实现上需要有一个@Import注解,这个@Import注解可以引入一个或者多个@Configuration注解过的类。而一个Configuration可以被@Enable*注解继续注解。

@Configuration
@ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class })
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = false)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true)
	public static class JdkDynamicAutoProxyConfiguration {

	}

	@Configuration
	@EnableAspectJAutoProxy(proxyTargetClass = true)
	@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false)
	public static class CglibAutoProxyConfiguration {

	}

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

	/**
	 * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
	 * to standard Java interface-based proxies. The default is {@code false}.
	 */
	boolean proxyTargetClass() default false;

	/**
	 * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
	 * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
	 * Off by default, i.e. no guarantees that {@code AopContext} access will work.
	 * @since 4.3.1
	 */
	boolean exposeProxy() default false;

}

而且@Enable注解本身也可以被另一个@Enable注解。

@Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value={java.lang.annotation.ElementType.TYPE})
@Documented
@Import({WebSecurityConfiguration.class,ObjectPostProcessorConfiguration.class})
@EnableGlobalAuthentication
public @interface EnableWebSecurity {

    /**
     * Controls debugging support for Spring Security. Default is false.
     * @return if true, enables debug support with Spring Security
     */
    boolean debug() default false;
}

Spring 在处理这块时已经想到了各种有意义的可能的组合,使用起来还是相当灵活方便的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
目前(截至2021年),Spring Framework 的最新版本是 5.x 系列,尚未发布 Spring Framework 6.x 版本。因此,无法提供关于 Spring Framework 6.x 的具体区别。以下是 Spring Framework 5.x 与之前版本的一些主要区别: 1. 响应式编程支持:Spring Framework 5 引入了对响应式编程的支持,通过 Reactor 框架和 Reactive Streams API 实现响应式流处理。这使得开发人员能够构建高性能、高吞吐量的异步和非阻塞应用程序,以更好地处理并发请求和处理大量数据流。 2. Java 8+ 特性支持:Spring Framework 5 开始强烈依赖于 Java 8+ 版本的特性,例如 Lambda 表达式、Stream API、新的日期和时间 API 等。通过利用这些特性,可以编写更简洁、更具表现力的代码,并提升开发效率。 3. WebFlux 模块:Spring Framework 5 引入了 WebFlux 模块,提供了基于反应式编程的 Web 开发框架。WebFlux 支持使用注解或函数式编程风格来创建异步、非阻塞的 Web 应用程序,并提供了对响应式 HTTP 客户端的支持。 4. Kotlin 支持:Spring Framework 5 开始对 Kotlin 编程语言提供了更好的支持。Kotlin 是一种现代、表达力强的 JVM 语言,与 Spring Framework 集成得非常紧密,可以更轻松地编写类型安全、简洁的 Spring 应用程序。 5. 模块化:Spring Framework 5 通过将核心容器模块进行细分和模块化,使得开发人员可以根据需要选择和引入所需的模块,从而减少了对不必要功能的依赖。这样可以提高应用程序的性能和开发效率。 需要注意的是,Spring Framework 是一个活跃发展的开源框架,新版本的发布可能会引入更多的功能和改进。因此,为了了解最新版本的 Spring Framework,请查阅官方文档或访问 Spring 官方网站。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈振阳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值