Spring框架之IoC

Spring的后处理器 待补充~

  • BeanFactoryPostProcessor
  • BeanPostProcessor

Bean的生命周期

具体可见图解:点击这里

补充:

  • Aware
  • Ordered

Bean的加载方式

1.xml方式

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--声明自定义bean-->
<bean id="bookService" class="com.azy.service.impl.BookServiceImpl"
scope="singleton"/> <!--声明第三方开发bean-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
</beans>

2.xml文件+Component注解

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描bean-->
<context:component-scan base-package="com.azy"/> </beans>

类上面加上@Component注解

@Component
//@Service,@Controller,@Repository为@Component衍生注解,效果相同
public class BookServiceImpl implements BookService { }
//第三方Bean
@Component
public class DruidBean {
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl("");
dataSource.setUsername("");
dataSource.setPassword("");
return dataSource;
}
}

3.纯注解

//配置类:
//注解开发,替换配置文件xml文件
@Configuration
@ComponentScan("com.azy") //包扫描
public class SpringConfig {
}

扩展:

  • FactoryBean接口产生Bean

  • ImportSource注解可以加载旧的配置文件

    @Configuration
    @ComponentScan("com.azy") //包扫描
    @ImportResource("applicationContext-config.xml")
    public class SpringConfig {
    }
  • Configuration注解默认有个参数proxyBeanMethods=true可以保障调用此方法得到的对象是从容器中获取的而不是重新创建的

4.Import注解导入

//配置类:
//注解开发,替换配置文件xml文件
@Configuration
@ComponentScan("com.azy") //包扫描
@Import(DruidBean.class)
public class SpringConfig {
}

Import可以导入普通类或者配置类,导入的普通类或者配置类不用再加@Component注解:

//第三方Bean
//@Component
public class DruidBean {
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl("");
dataSource.setUsername("");
dataSource.setPassword("");
return dataSource;
}
}

5.Spring容器注册

public class AppImport {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(SpringConfig.class);
ctx.register(Cat.class);//注册
//……
}
}

6.Import注解导入接口

  • ImportSelector接口:
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[0];
}
}
//可以根据importingClassMetadata参数来判断导入该实现类所在的类的条件,
//从而返回要进行创建的Bean的类名
  • ImportBeanDefinitionRegistrar接口
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { }
}
//通过BeanDefinition的注册器注册实名bean,实现对容器中bean的裁定,
//例如对现有bean的覆盖,进而达成不修改源代码的情况下更换实现的效果
  • BeanDefinitionRegistryPostProcessor接口
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = BeanDefinitionBuilder
.rootBeanDefinition(BookServiceImpl.class)
.getBeanDefinition();
registry.registerBeanDefinition("bookService", beanDefinition);
}
}
//通过BeanDefinition的注册器注册实名bean,实现对容器中bean的最终裁定

Bean的加载控制

1.Spring容器注册

2.Import注解导入接口

  • ImportSelector接口
  • ImportBeanDefinitionRegistrar接口
  • BeanDefinitionRegistryPostProcessor接口

3.Conditional衍生注解

这些衍生注解都是SpringBoot实现的

@Component
//@ConditionalOnClass(Book.class)
//ConditionalOnClass可以直接导入类,但是ConditionalOnMissingClass不可以,建议使用name
@ConditionalOnClass(name="com.azy.pojo.Book")//有这个类才加载下面的BookService
@ConditionalOnMissingClass("com.azy.pojo.Book")//没有这个类才加载下面的BookService
public class BookServiceImpl implements BookService { }

第三方Bean:

//有数据库驱动的时候才加载DataSource
@Component
public class DruidBean {
@Bean
@ConditionalOnClass(name="com.mysql.jdbc.Driver")
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl("");
dataSource.setUsername("");
dataSource.setPassword("");
return dataSource;
}
}

Spring自定义标签解析 待补充~

Spring注解的解析原理

Spring注解的解析主要包含两种方式(即Bean的加载方式中的2和3):

  • 配置文件中自定义标签:

    <context:component-scan base-package="com.azy"/>

​ 使用xml方式配置组件扫描,而component-scan是一个context命名空间下的自定义标签,所以要找到对应的命名空间处理器NamespaceHandler和解析器,查看spring-context包下的spring.handlers文件:

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler

