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