最全的Spring注解详解
@Configuration : 配置类 == 配置文件,告诉Spring这是一个配置类
@ComponentScan(value="com.atguigu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
@ComonentScan value : 指定要扫描的包(这个注解可以定义多个)
excludeFilters = Filter[] : 指定扫描的时候按照什么规则排除那些组件
includeFilters = Filter[] : 指定扫描的时候只需要包含那些组件
useDefaultFilters = false : 表示去掉默认扫描
FilterType.ANNOTATION : 按照注解类型 例如 : Controller.class
FilterType.ASSIGNABLE_TYPE : 按照给定的类型 例如 : UserService.class
FilterType.ASPECTJ : 使用ASPECTJ表达式
FilterType.REGEX : 使用正则指定
FilterType.CUSTOM : 使用自定义规则
自定义规则需要实现TypeFilter接口
public class MyTypeFilter implements TypeFilter {
/**
metadataReader : 读取到的当前正则扫描的类的信息
metadataReaderFactory : 可以获取到其他任何类的信息
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) {
// 获取当前类注解的信息
AnnotationMetadata annotationMetadate = metadataReader.getAnnontationMetadata();
// 获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
// 获取这个类名
String className = classMetadata.getClassName();
// 自定义匹配规则
if(className.contains("er")) {
return true;
}
return false;
}
}
@ComponentScans(
value {
@ComponentScan(value="com.atguigu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
}, useDefaultFilters = false)
}
) : 里面可以定义多个@ComponentScan
@Bean : 给容器中注册一个Bean;类型为返回值的类型,id默认是用方法名作为id
@Scope("") : 表示这个对象或者这个bean的创建作用域范围(调整作用域).
prototype : 多实例的,ioc容器时并不会调用方法创建对象放在容器中.每次获取的时候才会调用方法创建对象.
singleton : 单实例的(默认值),ioc容器启动会调用方法创建对象放到ioc容器中.以后每次获取就是直接从容器(map.get())中拿.
request : 同一次请求创建一个实例
session : 同一个session创建一个实例
@Lazy : 懒加载
单实例bean,默认在容器启动的时候创建对象.
懒加载: 容器启动不创建对象,第一次调用(获取)Bean创建对象,并初始化.
@Conditional({Condition}) : 按照一定的条件进行判断,满足条件给容器中注册bean(可以放在@Bean上,或者类上)
例如 :
//放在类上统一设置
// 类中组件统一设置,满足当前条件,这个类中配置的所有bean注册才能生效.
@Conditional({WindowsCondition.class})
@Configuration
//实现接口Condition
public class LinuxCondition implements Condition {
/**
*/
public boolean matchs(CondititContext context, AnnotatedTypeMetadata metadada) {
// 是否linux系统
// 1. 能获取到ioc使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2.获取类加载器
ClassLoader classLoader = context.getClassLoader();
// 3.获取当前环境信息
Environment environment = context.getEnvironment();
// 4.获取到bean定义的注册类(可以判断容器中的bean注册情况,也可以给容器中注册bean)
BeanDefinitionRegistry registry = context.getRegistry();
// 判断容器中是否包含bean
boolean definition = registry.containsBeanDefinition("persion");
String property = environment.getProperty("os.name");
if (property.contains("linux")){
return true;
}
return false;
}
}
// 获取bean名称
String[] namesForType = applicatinContext.getBeanNamsForType();
// 动态获取环境变量的值,获取容器运行环境例如 : windows,liunx
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// 获取操作系统的名称
String property = environment.getProperty("os.name");
给容器中注册组件 :
1 : 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
2 : @Bean[导入的第三方包里面的组件]
3 : @Import[快速给容器中导入一个组件]
1) : @Import(要导入到容器中的组件);容器中就会自动注册这个组件,id默认是组件的全类名(也可以导入多个组件)
2) : ImportSelector : 返回需要导入的组件的全类名数组.
3) : ImportBeanDefinitionRegistrar : 手动注册Bean到容器中
4 : 使用Spring提供的FactoryBean(工厂Bean)
1) : 默认获取到的是工厂bean调用getObject创建的对象
2) : 要获取工厂Bean本身,我们需要给id前面加一个&
&colorFactoryBean
@Import(要导入到容器中的组件 例如 : Color.class) : 方在类上,导入组件,容器中就会自动注册这个组件,id默认是组件的全类名(也可以导入多个组件)
(2) ImportSelector : 返回需要导入的组件的全类名数组.
例如 :
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
// 返回值,就是导入到容器中的组件全类名
// AnnotationMetadata : 当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 方法不要返回null值
return new String[];
}
}
@Import({Color.class,Red.class,MyImportSelector.class})
(3) ImportBeanDefinitionRegistrar : 手动注册Bean到容器中
例如 :
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
// AnnotationMetadata : 当前类的注解信息
// BeanDefinitionRegistry : BeanDefinitionRegistry注册类;
// 把所有需要添加到容器中的bean : 调用 BeanDefinitionRegistry.registryBeanDefinition手工注册进来
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
// 通过bean名称,判断bean是否在容器中
booean definition = registry.containsBeanDefinition("red");
boolean definition1 = registry.containsBeanDefinition("blue");
if (definition && definition1) {
// 指定bean定义信息 : (Bean的类型,Bean...)
RootBeanDefinition bean = new RootBeanDefinition(RainBow.class);
// 注册一个Bean,指定Bean名
registry.registryBeanDefinition("rainBow", bean);
}
}
}
4 : 例子 :
// 创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
return new Color();
}
public Class<?> getObjectType() {
return Color.class;
}
//是单例?
//true : 这个bean是单例,在容器中保存一份
//false : 多实例,每次获取都会创建一个新的bean
@Override
public boolean isSingleton() {
return false
}
}
@Bean
public ColorFactoryBean getBean() {
return new ColorFactoryBean();
}
public void test() {
//工厂Bean获取的是调用getObject创建的对象;实际上获取的是Color对象
Object bean2 = applicatinContext.getBean("colorFactoryBean");
//这个是获取的ColorFactoryBean对象,因为在FactoryBean接口中定义了一个字符串,表示以&开头的就是获取实现FactoryBean接口的对象
Object bean3 = applicatinContext.getBean("&colorFactoryBean");
}
Bean的生命周期
bean创建 -- 初始化 -- 销毁的过程
容器管理bean的生命周期 :
我们可以自定义初始化和销毁方法;容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁的方法
构造(对象创建)
单实例 : 在容器启动的时候创建对象
多实例 : 在每次获取的时候创建对象
BeanPostProcessor.postProcessBeforeInitialization
初始化 :
对象创建完成,并赋值好,调用初始化方法...
BeanPostProcessor.postProcessInitialization
销毁 :
单实例 : 容器关闭的时候
多实例 : 容器不会管理者bean,容器不会调用销毁方法.
遍历得到容器中所有的BeanPostProcessor : 挨个执行beforeInitialization,一旦返回null,跳出for循环,不会执行后面的BeanPostProcessor.postProcessBeforeInitialization
BeanPostProcessor的原理
populateBean(beanName, mdb, instanceWrapper) : 给bean进行属性赋值
initializeBean
{
appliyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)
invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName)
}
1) : 指定初始化和销毁方法:
通过@Bean指定init-method和destory-method;
2) : 通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑)
3) : 可以使用JSR250;
@PostConstruct : 在bean创建完成并且属性赋值完成;来执行初始化方法(在对象创建并赋值之后调用)
@PreDestroy : 在容器销毁bean之前通知我们进行清理工作.
例如 :
public class Dog{
public Dog() {
System.out.println("");
}
//对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("11");
}
//容器移除对象之前
@PreDestroy
public void detory(){
}
}
4) : BeanPostProcessor[interface] : bean后置处理器;
在bean初始化前后进行一些处理工作;
postProcessBeforeInitialization : 在初始化之前工作
postProcessInitialization : 在初始化之后工作
Spring底层对BeanPostProcessor的使用 :
bean赋值,注入其他组件,@Autowired,生命周期注解功能。@Async, xxx BeanPostProcessor;
@Value : 给属性赋值。
1. 基本数值 例如 : @Value("111")
2. 可以写SpEL. 例如 : @Value("#{20-2}")
3. 可以写${},取出配置文件中的值(在运行环境变量里面的值) 例如 : @Value("${name}")
@PropertySource读取外部配置文件中的k/v保存到运行的环境变量中;加载完外部的配置文件以后使用${}取出配置文件的值。
例如 :
AnnotationConfigApplicationContext applicatinContext = new AnnontationConfigApplicationContext();
pringBeans(applicationContext);
Person person = (Person)applicationContext.getBean("person");
ConfigurableEnvironment environment = applicatinContext.getEnvironment();
// 这是根路径下的.properties配置文件中的k/v值
Sting property = environment.getProperty("person.nickName);
applicatinContext.close();
自动装配 :
Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值;
1) . 默认优先按照类型去容器中找对应的组件 : applicationContext.getBean(BookDao.class);找到就赋值
2) . 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
3) . @Qualifier("bookDao") : 使用@Qualifier指定需要装配的组件的id,而不是使用属性名。
4) . 自动装配默认一定要将属性赋值好,没有就会报错。(可以通过更改属性值.例如 : @Autowired(required=false);这样就在没有这个组件时,不会进行自动装配)
5) . @Primary : 让Spring进行自动装配的时候,默认使用首选的bean;
也可以继续使用@Qualifier指定需要装配的bean的名字。
applicatinContext.getBean("bookDao");
BookService{
@Autowired
BookDao bookDao
}
(2):Spring还支持使用@Resource(JSR250)和@Inject(JSR330)【Java规范的注解】
@Resource
可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;
没有能支持@Primary功能没有支持 @Autowired(reqiured = false);
@Inject
需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;
@Autowired : Spring定义的; @Resouce和@Inject都是java规范。
Spring的@Autowired的底层使用AutowiredAnnotationBeanPostProcessor : 解析完成自动装配功能。
(3):@Autowired : 构造器,参数,方法,属性
@Componetnt : 默认加载ioc容器中的组件,容器启动会调用无参构造器创建对象,再进行初始化赋值等操作
1): 标注在方法位置 : @Bean + 方法参数;参数从容器中获取;默认不写@Autowired效果是一样的,都能自动装配
2): 标注在构造器上 : 如果组件只有一个有参构造器,这个有参构造器的@Autowired可以省略,参数位置的组件换是可以自动从容中获取.
3):标注在参数位置
@Bean标注的方法创建对象的时候,方法参数的值从容器中获取。
(4) : 自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware
把Spring底层一些组件注入到自定义的Bean中;
xxxAware: 功能使用xxxProcessor;
ApplicationContextAware ==> ApplicationContextAwareProcessor;
@Profile : 指定组件在哪个环境的情况下才能被注册到容器中。
1) : 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境。
2) : 写在配置上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效。
激活方式 :
(1) : 使用命令行动态参数 : 在虚拟机参数位置加载 -Dspring.profiles.active=test
(2) :代码的方式激活某种环境。
(3) : 没有标注环境标识的bean在任何环境下都是加载的。
例如 :
AnnotationConfigApplicationContext applicatinContext = new AnnontationConfigApplicationContext();
//1。创建一个applicationContext
//2. 设置需要激活的环境
applicatinContext.getEnvironment().setActiveProfiles("dev");
//3.注册主配置类
applicatinContext.registry(MainConfigOrProfile.class);
//4.启动刷新容器
applicatinContext.refresh();
最全的Spring注解详解的更多相关文章
- Spring注解详解
概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...
- 【转】Spring注解详解
http://blog.csdn.net/xyh820/article/details/7303330/ 概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类 ...
- Spring注解详解@Repository、@Component、@Service 和 @Constroller
概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...
- Spring @注解详解(转)
1.@controller 控制器(注入服务) 2.@service 服务(注入dao) 3.@repository dao(实现dao访问) 4.@component (把普通pojo实例化到spr ...
- Spring注解详解(转)
概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...
- Spring注解详解(转)
概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作.如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO ...
- [Spring学习笔记 3 ] spring 注解详解,完全注解,常用注解
.xml使用注解 xml 用来定义bean的信息,注解用来配置依赖信息 ) 在配置文件中配置bean )在javaBean中用注解来指定依赖注入 )在配置文件中开启注解扫描 @Resource标签 j ...
- Spring IoC 公共注解详解
前言 本系列全部基于 Spring 5.2.2.BUILD-SNAPSHOT 版本.因为 Spring 整个体系太过于庞大,所以只会进行关键部分的源码解析. 什么是公共注解?公共注解就是常见的Java ...
- Spring Boot 2.x基础教程:进程内缓存的使用与Cache注解详解
随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一.Spring 3开始提供了强大的基于注解的缓 ...
随机推荐
- ACM学习历程——HDU3333 Turing Tree(线段树 && 离线操作)
Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems abou ...
- forEach、for in 和for of的区别
forEach 不能使用break return 结束并退出循环 for in 和 for of 可以使用break return: for in遍历的是数组的索引(即键名),而for of遍历的是 ...
- tomcat集群--单tomcat多实例
1.解压apache-tomcat-7.0.75.tar.gz到任意目录 /data/tomcat-4X 2.建立tomcat多实例目录,这个tomcat-4X运行4X应用的两个实例4002,4004 ...
- Mesos的quorum配置引发的问题
Mesos安装完毕后,发现agent无法和master关联(通过WebUI的agent页面无法看到agent信息),查看日志显示: Elected as the leading master! sta ...
- Jmeter提取响应数据的结果保存到本地的一个文件
原文地址: https://www.cnblogs.com/whitewasher/p/9504728.html 当做性能压测时,可能会需要把响应数据的一些字段统计出来.这里简单介绍一下. 1.首先把 ...
- Java创建线程的三种方法比较
一般有三种方法,Thread,Runnable,Callable. Runnable和Callable的区别 (1)Callable规定的方法是call(),Runnable规定的方法是run(). ...
- 如何使用Git命令将项目从github或者服务器上克隆下来
在本地新建一个文件夹,作为本地仓库,如“demo”.单击右键git Bush here,打开git,输入命令: cd /c/Users/Administrator/Desktop/demo 然后按回 ...
- pysam操作sam文件
pysam模块 因为要分析sam文件中序列的情况,因此要对reads进行细分,所以之前想用数据库将sam文件信息存储,然后用sql语句进行分类.后来发现很麻烦,pysam就是一个高效读取存储在SAM ...
- linux多线程加解锁
1.动态方式使用互斥量,该类型的互斥量在定义时不进行初始化,需要在使用之前初始化,使用结束销毁 1.1.定义一个锁变量: pthread_mutex_t g_mutex_Msg; 1. ...
- 2019计蒜之道初赛3 D. 阿里巴巴协助征战SARS(困难)(大数取余+欧拉降幂)
阿里巴巴协助征战SARS(困难) 33.29% 1000ms 262144K 目前,SARS 病毒的研究在世界范围内进行,经科学家研究发现,该病毒及其变种的 DNA 的一条单链中,胞嘧啶.腺嘧啶均 ...