查看 ContextNamespaceHandler 类 :

public void init() {
this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
}

ComponentScanBeanDefinitionParser进行了注册,对其源码进行跟踪,最终将标注的@Component的类,生成对应的BeanDefiition进行了注册。

  • 配置类上添加ComponentScan注解

​ 使用配置类配置组件扫描,使用AnnotationConfigApplicationContext容器在进行创建时,内部调用了如下代码, 该工具注册了几个Bean后处理器:

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

​ 其中,ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor ,经过一系列源码调用,最终也指到了 ClassPathBeanDefinitionScanner doScan 方法,与xml方式最终终点一致。

Spring整合Mybatis原理

  • xml方式整合:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value=""/>
    <property name="username" value=""/>
    <property name="password" value=""/>
    </bean>
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="druidDataSource"/>
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.azy.ioc.mapper"/>
    </bean> </beans>

    主要是依靠SqlSessionFactoryBeanMapperScannerConfigurer来进行整合的:

    • SqlSessionFactoryBean的作用是向容器中提供SqlSessionFactory

      public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
      //这里实现了FactoryBean接口,getObject方法获取Bean
      public void afterPropertiesSet() throws Exception {
      //创建SqlSessionFactory对象
      this.sqlSessionFactory = this.buildSqlSessionFactory();
      }
      public SqlSessionFactory getObject() throws Exception {
      return this.sqlSessionFactory;
      }
      }
    • MapperScannerConfigurer的作用是扫描Mapper,向容器中注册Mapper对应的MapperFactoryBean:

      //MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor,在postProcessBeanDefinitionRegistry方法中利用ClassPathMapperScanner向容器中注册MapperFactoryBean
      class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean{
      public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
      ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
      scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
      }
      } //ClassPathMapperScanner继承了ClassPathBeanDefinitionScanner
      class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {
      public Set<BeanDefinitionHolder> doScan(String... basePackages) {
      Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
      if (beanDefinitions.isEmpty()) {
      } else {
      this.processBeanDefinitions(beanDefinitions);
      }
      }
      private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
      //设置Mapper的beanClass是org.mybatis.spring.mapper.MapperFactoryBean
      definition.setBeanClass(this.mapperFactoryBeanClass);
      definition.setAutowireMode(2); //设置MapperBeanFactory 进行自动注入
      }
      }

      MapperFactoryBean的作用就是产生对应的Mapper,其底层实际上还是调用的Mybatis的方法:

      public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
      public MapperFactoryBean(Class<T> mapperInterface) {
      this.mapperInterface = mapperInterface;
      }
      public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
      this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
      }
      public T getObject() throws Exception {
      return this.getSqlSession().getMapper(this.mapperInterface);
      }//这里getSqlSession利用自动注入,然后再利用sqlSession调用getMapper
      }
  • 注解方式:

    @Component
    @MapperScan("com.azy.annotation.mapper")
    public class MybatisConfig { @Bean //形参可以自动装配
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
    SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
    sqlSessionFactory.setTypeAliasesPackage("com.azy.annotation.pojo");
    sqlSessionFactory.setDataSource(dataSource);
    return sqlSessionFactory;
    }
    }

    这里主要看MapperScan注解,它导入了MapperScannerRegistrar

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(MapperScannerRegistrar.class)
    public @interface MapperScan {
    }

    MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口:

    public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    
    }

    其中的registerBeanDefinitions方法向容器中注册了Mapper对应的MapperFactoryBean,与前面相同。

