一些基础但是核心的知识总结:

  • Spring Boot项目启动的时候需要加@Configuration、 @ComponentScan
  • @Configuration + @Bean 把第三方jar包注入到容器中。
  • 内部的直接 @Service @Controller等等之类配合 @ComponentSscan 的就OK了
  • @Scope可以实现单例
  • 对于启动默认是饿汉式调用时候创建(但是项目启动时候比较耗费时间),另外一种是调用时候创建
  • @ComponentScan有排除的用法,排除那个组件 需要哪个组件可以控制
  • 在config类上面加 @ComponentScan然后去控制其他注解的注入情况
  • 使用@Condition多条件注册bean对象,根据环境判断进行抉择
  • @Import快速注入第三方bean对象
  • SpringBoot Emablexxx开启原理
  • 基于ImportBeanDefinitionRegister注册bean
  • 基于FactoryBean注册Bean对象

Spring的扩展接口:  condition


对于控制某个Bean,满足某个条件后才可以允许注册到容器中:

随便写个系统实体类吧:

public class OS {
private String name;
private Integer version; public OS() {
} @Override
public String toString() {
return "hello ********************* OS{" +
"name='" + name + '\'' +
", version=" + version +
'}';
}
}

配置文件(相当于xml)

@Configuration
public class MyConfig { @Bean
@Conditional(MyCondition.class)
public OS os(){
System.out.println("ttttttttttttttttttttt");
return new OS();
}
}

控制条件:

