前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 注解编程IOC

Spring 注解编程IOC

作者头像
Java架构师必看
发布2021-05-14 10:30:58
2560
发布2021-05-14 10:30:58
举报
文章被收录于专栏:Java架构师必看

Spring 注解编程IOC

强烈推介IDEA2020.2破解激活,IntelliJ IDEA 注册码,2020.2 IDEA 激活码

Bean 注册

注册Bean的常用注解有@Component、@Service、@Controller、@Repository,通过扫描包的方式对这些注解进行解析注册Bean。

注解ApplicationContext:AnnotationConfigApplicationContext

常用注解

@Configuration 声明Bean Difinition的配置文件,相当于一个xml文件

@Bean 声明Bean的组件

代码语言:javascript
复制
@Configuration
public class CustomConfig {
    @Bean
    public Person person() {
        return new Person();
    }
}

相当于xml bean内容

代码语言:javascript
复制
<beans>
    <bean id="person" class="top.felixfly.entity.Person"/>
</beans>

bean的名称默认为方法名称,也可以通过@Bean(value=“person”)或者@Bean(“person”)进行指定

@ComponentScan 指定扫描路径

代码语言:javascript
复制
@Configuration
@ComponentScan("top.felixfly.spring.annotation")
public class ScanConfiguration {
}

相当于xml component-scan

代码语言:javascript
复制
<beans>
    <context:component-scan package="top.felixfly.spring.annotation"/>
</beans>

@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
代码语言:javascript
复制
@Configuration
public class CustomConfig {
    @Bean
    @Scope("singleton")
    public Person person() {
        return new Person();
    }
}

相当于xml中bean中scope属性

代码语言:javascript
复制
<beans>
    <bean id="person" class="top.felixfly.entity.Person" scope="singleton"/>
</beans>

@Lazy 懒加载,针对singleton Bean进行懒加载,默认情况下单实例Bean直接加载

代码语言:javascript
复制
@Configuration
public class CustomConfig {
    @Bean
    @Lazy
    public Person person() {
        return new Person();
    }
}

相当于xml中bean的lazy-init属性

代码语言:javascript
复制
<beans>
    <bean id="person" class="top.felixfly.entity.Person" lazy-init="true"/>
</beans>

@DependsOn

依赖关系注解

代码语言:javascript
复制
@Configuration
public class CustomConfig {

    @Bean
    @DependsOn("person")
    public Manager manager(){
        return new Manager();
    }

    @Bean
    public Person person(){
        return new Person();
    }
}

相当于xml中bean的depends-on属性

代码语言:javascript
复制
<beans>
    <bean id="manager" class="top.felixfly.entity.Manager" depends-on="person"/>
</beans>

@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接口
代码语言:javascript
复制
public class CustomCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata 	metadata) {
        // true 进行装配,false不进行装配
        return false;
    }
}
  • Bean上配置@Conditional(Condition.class)
代码语言:javascript
复制
@Configuration
public class CustomConfig {

    @Conditional(CustomCondition.class)
    @Bean
    public Person person() {
        return new Person();
    }
}

当matches方法返回true的时候进行注册当前@Bean,否则不注册。该注解也可以放到配置类上,matches方法返回true的时候进行注册当前配置类,否侧不注册。

@Profile 环境注解,底层使用的是@Conditional

@Import 快捷注册Bean,默认名称为类的全路径

  • 直接导入类
代码语言:javascript
复制
@Configuration
@Import(Person.class)
public class CustomConfig {
}
  • 导入实现org.springframework.context.annotation.ImportSelector类
代码语言:javascript
复制
public class CustomImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{Person.class.getName()};
    }
}
代码语言:javascript
复制
@Configuration
@Import(CustomImportSelector.class)
public class CustomConfig {
}
  • 导入实现org.springframework.context.annotation.ImportBeanDefinitionRegistrar类
代码语言:javascript
复制
public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
        // 自行注册BeanDefinition
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
        registry.registerBeanDefinition("person",beanDefinition);
    }
}
代码语言:javascript
复制
@Configuration
@Import(CustomImportBeanDefinitionRegistrar.class)
public class CustomConfig {
}

@ImportResource

导入资源xml文件

资源文件名称spring/application-spring.xml

代码语言:javascript
复制
<beans>    
    <bean class="top.felixfly.spring.annotation.entity.Person">
        <constructor-arg index="0" value="张三"/>
        <constructor-arg index="1" value="27"/>
    </bean>
</beans>
代码语言:javascript
复制
@Configuration
@ImportResource("classpath:/spring/application-spring.xml")
public class CustomConfig {
}

常见问题

@Configuration、其他注解与@Bean结合使用有什么不同 答:@Configuration注解使用的其实也是一个Bean,但本身是BeanFatory,是经过CGLIB进行增强的Bean,其他注解(@Component、@Service、@Controller、@Repository)使用的就是一个简单的Bean

Bean 依赖注入

常用注解

@Autowired Spring自带的自动注入,注解的属性required来支持是否必须要进行依赖注入。根据以下规则进行查找进行注入

1、 根据类型查找,只查询一个直接返回

2、 根据名称查找

代码语言:javascript
复制
@Service
public class PersonService {

    @Autowired
    private PersonMapper personMapper;
}

可以结合以下注解进行使用

  • @Qualifier

指定名称进行依赖注入

代码语言:javascript
复制
@Service
public class PersonService {

