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. immutable.js学习笔记(八)----- immutable.js对象 和 原生对象的相互转换

    一.原生对象转换为immutable.js对象 fromJS 栗子一: 栗子二: 如果数组里面有对象,对象里面有数组,怎么转换呢 复杂结构的转换 二.immutable.js对象转换为原生对象 toJ ...

  2. C#,Winform软件防破译-源代码加密简单方法之.NET REACTOR(二)制作软件及软件试用时间限定

    二.简单介绍使用 .net reactor 软件制作试用软件,利用license制作授权软件的方法. 1.首先,生成试用版软件 设置主文件和附属文件,打开.net Reactor 设置试用期限,在Se ...

  3. Selenium CHANGELOG[最新版本4.8.0 计划中]

    Selenium CHANGELOG[持续更新] 源文件 https://github.com/SeleniumHQ/selenium/blob/trunk/py/CHANGES 搬运工 对重点版本做 ...

  4. USACO 2023 January Contest, Bronze Problem 3. Moo Operations

    这道题目灰常简单,我们先从最简单的3个字符串开始 有以下几种情况: 可以看到,只有在中间是O的情况下才有可能变成MOO 辣么我们不妨在在s串中枚举这个中间 O 每枚举到一个就看看能不能用他的本身操作次 ...

  5. redis georadius源码分析与性能优化

    原文地址: https://blog.fanscore.cn/a/51/ 背景 最近接到一个需求,开发中使用了redis georadius命令取附近给定距离内的点.完工后对服务进行压测后发现geor ...

  6. javaweb-LoginDemo在JdbcTemp的登录实现及总结+进阶javabean改进

    刚开始发现- -我好像忘记了JdbcTemp的知识了,以为自己学漏了,重新回去看了一下,还好还记得,所以今天做一个案例: 案例分析: 登录的实现 步骤: 先导入jar包,然后写一个简单的html页面 ...

  7. 宇宙最强开发工具VScode简易手册

    VS Code 的全称是 Visual Studio Code,是一款开源的.免费的.跨平台的.高性能的.轻量级的代码编辑器.它在性能.语言支持.开源社区方面,都做得很不错,是这两年非常热门的一款开发 ...

  8. uboot启动过程 1

    打开 u-boot.lds OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-li ...

  9. 逆天的Zstack-工控机上测试

    放假前一直在服务器上折腾Zstack跑数据库,调IOC.正好手头有个32G内存,intel i7处理器的工控机,就试试装Zstack跑跑看,想着即使重负荷的跑不了,跑跑docker之类的也行.装成功后 ...

  10. 微信小程序-【转发好友】以及中文标题乱码问题解决

    微信小程序的转发功能,参考官方文档,使用的buttom的open-type功能,下面是转发功能的具体实现. // 通过按钮的 open-type="share"实现转发,触发onS ...