第三章
Spring Aware
Spring的依赖注入的最大亮点就是所有的bean对Spring容器的存在是没有任何意识的,即你可以将你的容器替换成别的容器,如Google Guice,这时Bean之间的耦合度很低。
但是在实际项目中,我们不可避免的要使用到Spring容器本身的功能资源,这个时候就需要Bean必须要意识到Spring容器的存在,只有这样才能够调用Spring所提供的资源,这就是所谓的Spring Aware。但是使用了Spring Aware,我们的Bean就会和Spring框架耦合。
Aware接口的子接口如图所示。
其中常用的接口和相关作用如下表所示。
接口名称 | 作用 |
---|---|
BeanNameAware | 获得到容器中Bean的名称 |
BeanFactoryAware | 获得当前bean factory,这样可以调用容器的服务 |
ApplicationContextAware | 获取当前的application context,,这样可以调用容器的服务 |
MessageSourceAware | 获取message source,这样可以获得文本信息 |
ApplicationEventPublisherAware | 应用事件发不起,可以发布事件 |
ResourceLoaderAware | 获得资源加载器,可以加载外部资源文件。 |
Spring Aware的目的是为了让Bean获得Spring容器提供的服务,因为ApplicationContext接口集成了MessageSource、ApplicationEventPublisher、ResourceLoader等接口,所以Bean实现ApplicationContextAware接口就可以获得Spring容器的所有服务,但原则上我们还是用到什么接口,就实现什么接口。
@Enable*注解的工作原理
Spring和Spring Boot提供了很多Enable注解。我们通过简单的@Enable来开启一项功能的支持,从而避免自己配置大量的代码,大大降低使用难度。
通过观察@Enable*的源码,我们发现所有的注解都有一个@Import注解。
@Import注解是用来导入标注@Configuration的类,作用和在Spring XML中的import标签一样,除此之外,该注解还可以用来导入ImportSelector、ImportBeanDefinitionRegistrar的实现类和regular component class。
@Import是用来导入配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的Bean。这些导入的配置方式主要分为以下三种类型。
第一类:直接导入配置类(@Configuration)
eg: @EnableScheduling
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}
直接导入配置类SchedulingConfiguration,这个类注解了@Configuration,且注册了一个ScheduledAnnotationBeanPostProcessor的Bean。
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
第二类:依据条件选择配置类(@ImportSelector)
eg: @EnableAsync
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
AsyncConfigurationSelector通过条件来选择需要导入的配置类,AsyncConfigurationSelector的根接口是ImportSelector,这个接口包含一个selectImports方法,实现类也是通过重写该方法来实现有选择的加载配置类。SpringBoot中的@EnableAutoConfiguration就是这一类。
第三类:动态注册Bean(@ImportBeanDefinitionRegistrar)
eg: @EnableAspectJAutoProxy
@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;
}
AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,该接口的作用是在运行时自动添加Bean到已有的配置类中,通过重写方法:
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
其中AnnotationMetadata参数是用来获得当前配置类上的注解,BeanDefinitionRegistry参数用来注册Bean。