Spring注解/解析

作者: suxin1932 | 来源:发表于2019-07-31 14:33 被阅读0次
    注解 功能分类 功能 Spring Version 备注
    @Order Bean加载顺序控制 数值越小表示优先级越高.默认优先级最低. 2.0 -
    @DependsOn Bean加载顺序控制 可使得依赖的Bean如果未被初始化会被优先初始化 3.0 -

    1.注解

    1.1 @Import

    可以普通类导入到 IOC 容器中。提供与 xml 中 <import/> 等效的功能, 
    允许去导入 @Configuration类, ImportSelector 和 ImportBeanDefinitionRegistrar 的具体实现, 
    以及常规组件类 (这一句划重点)。
    类似于AnnotationConfigApplicationContext.register(java.lang.Class<?>...) 这种操作。
    
    如果需要导入XML或其他非 @Configuration bean定义资源,请改用 @ImportResource 注解。
    
    想要让一个普通类接受 Spring 容器管理,有以下方法
    >> 使用@Configuration 注解标注类, 同时@Bean 注解该类的方法上
    >> 使用 @Controller @Service @Repository @Component 注解标注该类,然后再使用 @ComponentScan 扫描包
    >> @Import 方法
    
    #应用
    1.Enable..., 如: 
    @EnableAspectJAutoProxy --> @Import(AspectJAutoProxyRegistrar.class)
    @EnableEurekaServer --> @Import(EurekaServerMarkerConfiguration.class)
    @EnableAutoConfiguration --> @Import(AutoConfigurationImportSelector.class)
    @EnableDubbo --> @EnableDubboConfig --> @Import(DubboConfigConfigurationRegistrar.class)
    
    @Import用法示例结构图.png
    ///////////////////// 方法1: 常规bean //////////////////////
    package com.zy.springframework.annotation;
    
    import lombok.Data;
    @Data
    public class ImportAnno01 {
        private Long timeout = 100L;
        private String uuid = "1";
    }
    
    ///////////////////// 方法2: 实现 ImportSelector //////////////////////
    package com.zy.springframework.annotation.importselector;
    
    import lombok.Data;
    @Data
    public class ImportAnno02 {
        private Long timeout = 200L;
        private String uuid = "2";
    }
    
    package com.zy.springframework.annotation.importselector;
    
    import org.springframework.context.annotation.ImportSelector;
    import org.springframework.core.type.AnnotationMetadata;
    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[] {"com.zy.springframework.annotation.importselector.ImportAnno02"};
        }
    }
    
    ///////////////////// 方法3: 实现 ImportBeanDefinitionRegistrar //////////////////////
    package com.zy.springframework.annotation.register;
    
    import lombok.Data;
    @Data
    public class ImportAnno03 {
        private Long timeout = 300L;
        private String uuid = "3";
    }
    
    package com.zy.springframework.annotation.register;
    
    import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    import org.springframework.beans.factory.support.RootBeanDefinition;
    import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
    import org.springframework.core.type.AnnotationMetadata;
    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            registry.registerBeanDefinition("importAnno03", new RootBeanDefinition(ImportAnno03.class));
        }
    }
    
    /////////////////////////////////// 核心步骤: 导入bean ///////////////////////////////////
    package com.zy.springframework.annotation;
    
    import com.zy.springframework.annotation.importselector.MyImportSelector;
    import com.zy.springframework.annotation.register.MyImportBeanDefinitionRegistrar;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    @Configuration
    @Import({ImportAnno01.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    public class ImportAnnoConfig {
    }
    
    /////////////////////////////////// 测试 ///////////////////////////////////
    package com.zy.springframework.annotation;
    
    import com.zy.springframework.annotation.importselector.ImportAnno02;
    import com.zy.springframework.annotation.register.ImportAnno03;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import java.util.Arrays;
    public class ImportsTest {
        public static void main(String[] args) {
            ApplicationContext ctx = new AnnotationConfigApplicationContext(ImportAnnoConfig.class);
            String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
            System.out.println("---------------");
            System.out.println(Arrays.toString(beanDefinitionNames));
            System.out.println("---------------");
            System.out.println(ctx.getBean("com.zy.springframework.annotation.ImportAnno01", ImportAnno01.class).getUuid());
            System.out.println(ctx.getBean("com.zy.springframework.annotation.importselector.ImportAnno02", ImportAnno02.class).getUuid());
            System.out.println(ctx.getBean("importAnno03", ImportAnno03.class).getUuid());
        }
    }
    

    1.2 @ImportResource

    导入XML或其他非 @Configuration bean定义资源
    
    package com.zy.springframework.annotation.importresource;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.ImportResource;
    @Configuration
    @ImportResource(locations = {"classpath*:META-INF/applicationContext-global.xml"})
    public class ImportResourceConfig { }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!-- 扫包 -->
        <context:component-scan base-package="com.zy"/>
        <!-- 这里是对 aop 的支持, 此处不必配置 -->
        <aop:aspectj-autoproxy/>
        <!-- MyImportSelector 复用了上文的 class -->
        <bean name="myImportSelector2" class="com.zy.springframework.annotation.importselector.MyImportSelector"/>
    </beans>
    
    @Test
    public void fn01() {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(ImportResourceConfig.class);
        System.out.println(ctx.getBean("myImportSelector2", MyImportSelector.class));
    }
    

    1.3 @PropertySource

    package com.zy.eureka;
    
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.stereotype.Component;
    
    /**
     * 若想读取 classpath 下自定义的 properties 配置文件:
     *  方法1
     *  @PropertySource + @ConfigurationProperties
     */
    @PropertySource(value = {"classpath:propertySourceBean.properties"})
    @Component
    @ConfigurationProperties(prefix = "model")
    @Data
    public class PropertySourceBean {
        private String name;
        private Integer age;
        private String gender;
    
        /**
         * 若想读取 classpath 下自定义的 properties 配置文件:
         *  方法2
         *  @PropertySource + @Value
         */
        @Data
        @PropertySource(value = {"classpath:propertySourceBean.properties"})
        @Component
        public static class PropertyBean {
            @Value("${model.name}")
            private String name;
            @Value("${model.age}")
            private Integer age;
            @Value("${model.gender}")
            private String gender;
        }
    }
    

    propertySourceBean.properties

    model.name=tom
    model.age=30
    model.gender=male
    

    1.4 @ConditionalOn xxx

    https://www.jianshu.com/p/d2bb0a96daf6 (@ConditionalOn xxx查看这里)

    1.5 装配Bean的注解

    1.5.1 @Component, @Repository, @Service, @Controller

    1)@Component
    可以使用此注解描述 Spring 中的 Bean,但它是一个泛化的概念,
    仅仅表示一个组件(Bean),并且可以作用在任何层次。
    使用时只需将该注解标注在相应类上即可。
    
    2)@Repository
    用于将数据访问层(DAO层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
    
    3)@Service
    通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
    
    4)@Controller
    通常作用在控制层,用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。
    
    其实源码中, 后三个注解上层即为@Component注解, 仅仅是为了更好的语义区分而已.
    

    1.5.2 @Autowired, @Resource, @Qualifier

    1)@Autowired
    用于对Bean的属性变量,属性的Set方法及构造函数进行标注,配合对应的注解处理器完成Bean的自动配置工作。
    默认按照Bean的类型进行装配。
    
    2)@Resource  ---> 这货是jdk的注解!!!!!
    其作用与 Autowired 一样。
    其区别在于@Autowired默认按照Bean类型装配,而@Resource默认按照Bean实例名称进行装配。
    @Resource 中有两个重要属性:name 和 type。
    Spring 将 name 属性解析为 Bean 实例名称,type 属性解析为 Bean 实例类型。
    如果指定 name 属性,则按实例名称进行装配;
    如果指定 type 属性,则按 Bean 类型进行装配。
    如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;
    如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
    
    3)@Qualifier
    与@Autowired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,
    Bean的实例名称由@Qualifier注解的参数指定。 如:
    '
    @Autowired
    @Qualifier("importExecutor")
    private ExecutorService tipsExecutor;
    
    <bean id="importExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean">
    ...
    </bean>
    '
    

    1.5.3 @Configuration, @Bean

    @Configuration需要与@Bean注解配合使用, 共同完成bean的IOC/DI工作.
    @Configuration注解上也有@Component注解, spring容器启动时, 
    会扫描其中加了@Bean注解的方法, 从而实例化bean.
    详细过程可参见作者IOC分析一文.
    

    1.5.3.1 @Bean

    @Bean注解的方法存在参数,参数取值逻辑:
    会从Spring容器中根据类型注入(若有多个类型的的话则根据方法名按名称注入,没有找到就会报错)
    
    package com.zy.eureka.config;
    
    import io.netty.util.concurrent.DefaultThreadFactory;
    import lombok.Builder;
    import lombok.Data;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import java.io.Serializable;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.RejectedExecutionHandler;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    @Configuration
    public class ConfigurationBean {
    
        /**
         * 如果 @Bean 注解对应的方法中有 参数, 则:
         * @param executorConfig 该参数一定要提前注入到 Spring 中, 被 BeanFactory 管理
         * @return
         */
        @Bean
        public ExecutorService executorService(ExecutorConfig executorConfig) {
            return new ThreadPoolExecutor(executorConfig.getCorePoolSize(),
                    executorConfig.getMaximumPoolSize(),
                    executorConfig.getKeepAliveTime(),
                    executorConfig.getUnit(),
                    executorConfig.getWorkQueue(),
                    executorConfig.getThreadFactory(),
                    executorConfig.getHandler());
        }
    
        /**
         * 如果把此处的 方法注释掉, 启动将会报错
         * Parameter 0 of method executorService in
         * com.zy.eureka.config.ConfigurationBean
         * required a bean of type  ---> 这里的 说的这个 bean, 需要被 Spring 管理
         * 'com.zy.eureka.config.ConfigurationBean$ExecutorConfigBean'
         * that could not be found.
         * @return
         */
        @Bean
        public ExecutorConfig executorConfigBean() {
            return ExecutorConfig.builder()
                    .corePoolSize(8)
                    .maximumPoolSize(8)
                    .keepAliveTime(0L)
                    .unit(TimeUnit.SECONDS)
                    .workQueue(new LinkedBlockingQueue<>(10240))
                    .threadFactory(new DefaultThreadFactory("executorServiceThreadPool"))
                    .handler(new ThreadPoolExecutor.DiscardOldestPolicy())
                    .build();
        }
    
        @Data
        @Builder
        private static class ExecutorConfig implements Serializable {
            private static final long serialVersionUID = 1621561831662994994L;
            private int corePoolSize;
            private int maximumPoolSize;
            private long keepAliveTime;
            private TimeUnit unit;
            private BlockingQueue<Runnable> workQueue;
            private ThreadFactory threadFactory;
            private RejectedExecutionHandler handler;
        }
    }
    

    --------------------------------注解解析分析开始-------------------------------

    Spring中常见注解工具类.png
    #Spring中注解解析相关class
    1.org.springframework.core.annotation.AnnotationAttributes
    2.org.springframework.core.type.AnnotationMetadata
    3.org.springframework.core.annotation.AnnotatedElementUtils
    4.org.springframework.core.annotation.AnnotationUtils
    5.org.springframework.beans.annotation.AnnotationBeanUtils
    6.org.springframework.context.annotation.AnnotationConfigUtils
    7.org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils
    

    https://blog.csdn.net/f641385712/article/details/88767877

    --------------------------------注解解析分析结束-------------------------------

    参考资源
    https://www.jianshu.com/p/56d4cadbe5c9 (@Import注解)
    http://c.biancheng.net/view/4265.html

    相关文章

      网友评论

        本文标题:Spring注解/解析

        本文链接:https://www.haomeiwen.com/subject/pezzrctx.html