public class MyCondition implements Condition {
/**
*
* @param conditionContext 获取当前上下文
* @param annotatedTypeMetadata 获取到当前注解的细节
* @return
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String osName = environment.getProperty("os.name");
if (osName.equals("Windows 7")){
return false;
}
if (osName.equals("Windows 10")){
return true;
}
return false;
}
}

测试类:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
OS osTest = (OS)applicationContext.getBean("os");
System.out.println(osTest);
}
}

结果:

2. @Import注解


思考 为啥使用@Import注解呢?

@Bean注解应用场景是什么呢? 注册加载外部的jar。如果有30个bean,逐个去写也是非常麻烦的啊

所以就用@Import简化操作,将外部的jar包注入到Spring ioc容器中。等同于@Bean。@Import注册的Bean对象,id为当前类的全路径。

配置类:

@Configuration
@Import(OS.class)
public class MyConfig {
}

测试方法:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
//Import的特殊性
OS osTest = (OS)applicationContext.getBean("com.toov5.config.beanTest.OS");
System.out.println(osTest);
}
}

@Import 和 @Bean的区别:

@Bean注册的bean的id是方法名称

@Import当前类完整地址

共同应用场景都是引用外部jar包。

3. @EnableXXX


开启某某功能。底层使用@Import注解实现的

底层调用的就是@Import注解

场景: 封装一个框架,把不支持springboot的,鼓捣成支持springboot的!

实体类:

public class PayEntity {
}

注解:

/**
* 启动时候加入该注解,开启功能,会将实体类注入到容器中
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({PayEntity.class})
public @interface EnablePayEntity { }

启动:

@Configuration
@EnablePayEntity
public class MyConfig {
}

测试:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
}
}

结果:

补充下: 可以@Import多个 ”,“解决。

4. ImportSelector接口 (跟 @Import注解一样的,只不过这个是原生api罢了)


实体类1:

public class MemberEntity {
}

实体类2:

public class PersonEntity {
}

原生接口的实现:

public class MyImportSeletcor implements ImportSelector {
/**
* 注解信息
* @param annotationMetadata
* @return
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.toov5.config.beanTest.MemberEntity", "com.toov5.config.beanTest.PersonEntity"};
}
}

启动类:

@Configuration
@Import(MyImportSeletcor.class)
public class MyConfig {
}

测试类:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
}
}

结果:

5. ImportBeanDefinitionRegister接口  手动往ioc 注入bean


Spring容器中 Bean的信息,都是由BeanDefinition描述的

可以看下:

各种方法,Bean的各种信息。

实体类:

public class PersonEntity {
}

接口实现,手动注入实体类

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 注解信息
* @param annotationMetadata
* @param beanDefinitionRegistry
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//手动注册到ioc容器中
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(PersonEntity.class);
//IOC源码里面肯定有这个的!!! 对象放到IOC容器中就叫注册 (底层是个map 线程安全的)
beanDefinitionRegistry.registerBeanDefinition("personEntity", rootBeanDefinition);
}
}

启动类:

@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class MyConfig { }

测试类:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
}
}

运行结果:

6. 基于FactoryBean


FactoryBean也可以用来注册Bean

启动方式千万万,随便使用:

实体类:

public class PersonEntity {
}

FactoryBean:

public class MyFactoryBean implements FactoryBean<PersonEntity> {
@Override
public PersonEntity getObject() throws Exception {
return new PersonEntity();
} @Override
public Class<?> getObjectType() {
return PersonEntity.class;
} @Override
public boolean isSingleton() {
//默认情况下是true。单例
return true;
}
//往ioc容器中注入对象 }

启动类:

@Configuration
public class MyConfig { @Bean
public MyFactoryBean myFactoryBean(){
return new MyFactoryBean();
}
}

测试类:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
PersonEntity personEntity1 = (PersonEntity)applicationContext.getBean("myFactoryBean");
PersonEntity personEntity2 = (PersonEntity)applicationContext.getBean("myFactoryBean");
System.out.println(personEntity1 == personEntity2);
}
}


自己写“抄”个注解玩玩

自定义一个注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface toov5 {
}

实体类:

@toov5
public class Hello {
}

启动采用扫包的方式:扫包的范围

@Configuration
@ComponentScan("com.toov5.config.beanTest.entity")
public class MyConfig { }

测试:

public class test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames){
System.out.println(name);
}
}
}

测试结果:

小结: spring 注入bean到容器方式:

@Bean  @Import ,一般用于外部的jar包

其他的 @Service @Repository 注入对象底层其实都一样,就是区分不同的场景。使用的时候需要@ComponentScan注解扫包

还有就是实现一系列相应的接口去实现注入Bean 的方式

如下:

  • 注解

    • @Bean
    • @Import
    • @EnableXXX(实质@Import)
  • 接口

    • condition接口 + @Conditional
    • ImportSelector接口 + @Bean、@Import
    • ImportBeanDefinitionRegister接口+@Bean、@Import
    • FactoryBean接口+ @Bean、@Import

Spring5源码分析之启动类的相关接口和注解的更多相关文章

  1. 精尽Spring Boot源码分析 - SpringApplication 启动类的启动过程

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

  2. Appium Server 源码分析之启动运行Express http服务器

    通过上一个系列Appium Android Bootstrap源码分析我们了解到了appium在安卓目标机器上是如何通过bootstrap这个服务来接收appium从pc端发送过来的命令,并最终使用u ...

  3. Appium Android Bootstrap源码分析之启动运行

    通过前面的两篇文章<Appium Android Bootstrap源码分析之控件AndroidElement>和<Appium Android Bootstrap源码分析之命令解析 ...

  4. Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...

  5. Spring5源码分析(1)设计思想与结构

    1 源码地址(带有中文注解)git@github.com:yakax/spring-framework-5.0.2.RELEASE--.git Spring 的设计初衷其实就是为了简化我们的开发 基于 ...

  6. u-boot 源码分析(1) 启动过程分析

    u-boot 源码分析(1) 启动过程分析 文章目录 u-boot 源码分析(1) 启动过程分析 前言 配置 源码结构 api arch board common cmd drivers fs Kbu ...

  7. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  8. Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...

  9. JUC源码分析-其它工具类(一)ThreadLocalRandom

    JUC源码分析-其它工具类(一)ThreadLocalRandom ThreadLocalRandom 是 JDK7 在 JUC 包下新增的随机数生成器,它解决了 Random 在多线程下多个线程竞争 ...

随机推荐

  1. JQuery的入门(二)

    Jquery的遍历 jQuery对象本身就是数组对象,通过jquery选择器获得的都是满足该选择器条件的元素对象的集合体,因此在常常需要对jquery对象进行遍历.这里有三种遍历Jquery的方法. ...

  2. 国产MM才叫漂亮[景甜]

  3. JAVA面试中需要准备的点

    零基础入门学习Java,如何准备Java初级和高级的技术面试   本人最近几年一直在做java后端方面的技术面试官,而在最近两周,又密集了面试了一些java初级和高级开发的候选人,在面试过程中,我自认 ...

  4. c#基础用法

    1.注释符 1)注销 2)解释 2.3种方式 1)单行注释 // 2)多行注释 /*要注释的内容*/ 3)文档注释 /// 多用来解释类或方法 3.数据类型 1)值类型 2)引用类型 1.对象 obj ...

  5. 接口中的xml报文和实体类的之间转换

    需求:湖南保险行业意健险承保风险预警平台数据接口 平台提供HTTPServlet服务,接受保险公司的数据请求,并在处理后返回给保险公司相应的处理结果.数据接口格式为XML数据报文,在每次接口的交易中, ...

  6. ztree树默认根据ID默认选中该条数据

    functiongetZtree() { varsetting = { view: { expandSpeed: 100, selectedMulti: true, showLine: true, / ...

  7. mysql5.7的手动安装

    1.安装必要的组件    | yum install –y autoconf automake imake libxml2-devel expat-devel cmake gcc gcc-c++ li ...

  8. PHP 源码安装常用配置参数和说明

    常用的配置参数1. --prefix=/usr/local/php指定 php 安装目录install architecture-independent files in PREFIX 默认/usr/ ...

  9. C函数指针数组的定义和使用

    1.使用函数指针数组来实现计算器 2.通过函数指针变量来调用对应的函数 #include <stdio.h> int add(int a,int b){ return a+b; } int ...

  10. Python学习之--用户输入以及运算

    一. 用户输入:input 1. 函数input() 让程序暂停运行,等待用户输入一些文本. 2.使用int()将字符串转为数值 二.运算:+-*. 1.求模运算符 (%)将两个数相除并返回余数: 2 ...