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. .Net和.NetCore WebAPI批量上传文件以及文件操作(支持模糊匹配)

    1.Net /// <summary> /// 上传文件 /// </summary> /// <returns></returns> [HttpPos ...

  2. C# 高德地图WebApi对接示例

    1.登录或注册高德地图开放平台然后申请应用key(需要认证个人或企业开发者) 高德开放平台 | 高德地图API (amap.com)https://developer.amap.com/?ref=ht ...

  3. 源码下载teb

    git clone https://github.com/rst-tu-dortmund/teb_local_planner.git git checkout <ros版本分支> git ...

  4. 基于jib-maven-plugin快速构建微服务docker镜像

    一.说明 本文介绍基于 Maven 插件 jib-maven-plugin 实现快速构建 Spring Boot 程序镜像,并推送到远程仓库中,且 无需安装 Docker 环境 . Jib 是 Goo ...

  5. 关于HTML5中Video标签播放问题

    PS:官网首页视频IOS与安卓都可播放代码: <video width="100%" height="auto" type="video/mp4 ...

  6. Blob 和 ArrayBuffer

    Blob 和 ArrayBuffer Blob 对象表示的是二进制到文本的对象: ArrayBuffer 对象表示一段二进制数据,用来模拟内存里面的数据. Blob 关于 Blob 的详细内容:了解 ...

  7. Intellij IDEA 通过数据库表生成带注解的实体类Generate MyPOJOs.groovy脚本的编写

    //两段代码第一个是mybatis-plus的 第二个spring-jpa的,jpa的是我复制别人的,是本体,mybatis的是我改的//idea连接数据方法见 https://www.cnblogs ...

  8. python sys.argv(全局文本索引替换)

    #利用sys.argv(实现从程序外部向程序传递参数.)写一个脚本.#全局替换(old_str to new_str,filename)import sys #导入sys模块print(sys.arg ...

  9. LCD1602液晶屏(续)

    从前面的分析中知道,在HD44780控制芯片忙的时候,是不能对其进行写入操作的,所以在写入指令或数据时都需要进行判忙的操作,其时序如下图所示(8位数据模式). 从上图中可看到,当HD44780在执行内 ...

  10. ansible 离线部署

    1.安装 python 环境 wget https://mirrors.bfsu.edu.cn/anaconda/archive/Anaconda3-2022.10-Linux-x86_64.sh s ...