zoukankan      html  css  js  c++  java
  • Spring 高级话题

    1. Spring Aware

    1.1 基础知识

    Spring 的依赖注入,即所有的 Bean 对 Spring 容器的存在是没有意识的。就说明 Bean 之间的耦合度很低。
    但在实际项目中,要想用到 Spring 容器中所提供的资源就需要使 Bean 意识到容器 Spring 的存在,才能调用 Spring 所提供的资源,这就是所谓的 Spring Aware。若使用了 Spring Aware ,你的 Bean 将会和 Spring 框架耦合。
    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 容器的所有服务。

    2. 多线程

    2.1 基础知识

    Spring 通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用 ThreadPoolTaskExecutor 可实现一个基于线程池的 TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过 @EnbaleAsync 开启对异步任务的支持,并通过在实际执行的 Bean 的方法中使用 @Async 注解来声明其是一个异步任务。

    3. 计划任务

    3.1 基础知识

    首先通过在配置类中注解 @EnableScheduling 来开启对计划任务的支持,然后在要执行计划任务的方法上注解 @Scheduled ,声明这是一个计划任务。

    4. 条件注解 @Conditional

    4.1 基础知识

    @Conditional 根据满足某一个特定条件创建一个特定的 Bean。比方说,当某一个 jar 包在一个类路径下的时候,自动配置一个或多个 Bean;或者只有某个 Bean 被创建才会创建另外一个 Bean。总的来说,就是根据特定条件来控制 Bean 的创建行为,这样我们可以利用这个特性来进行一些自动配置。

    5. 组合注解与元注解

    5.1 基础知识

    元注解 其实就是可以注解到别的注解上的注解,被注解的注解称之为 组合注解,组合注解具备注解其上的元注解的功能。Spring 的很多注解都可以作为元注解,而且 Spring 本身已经有很多组合注解,如 @Configuration 就是一个组合 @Component 注解,表明这个类其实也是个 Bean。

    6. @Enable* 注解的工作原理

    6.1 基础知识

    @Enable* 的例子有:@EnableAspectJAutoProxy 开启对 AspectJ 自动代理的支持;@EnableAsync 开启异步方法的支持;@EnableScheduling 开启计划任务的支持。

    通过观察这些 @Enable* 注解的源码,我们发向所有的注解都有一个 @Import 注解,@Import 是用来导入配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的 Bean。这些导入的配置方式主要分为以下三种类型。
    (1)直接导入配置类

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

    直接导入配置类 SchedulingConfiguraiton,这个类注解了 @Configuration,且注册了一个 scheduledAnnotationProcessor 的 Bean,源码如下:

    @Configuration
    @Role(2)
    public class SchedulingConfiguration {
        public SchedulingConfiguration() {
        }
    
        @Bean(
            name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
        )
        @Role(2)
        public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
            return new ScheduledAnnotationBeanPostProcessor();
        }
    }
    

    (2)依据条件选择配置类

    @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 方法,在此方法内进行事先条件判断。此例中,若 adviceMode 为 PROXY,则返回 ProxyAsyncConfiguration 这个配置类;若 activeMode 为 ASPECTJ,则返回 AspectJAsyncConfiguration 配置类,源码如下:

    public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
        private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME = "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
    
        public AsyncConfigurationSelector() {
        }
    
        @Nullable
        public String[] selectImports(AdviceMode adviceMode) {
            switch(adviceMode) {
            case PROXY:
                return new String[]{ProxyAsyncConfiguration.class.getName()};
            case ASPECTJ:
                return new String[]{"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"};
            default:
                return null;
            }
        }
    }
    

    (3)动态注册 Bean

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({AspectJAutoProxyRegistrar.class})
    public @interface EnableAspectJAutoProxy {
        boolean proxyTargetClass() default false;
    
        boolean exposeProxy() default false;
    }
    

    AspectJAutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,它的作用是在运行时自动添加 Bean 到已有的配置类,通过重写方法:

    registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
    

    其中,AnnotationMetadata 参数用来获得当前配置类上的注解;BeanDefinitionRegistry 参数来注册 Bean。源码如下:

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        AspectJAutoProxyRegistrar() {
        }
    
        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);
                }
            }
    
        }
    }
    
  • 相关阅读:
    JVM StackOverflowError vs. OutOfMemoryError
    db2 command line notes
    my emacs configuration
    repackage android application
    file -i haha.csv
    QualType in clang
    STM in Clojure
    32bit / 64bit co-exist Linux, ld-linux.so, linux-gate.so.1 etc
    hash tree
    K-S Test
  • 原文地址:https://www.cnblogs.com/john1015/p/13840495.html
Copyright © 2011-2022 走看看