    @Autowired
    @Qualifier("personMapper")
    private PersonMapper personMapper;
}
  • @Primary

指定优先进行依赖注入

代码语言:javascript
复制
@Service
public class PersonService {

    @Autowired
    private PersonMapper personMapper;
}
代码语言:javascript
复制
@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是否必须要进行依赖注入

代码语言:javascript
复制
@Service
public class PersonService {

    @Resource
    private PersonMapper personMapper;
}

@Service
public class PersonService {
	// 强制指定Bean
    @Resource(name="personMapper2")
    private PersonMapper personMapper;
}

@Inject

Java规范的注解(JSR330),功能与@Autowired一样,但不支持required是否必须要进行依赖注入。需要引入javax.inject

代码语言:javascript
复制
<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>
代码语言:javascript
复制
@Service
public class PersonService {

    @Inject
    private PersonMapper personMapper;
}

注入方式

构造器注入

代码语言:javascript
复制
@Configuration
public class AppConfig {

    @Bean
    public BeanOne beanOne() {
        // 构造器注入
        return new BeanOne(beanTwo());
    }
    
    @Bean
    public BeanOne beanThree(BeanTwo beanTwo) {
        // 构造器注入
        return new BeanOne(beanTwo);
    }

    @Bean
    public BeanTwo beanTwo() {
        return new BeanTwo();
    }
}

Setter方法注入

代码语言:javascript
复制
public class BeanTwo {

    @Autowired
    public void setBeanOne(BeanOne beanOne) {
        this.beanOne = beanOne;
    }
}

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
代码语言:javascript
复制
@Configuration
public class CustomConfig {

    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Person person(){
        return new Person();
    }
}

相当于xml中配置init-method和destroy-method属性

代码语言:javascript
复制
<beans>
    <bean class="top.felixfly.spring.annotation.entity.Person" init-method="init" destroy-method="destroy"/>
</beans>
  • 实现InitializingBean和DisposableBean
代码语言:javascript
复制
public class Person implements InitializingBean, DisposableBean {

    public Person() {
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    }

    @Override
    public void destroy() throws Exception {
    }
}
  • 使用@PostConstruct和@PreDestroy

注解使用InitDestroyAnnotationBeanPostProcessor进行解析处理,父类CommonAnnotationBeanPostProcessor

代码语言:javascript
复制
public class Person {

    public Person() {
    }

    @PostConstruct
    public void postConstruct(){
    }

    @PreDestroy
    public void preDestroy(){
    }
}

BeanPostProcessor

  • postProcessBeforeInitialization 初始化之前执行方法
  • postProcessAfterInitialization 初始化之后执行方法
代码语言:javascript
复制
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }


    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
代码语言:javascript
复制
@Configuration
@Import(CustomBeanPostProcessor.class)
public class CustomConfig {

    @Bean
    public Person person(){
        return new Person();
    }
}

执行方法若是返回null值,后续的BeanPostProcessor不会进行执行,源代码执行如下:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

代码语言:javascript
复制
@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

常见问题

生命周期执行方法顺序、

答:初始化方法执行顺序

  1. @PostConstruct
  2. 实现InitializingBean接口的方法
  3. @Bean指定initMethod

销毁方法执行顺序

  1. @PreDestroy
  2. 实现DisposableBean接口的方法
  3. @Bean指定destroyMethod

Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, are called as follows:

  1. Methods annotated with @PostConstruct
  2. afterPropertiesSet() as defined by the InitializingBean callback interface
  3. A custom configured init() method

Destroy methods are called in the same order:

  1. Methods annotated with @PreDestroy
  2. destroy() as defined by the DisposableBean callback interface
  3. A custom configured destroy() method

资源属性赋值

常用注解

@Value

属性进行赋值,可以有如下三种写法

  • 直接赋值
代码语言:javascript
复制
public class Person {

    @Value("张三")
    private String name;
}
  • SpEL表达式 #{}
代码语言:javascript
复制
public class Person {

    @Value("#{20-2}")
    private String age;
}
  • ${} 文件属性赋值(通常在环境变量Enviroment中),要配合@PropertySource使用
代码语言:javascript
复制
public class Person {

    @Value("${person.age}")
    private String age;
}

@PropertySource

引入配置文件,配置文件下根路径下person.properties

代码语言:javascript
复制
@PropertySource("classpath:/person.properties")
public class CustomConfig {

}

相当于xml中的context:property-placeholder

代码语言:javascript
复制
<context:property-placeholder location="classpath:person.properties"/>

@PropertySources

多个配置文件引入,值为PropertySource的数组,1.8以后可以用多个@PropertySource代替此注解

常见问题

配置文件属性乱码

答:注解@PropertySource通过属性encoding进行配置文件编码,该配置在4.3版本引入;xml配置文件中通过属性file-encoding配置文件编码

原文链接:https://gper.club/articles/7e7e7f7ff7g5fgccg67

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Bean 注册
  • 常用注解
  • 常见问题
  • Bean 依赖注入
    • 常用注解
    • 注入方式
      • 构造器注入
        • Aware接口
        • 常见问题
          • 循环依赖的问题
          • Bean 生命周期
          • 初始化和销毁常用方法
          • 常见问题
            • 生命周期执行方法顺序、
            • 资源属性赋值
              • 常用注解
              • 常见问题
                • 配置文件属性乱码
                相关产品与服务
                容器服务
                腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档