Spring框架1--IoC的更多相关文章

  1. Spring框架(3)---IOC装配Bean(注解方式)

    IOC装配Bean(注解方式) 上面一遍文章讲了通过xml来装配Bean,那么这篇来讲注解方式来讲装配Bean对象 注解方式需要在原先的基础上重新配置环境: (1)Component标签举例 1:导入 ...

  2. Spring框架之IOC(控制反转)

    [TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...

  3. Spring框架中IoC(控制反转)的原理(转)

    原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...

  4. Spring框架的IOC核心功能快速入门

    2. 步骤一:下载Spring框架的开发包 * 官网:http://spring.io/ * 下载地址:http://repo.springsource.org/libs-release-local/ ...

  5. (精简)Spring框架的IoC(替代工厂类实现方法)和AOP(定义规则,约定大于配置)

    Spring的核心框架主要包含两个技术,分别用来处理工厂类,以及事务处理和连接管理的. 两大核心概念 1)  IoC:控制反转,在现在的开发中,如果想建立对象并设置属性,是需要先new对象,再通过se ...

  6. 初识Spring框架实现IOC和DI(依赖注入)

    学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的, IoC是 ...

  7. Spring框架(2)---IOC装配Bean(xml配置方式)

    IOC装配Bean (1)Spring框架Bean实例化的方式提供了三种方式实例化Bean 构造方法实例化(默认无参数,用的最多) 静态工厂实例化 实例工厂实例化 下面先写这三种方法的applicat ...

  8. 十七、Spring框架(IOC/DI)

    一.Spring框架 Spring是一个基于IOC和AOP的结构J2EE系统的框架. 1.IOC反转控制是Spring的基础(Inversion Of Control).也就是说创建对象由以前的程序员 ...

  9. Spring框架的IOC之注解方式的快速入门

    1. 步骤一:导入注解开发所有需要的jar包 * 引入IOC容器必须的6个jar包 * 多引入一个:Spring框架的AOP的jar包,spring-aop的jar包 2. 步骤二:创建对应的包结构, ...

  10. Spring框架之IoC和AOP

    Spring框架简介: 2003年2月,Spring框架正式成为一个开源项目,并发布于SourceForge中.致力于Java EE应用的各种解决方案,而并不是仅仅专注于某一层的方案,是企业应用开发的 ...

随机推荐

  1. Django3.X使用富文本编辑器kindereditor上传图片时一直转圈圈,如何解决

    问题描述: 在写bbs项目的时候,老师用的是Django1.X结合富文本编辑器kindeditor,实现了图片上传,但是我在用Django3.X的时候,代码和老师一模一样,上传图片的时候一直转圈圈?? ...

  2. Grafana 系列文章(十二):如何使用Loki创建一个用于搜索日志的Grafana仪表板

    概述 创建一个简单的 Grafana 仪表板, 以实现对日志的快速搜索. 有经验的直接用 Grafana 的 Explore 功能就可以了. 但是对于没有经验的人, 他们如何能有一个已经预设了简单的标 ...

  3. 基于minikube快速搭建kubernetes单节点环境

    一.说明 本文主要介绍在 Centos7 环境下基于 Minikube 来快速部署 Kubernetes 单节点集群环境,并在浏览器上访问部署在 k8s 上的 dashboard 服务. 二.Mini ...

  4. FAS2720 配置

    FAS 2720配置操作 第1章 初始化 1.1设备物理安装 1.1.1组件介绍 机头FAS 2720 (2U)   前面板 后面 1.1.2准备工作 (1)工具准备 螺丝刀.网线.Console线. ...

  5. 斜率优化建图学习笔记 & JZOJ 地壳运动题解

    本章学习斜率优化建图 请放心食用 引言 最小生成树(\(mst\)) (\(Algorithm: \text {Prim or Kruskal}\)) 从裸题到一丁点技巧,再到丧心病狂的神仙题 原始时 ...

  6. RocketMQ - 消费者消费方式

    RocketMQ的消费方式包含Pull和Push两种 Pull方式:用户主动Pull消息,自主管理位点,可以灵活地掌控消费进度和消费速度,适合流计算.消费特别耗时等特殊的消费场景.缺点也显而易见,需要 ...

  7. Unity3D 不挂载脚本自动初始化

    https://blog.csdn.net/piai9568/article/details/98886028

  8. pip 基本问题

    pip语法错误 pip换源 更新错误 无模板 Ignoring警告 问题一 (pip语法错误 ) pip list File "<stdin>", line 1 pip ...

  9. vue学习笔记:Vue生命周期

    概念 一个Vue 实例从开始创建.初始化数据.编译模板.挂载 DOM.渲染→更新→渲染.卸载等一系列过程,这就是 Vue 的生命周期.同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不 ...

  10. JS下载单个图片、单个视频;批量下载图片,批量下载视频

    下载单张图片 import JSZip from "jszip"; import FileSaver from "file-saver"; downloadIa ...