Spring 注解编程IOC
-
Bean
注册 -
Bean
依赖注入 -
Bean
生命周期 - 资源属性赋值
Bean 注册
注册Bean
的常用注解有@Component
、@Service
、@Controller
、@Repository
,通过扫描包的方式对这些注解进行解析注册Bean
。
注解
ApplicationContext
:AnnotationConfigApplicationContext
常用注解
@Configuration
声明Bean Difinition
的配置文件,相当于一个xml文件
@Bean
声明Bean
的组件
1 |
|
相当于xml bean内容
1 |
|
bean的名称默认为方法名称,也可以通过
@Bean(value="person")
或者@Bean("person")
进行指定
@ComponentScan
指定扫描路径
1 |
|
相当于xml component-scan
1 |
|
@ComponentScans
多个扫描路径,值为ComponentScan
的数组,1.8以后可以用多个@ComponentScan
代替此注解
@Scope
指定Bean
的作用域,默认为singleton
singleton
org.springframework.beans.factory.config.ConfigurableBeanFactory#SCOPE_SINGLETON
prototype
org.springframework.beans.factory.config.ConfigurableBeanFactory#SCOPE_PROTOTYPE
request
org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
session
org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
1 |
|
相当于xml中bean中scope
属性
1 |
|
@Lazy
懒加载,针对singleton
Bean
进行懒加载,默认情况下单实例Bean直接加载
1 |
|
相当于xml中bean的lazy-init
属性
1 |
|
@DependsOn
依赖关系注解
1 |
|
相当于xml中bean的depends-on
属性
1 |
|
@Order
Bean
的排序,或者说是优先级,两个接口org.springframework.core.Ordered
以及org.springframework.core.PriorityOrdered
,主要使用优先级的内容
org.springframework.beans.factory.config.BeanPostProcessor
org.springframework.http.converter.HttpMessageConverter
@Conditional
条件装配Bean
实现
org.springframework.context.annotation.Condition
接口1
2
3
4
5
6
7public class CustomCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// true 进行装配,false不进行装配
return false;
}
}Bean
上配置@Conditional(Condition.class)
1
2
3
4
5
6
7
8
9@Configuration
public class CustomConfig {
@Conditional(CustomCondition.class)
@Bean
public Person person() {
return new Person();
}
}
当matches方法返回true的时候进行注册当前@Bean
,否则不注册。该注解也可以放到配置类上,matches方法返回true的时候进行注册当前配置类,否侧不注册。
@Profile
环境注解,底层使用的是@Conditional
@Import
快捷注册Bean
,默认名称为类的全路径
直接导入类
1
2
3
4@Configuration
@Import(Person.class)
public class CustomConfig {
}导入实现
org.springframework.context.annotation.ImportSelector
类1
2
3
4
5
6
7public class CustomImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{Person.class.getName()};
}
}1
2
3
4@Configuration
@Import(CustomImportSelector.class)
public class CustomConfig {
}导入实现
org.springframework.context.annotation.ImportBeanDefinitionRegistrar
类1
2
3
4
5
6
7
8
9public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
// 自行注册BeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
registry.registerBeanDefinition("person",beanDefinition);
}
}1
2
3
4@Configuration
@Import(CustomImportBeanDefinitionRegistrar.class)
public class CustomConfig {
}
@ImportResource
导入资源xml文件
资源文件名称
spring/application-spring.xml
1 |
|
1 |
|
常见问题
@Configuration
、其他注解与@Bean
结合使用有什么不同
答:@Configuration
注解使用的其实也是一个Bean
,但本身是BeanFatory
,是经过CGLIB
进行增强的Bean
,其他注解(@Component
、@Service
、@Controller
、@Repository
)使用的就是一个简单的Bean
Bean 依赖注入
常用注解
@Autowired
Spring自带的自动注入,注解的属性required
来支持是否必须要进行依赖注入。根据以下规则进行查找进行注入
- 根据类型查找,只查询一个直接返回
- 根据名称查找
1 |
|
可以结合以下注解进行使用
@Qualifier
指定名称进行依赖注入
1
2
3
4
5
6
7@Service
public class PersonService {
@Autowired
@Qualifier("personMapper")
private PersonMapper personMapper;
}@Primary
指定优先进行依赖注入
1
2
3
4
5
6@Service
public class PersonService {
@Autowired
private PersonMapper personMapper;
}1
2
3
4
5
6
7
8
9
10@Configuration
@ComponentScan({"top.felixfly.spring.annotation.mapper","top.felixfly.spring.annotation.service"})
public class CustomConfig {
// 优先注入
@Bean("personMapper2")
@Primary
public PersonMapper personMapper(){
return new PersonMapper();
}
}
只有一个有参构造器时,
@Autowired
可以省略,可以自动进行注入
@Resource
Java规范(JSR250)的注解,默认按照属性的名称进行依赖查找匹配,也可以用属性name
进行强制指定,但不支持与@Primary
注解结合使用和required
是否必须要进行依赖注入
1 |
|
@Inject
Java规范的注解(JSR330),功能与@Autowired
一样,但不支持required
是否必须要进行依赖注入。需要引入javax.inject
1 |
|
1 |
|
注入方式
构造器注入
1 |
|
Setter
方法注入
1 |
|
Aware
接口
自定义组件注入Spring底层的组件,比如ApplicationContext
,这些Aware
接口一般通过Processor
进行处理。ApplicationContextAwareProcessor
处理EnvironmentAware
、EmbeddedValueResolverAware
、ResourceLoaderAware
、ApplicationEventPublisherAware
、MessageSourceAware
、ApplicationContextAware
ApplicationContextAware |
ApplicationContext |
---|---|
ApplicationEventPublisherAware |
ApplicationContext 事件发布器 |
BeanClassLoaderAware |
类加载器 |
BeanFactoryAware |
Bean 工厂 |
BeanNameAware |
Bean 名称 |
BootstrapContextAware |
BootstrapContext |
MessageSourceAware |
国际化管理 |
NotificationPublisherAware |
Spring JMX 通知发布器 |
ResourceLoaderAware |
资源加载器 |
EmbeddedValueResolverAware |
@Value 解析器 |
EnvironmentAware |
环境变量 |
常见问题
循环依赖的问题
答:循环依赖的产生,BeanA依赖BeanB,BeanB依赖BeanC,而BeanC又依赖于BeanA,这时候就会产生循环依赖的问题,单例Bean中通过构造器注入会产生循环依赖的问题,会产生BeanCurrentlyInCreationException
,通过Setter
方法注入不会产生异常,可以解决循环依赖问题。原型@Bean通过Setter
方法注入依然会产生BeanCurrentlyInCreationException
,没办法解决循环依赖问题。
Bean 生命周期
Bean
的生命周期包含实例化–>初始化–>销毁,单实例Bean
实例化在容器创建的时候进行实例化以及初始化,销毁在容器关闭的时候进行调用;多实例Bean
在获取Bean
的时候进行实例化以及初始化,销毁需要自行进行调用。
初始化和销毁常用方法
@Bean
指定initMethod
和destroyMethod
1
2
3
4
5
6
7
8@Configuration
public class CustomConfig {
@Bean(initMethod = "init",destroyMethod = "destroy")
public Person person(){
return new Person();
}
}相当于xml中配置
init-method
和destroy-method
属性1
2
3<beans>
<bean class="top.felixfly.spring.annotation.entity.Person" init-method="init" destroy-method="destroy"/>
</beans>实现
InitializingBean
和DisposableBean
1
2
3
4
5
6
7
8
9
10
11
12
13public class Person implements InitializingBean, DisposableBean {
public Person() {
}
@Override
public void afterPropertiesSet() throws Exception {
}
@Override
public void destroy() throws Exception {
}
}使用
@PostConstruct
和@PreDestroy
注解使用
InitDestroyAnnotationBeanPostProcessor
进行解析处理,父类CommonAnnotationBeanPostProcessor
1
2
3
4
5
6
7
8
9
10
11
12
13public class Person {
public Person() {
}
@PostConstruct
public void postConstruct(){
}
@PreDestroy
public void preDestroy(){
}
}
BeanPostProcessor
postProcessBeforeInitialization
初始化之前执行方法postProcessAfterInitialization
初始化之后执行方法
1 |
|
1 |
|
执行方法若是返回null值,后续的BeanPostProcessor
不会进行执行,源代码执行如下:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
1 |
|
常见问题
生命周期执行方法顺序
答:初始化方法执行顺序
@PostConstruct
- 实现
InitializingBean
接口的方法 @Bean
指定initMethod
销毁方法执行顺序
@PreDestroy
- 实现
DisposableBean
接口的方法 @Bean
指定destroyMethod
Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:
- Methods annotated with
@PostConstruct
afterPropertiesSet()
as defined by theInitializingBean
callback interface- A custom configured
init()
methodDestroy methods are called in the same order:
- Methods annotated with
@PreDestroy
destroy()
as defined by theDisposableBean
callback interface- A custom configured
destroy()
method
资源属性赋值
常用注解
@Value
属性进行赋值,可以有如下三种写法
直接赋值
1
2
3
4
5public class Person {
@Value("张三")
private String name;
}SpEL
表达式 #{}1
2
3
4
5public class Person {
@Value("#{20-2}")
private String age;
}${} 文件属性赋值(通常在环境变量
Enviroment
中),要配合@PropertySource
使用1
2
3
4
5public class Person {
@Value("${person.age}")
private String age;
}
@PropertySource
引入配置文件,配置文件下根路径下person.properties
1 |
|
相当于xml中的context:property-placeholder
1 |
|
@PropertySources
多个配置文件引入,值为PropertySource
的数组,1.8以后可以用多个@PropertySource
代替此注解
常见问题
配置文件属性乱码
答:注解@PropertySource
通过属性encoding
进行配置文件编码,该配置在4.3版本引入;xml配置文件中通过属性file-encoding
配置文件编码