还只会用 @Service 注册 Bean 吗? | 七日打卡

3,464 阅读3分钟

前言

众所周知,在我们平时的开发中,Spring这个框架已经环绕了整个项目,不是说我们不能不用Spring,而是这样做的代价太大了。每次面试,总是会问道Spring IOCAOP事务等等,今天这篇的话是猛男我刚工作碰到的一个面试真题,可怜我那时只知道@Service。然后就回去等通知了,到现在还没有给我通知。

另外的话,今天这篇会讲几种注入方式,至于原理好哥哥们就先别想了(别打我脸就行),这随便拿一个出来都的讲源码讲一遍,主要需要依赖的东西优点多,所以找个机会将Spring IOC 那一块的源码弄出来说说,这一篇的话主要是讲个大概。
打脸

正题

1 @Service、@Component、@Repository、@Controller

这种方式就很简单,像@Service@Repository其实还是用的@Component,在注解里面点击去看就知道了,需要注意的点是这种方式需要用@ComponentScan配置一个一个扫包范围。为什么不用@Component这一个呢,主要是Spring为了区分Bean的类型。@Repository作用于持久层,@Service 作用于业务逻辑层,@Controller作用于表现层(spring-mvc的注解)

@Component
public class ApproveCenterServiceImpl implements ApproveCenterService {
}
@Service
public class ApproveCenterServiceImpl implements ApproveCenterService {
}
@Repository
public class ApproveCenterServiceImpl implements ApproveCenterService {
}

2 @Bean 和@Configuration

这种方式是不是很熟悉,常用于标注配置类,最简单的一个例子就是我们使用SpringBoot 的时候需要手动注册一个 Bean叫做 RestTemplate

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

3 使用@Import

@Import 注解可以注册三种类型的Bean,第一种就是普通类,第二种DefinitionRegistrar类,第三种就是ImportSelector

3.1 普通类

/**
 * @author xiejianwei
 */
@Import(MessageRecord.class)
public @interface ImportBean {
}

3.2 DefinitionRegistrar

实现了ImportBeanDefinitionRegistrar,这种方式在实现类中提供了一个注册器,有一个很熟悉的注解@MapperScan好哥哥们点进去看看就明白了。

@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
}

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
  /**
   * 主要是这个方法,在参数中提供了BeanDefinitionRegistry这个注册器,可以手动向容器中注入bean
   */
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    AnnotationAttributes mapperScanAttrs = AnnotationAttributes
        .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
    if (mapperScanAttrs != null) {
      registerBeanDefinitions(mapperScanAttrs, registry);
    }
  }
}

3.3 ImportSelector

很多想Springboot starter中要开启某个功能时就会用到ImportSelector,比如像开启服务注册与发现的注解@EnableDiscoveryClient,主要原理是ImportSelector中的selectImports方法会返回一个字符串的数组,这里的字符串实际上是一个个我们需要注册类的全路径,类似于com.xjw.entity.pojo.MessageRecordSpring会根据全路径反射生成Bean。源码这一块就先不讲了(手动狗头)。

public class CommonModelSelector implements ImportSelector {
    public CommonModelSelector() {
    }

    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{MessageRecord.class.getName()};
    }
}

4 FactoryBean

FactoryBean是一个特殊的Bean,是否很多好哥哥在面试时被问到过FactoryBeanBeanFactry的区别呢,说道这个我的眼眶湿润了(讲道理,这个在面所谓高级工程师的时候经常被问到)。FactoryBean是一个特殊Bean,当我们实现这个接口时,会生成两个Bean对象,第一个就是实现类本身,需要用在Bean名称前(正常是类名首字母小写)加&来获取Bean,第二个Bean的话实际上就是getObject方法返回的bean,需要注意的是这种方式需要配合@Component或者@Configuration来实现。BeanFactry简单点来说就是Spring上下文的容器。
湿了

实例代码如下:

@Component
public class FactoryBeanLearn implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        //这个Bean是我们自己new的,这里我们就可以控制Bean的创建过程了
        return new MessageRecord();
    }

	/**
	 * bean的类型
	 *
	 **/
    @Override
    public Class<?> getObjectType() {
        return MessageRecord.class;
    }

	/**
	 * 是否是单例的
	 *
	 **/
    @Override
    public boolean isSingleton() {
        return true;
    }
}

本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