spring全家桶

Spring注解/解析

2019-07-31  本文已影响0人  suxin1932
注解 功能分类 功能 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

上一篇下一篇

猜你喜欢

热点阅读