Spring系列之@Import

@Import简介

@Import表示用来导入配置类或者一些需要前置加载的类.。
@Import支持 三种方式
1.带有@Configuration的配置类(4.2 版本之前只可以导入配置类, 4.2版本之后 也可以导入 普通类)
2.ImportSelector 的实现
3.ImportBeanDefinitionRegistrar 的实现

导入@Configuration的配置类

代码结构

1、代码结构见上图,RootConfig和OtherConfig在两个目录中

//ComponentScan包扫描,默认扫描当前路径下所有文件和子目录文件
//所有会扫描到RootConfig而扫描不到OtherConfig
@ComponentScan
public class SpringApplicationContext {
    public static void main(String[] args) {
    	//创建Annotation上下文
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringApplicationContext.class);
        //得到AService的bean
        AService bean = context.getBean(AService.class);
        bean.service();
        //得到BService的bean
        BService bean2 = context.getBean(BService.class);
        bean2.service();
        //关闭容器
        context.close();
    }
}

2、先看RootConfig 和AService代码

//Configuration等同于xml配置
//类中@bean注解的会被注册到spring容器中
//@import 将另外一个Configuration导入到当前Configuration中
//等于xml中<import>另一个xml
@Configuration
@Import(OtherConfig.class)
public class RootConfig {
    @Bean
    public AService orderDemoService(){
        return new AService();
    }
}

//AService 无任何注解,表示没有交给Spring管理
public class AService {
    public void service(){
        System.out.println("AService run");
    }
}

3、再看OtherConfig 和BService代码

//Configuration等同于xml配置
//类中@bean注解的会被注册到spring容器中
@Configuration
public class OtherConfig {
    @Bean
    public BService omsService(){
        return new BService();
    }
}
//BService 无任何注解,表示没有交给Spring管理
public class BService {
    public void service(){
        System.out.println("BService run");
    }
}

4、最后看执行效果
执行结果
执行结果表示,AService和BService 都是spring的bean,交给容器管理,说明此处import见效。

总结下执行过程:

  1. 容器类注解@ComponentScan,故启动时会扫描当前路径
  2. 扫描到RootConfig类,由于RootConfig类注解@Import(OtherConfig.class),故扫描OtherConfig类
  3. RootConfig和OtherConfig中分别存在@Bean注解,会将@Bean注解的方法的返回值放入Spring容器中
  4. 容器启动后AService和BService都在容器中,故可getBean拿到bean后使用

导入ImportSelector 的实现

1、先看启动类

//导入ImportSelector的实现类
//面向接口编程
@ComponentScan
@Import(MySelector.class)
public class SpringApplicationContext {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringApplicationContext.class);
        //得到MyBean的bean
        MyBean myBean = context.getBean(MyBean.class);
        myBean.service();
        //关闭容器
        context.close();
    }
}

2、继续上MySelector 和MyBean代码

//实现ImportSelector接口中selectImports方法
public class MySelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{MyBean.class.getName()};
    }
}
//MyBean 无任何注解,表示没有交给Spring管理
public class MyBean {
    public void service(){
        System.out.println("MyBean run");
    }
}

3、最后看运行结果
运行结果
执行结果表示,MyBean在容器中,说明此处import见效。

总结下执行过程:

  1. 容器类注解@ComponentScan,故启动时会扫描当前路径
  2. 扫描启动类时发现@Import(MySelector.class),会取出MySelector类中selectImports方法的返回值,返回值为String数组,数组内容为类的全限定名
  3. 容器会加载这些类,我们示例中会加载MySelector
  4. 容器启动后MySelector在容器中,故可getBean拿到bean后使用

ImportBeanDefinitionRegistrar 的实现

1、先看启动类

//导入ImportBeanDefinitionRegistrar的实现类
//可批量加入bean
@ComponentScan
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringApplicationContext {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringApplicationContext.class);
        //得到类的实例
        MyRegistrarBean myRegistrarBean = context.getBean(MyRegistrarBean.class);
        myRegistrarBean.service();
        //关闭容器
        context.close();
    }
}

2、继续上MyImportBeanDefinitionRegistrar和MyRegistrarBean代码

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        String beanName = MyRegistrarBean.class.getSimpleName();
        //beanName转化为驼峰式
        beanName = StringUtils.uncapitalize(beanName);
        //新建RootBeanDefinition放入BeanDefinition注册器中
        RootBeanDefinition beanDefinition = new RootBeanDefinition(MyRegistrarBean.class);
        registry.registerBeanDefinition(beanName,beanDefinition);
    }
}
public class MyRegistrarBean {
    public void service(){
        System.out.println("MyRegistrarBean service");
    }
}

3、最后看运行结果
运行结果执行结果表示,MyRegistrarBean 在容器中,说明此处import见效。

总结下执行过程:

  1. 容器类注解@ComponentScan,故启动时会扫描当前路径
  2. 扫描启动类时发现@Import(MyImportBeanDefinitionRegistrar.class),因为我们在MyImportBeanDefinitionRegistrar类中往BeanDefinition注册器中添加了MyRegistrarBean的BeanDefinition
  3. 容器会加载这些类
  4. 容器启动后MyRegistrarBean 在容器中,故可getBean拿到bean后使用
  5. ImportBeanDefinitionRegistrar因为直接添加BeanDefinition,故更强大灵活,也对开发者有一定的spring基础要求

总结

1、我们在springboot中经常见到导入ImportSelector和ImportBeanDefinitionRegistrar的代码,用的就是这个原理。
2、在日常开发中,我们可以通到配置XML或者外部资源配置管理类全限定名,起到手动加载自己想要的类的目的。
3、ImportSelector源码实现是在初始化beanFactory时完成解析,源码较复杂,有兴趣可自己查看。

 private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
	  //删除无关代码
	  // Import 注解中配置的是 ImportSelector 类型
      if (candidate.isAssignable(ImportSelector.class)) { 
            Class<?> candidateClass = candidate.loadClass();
            ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); // 实例化
            ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry); // 如果该类有实现对应的 Aware 接口,则注入对应的属性
            if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { // DeferredImportSelector 类型的放到集合中待后续处理
                this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
            }
            else { // 直接调用 selectImports 方法取得对应的类
                String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                processImports(configClass, currentSourceClass, importSourceClasses, false);
            }
        }
        else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
            // 如果是 ImportBeanDefinitionRegistrar 类型
            Class<?> candidateClass = candidate.loadClass();
            ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
            ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);
            configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
        }
        else {
            // 如果非上面两种类型,那么代表这是一个与 @Configuration 相关的类
            this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
            processConfigurationClass(candidate.asConfigClass(configClass));
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis 目录(?)[-] mybatis实战教程mybatis in action之一开发环境搭建 mybatis实战教程mybatis in action之二以接口的方式编程 mybatis实战教程mybatis in action之三实现数据的增删改查 mybatis实战教程mybatis in action之四实现关联数据的查询 mybatis实战教程mybatis in action之五与spring3集成附源码 mybatis实战教程mybatis in action之六与Spring MVC 的集成 mybatis实战教程mybatis in action之七实现mybatis分页源码下载 mybatis实战教程mybatis in action之八mybatis 动态sql语句 mybatis实战教程mybatis in action之九mybatis 代码生成工具的使用 mybatis SqlSessionDaoSupport的使用附代码下载 转自:http://www.yihaomen.com/article/java/302.htm (读者注:其实这个应该叫做很基础的入门一下下,如果你看过Hibernate了那这个就非常的简单) (再加一条,其实大家可以看官方的教程更好些:http://mybatis.github.io/mybatis-3/,而且如果英文不是很好的那就看中文的:http://mybatis.github.io/mybatis-3/zh/sqlmap-xml.html) 写在这个系列前面的话: 以前曾经用过ibatis,这是mybatis的前身,当时在做项目时,感觉很不错,比hibernate灵活。性能也比hibernate好。而且也比较轻量级,因为当时在项目中,没来的及做很很多笔记。后来项目结束了,我也没写总结文档。已经过去好久了。但最近突然又对这个ORM 工具感兴趣。因为接下来自己的项目中很有可能采用这个ORM工具。所以在此重新温习了一下 mybatis, 因此就有了这个系列的 mybatis 教程. 什么是mybatis MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录. orm工具的基本思想 无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点: 1. 从配置文件(通常是XML配置文件中)得到 sessionfactory. 2. 由sessionfactory 产生 session 3. 在session 中完成对数据的增删改查和事务提交等. 4. 在用完之后关闭session 。 5. 在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。 mybatis实战教程(mybatis in action)之一:开发环境搭建 mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包。这些软件工具均可以到各自的官方网站上下载。 首先建立一个名字为 MyBaits 的 dynamic web project 1. 现阶段,你可以直接建立java 工程,但一般都是开发web项目,这个系列教程最后也是web的,所以一开始就建立web工程。 2. 将 mybatis-3.2.0-SNAPSHOT.jar,mysql-connector-java-5.1.22-bin.jar 拷贝到 web工程的lib目录. 3. 创建mysql 测试数据库和用户表,注意,这里采用的是 utf-8 编码 创建用户表,并插入一条测试数据 程序代码 程序代码 Create TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(50) DEFAULT NULL, `userAge` int(11) DEFAULT NULL, `userAddress` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; Insert INTO `user` VALUES ('1', 'summer', '100', 'shanghai,pudong'

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值