• Spring(十五)- Spring注解方式整合第三方框架


    一、Spring注解方式整合第三方框架

    1. Spring注解方式整合Mybatis原理

    第三方框架整合,依然使用MyBatis作为整合对象,之前我们已经使用xml方式整合了MyBatis,现在使用注解方式无非就是将xml标签替换为注解,将xml配置文件替换为配置类而已,原有xml方式整合配置如下:

     
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> 
    	<property name="url" value="jdbc:mysql://localhost:3306/mybatis">property> 
    	<property name="username" value="root">property> 
    <property name="password" value="root">property>
    bean>
    
     
    <bean class="org.mybatis.spring.SqlSessionFactoryBean"> 
    	<property name="dataSource" ref="dataSource">property>
    bean>
    
     
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
    	<property name="basePackage" value="com.itheima.dao">property>
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    使用@Bean将DataSource和SqlSessionFactoryBean存储到Spring容器中,而MapperScannerConfigurer使用注解@MapperScan进行指明需要扫描的Mapper在哪个包下,使用注解整合MyBatis配置方式如下:

    @Configuration
    @ComponentScan("com.itheima")
    @MapperScan("com.itheima.mapper")
    public class ApplicationContextConfig {
    
    	@Bean
        public DataSource dataSource(
                @Value("${jdbc.driver}") String driver,
                @Value("${jdbc.url}") String url,
                @Value("${jdbc.username}") String username,
                @Value("${jdbc.password}") String password
        ){
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driver);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
        
    	@Bean
    	public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
    		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    		sqlSessionFactoryBean.setDataSource(dataSource);
    		return sqlSessionFactoryBean;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注解方式,Spring整合MyBatis的原理,关键在于@MapperScan,@MapperScan不是Spring提供的注解,而是MyBatis为了整合Spring,在整合包org.mybatis.spring.annotation中提供的注解,源码如下:

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    @Import({MapperScannerRegistrar.class})
    @Repeatable(MapperScans.class)
    public @interface MapperScan {
    	String[] value() default {};
    	String[] basePackages() default {};
    	Class<?>[] basePackageClasses() default {};
    	Class<? extends Annotation> annotationClass() default Annotation.class;
    	// ... ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    重点关注一下@Import({MapperScannerRegistrar.class}),当@MapperScan被扫描加载时,会解析@Import注解,从而加载指定的类,此处就是加载了MapperScannerRegistrar

    MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,Spring会自动调用registerBeanDefinitions方法,该方法中又注册MapperScannerConfigurer类,而MapperScannerConfigurer类作用是扫描Mapper,向容器中注册Mapper对应的MapperFactoryBean,前面讲过,此处不在赘述了:章节地址

    public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
    		// 默认执行registerBeanDefinitions方法
    		void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
    			BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
    			// ... 省略其他代码 ...
    			// 注册BeanDefinition
    			registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
    	} 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2. @Import整合第三方框架原理

    Spring与MyBatis注解方式整合有个重要的技术点就是@Import,第三方框架与Spring整合xml方式很多是凭借自定义标签完成的,而第三方框架与Spring整合注解方式很多是靠@Import注解完成的。
    @Import可以导入如下三种类:
    ⚫ 普通的配置类
    ⚫ 实现ImportSelector接口的类
    ⚫ 实现ImportBeanDefinitionRegistrar接口的类

    @Import导入实现了ImportSelector接口的类

    @Configuration
    @ComponentScan("com.itheima")
    @Import({MyImportSelector.class})
    public class ApplicationContextConfig {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    public class MyImportSelector implements ImportSelector {
    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		// 返回要进行注册的Bean的全限定名数组
    		return new String[]{User2.class.getName()};
    	} 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ImportSelector接口selectImports方法的参数AnnotationMetadata代表注解的媒体数据,可以获得 当前注解(@Import({MyImportSelector.class})) 修饰的类(ApplicationContextConfig ) 的 其他注解的元信息,例如:@Configuration、@ComponentScan(“com.itheima”)注解的元信息

    public class MyImportSelector implements ImportSelector {
    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		// 获得指定类型注解的全部信息
    		Map<String, Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(ComponentScan.class.getName());
    		// 获得全部信息中basePackages信息
    		String[] basePackages = (String[]) annotationAttributes.get("basePackages");
    		// 打印结果是com.itheima
    		System.out.println(basePackages[0]);
    		return new String[]{User2.class.getName()};
    	} 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    @Import导入实现ImportBeanDefinitionRegistrar接口的类,实现了该接口的类的registerBeanDefinitions方法会被自动调用,在该方法内可以注册BeanDefinition

    public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    	@Override
    	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    		// 使用给定的BeanDefinitionRegistry参数,手动注册BeanDefinition
    		BeanDefinition beanDefinition = new RootBeanDefinition();
    		beanDefinition.setBeanClassName("com.itheima.pojo.User2");
    		registry.registerBeanDefinition("user2", beanDefinition);
    	} 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    Java开发的九大工作领域
    如何进行高性能架构的设计
    rnacos实现raft和类distro协议,支持集群部署
    数学建模B多波束测线问题B
    haproxy参数选择问题
    Linux Command echo
    jsp监考安排管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
    基于Skeleton的手势识别:SAM-SLR-v2
    linux系统,确认账户密码正确
    [附源码]java毕业设计宠物商店管理系统
  • 原文地址:https://blog.csdn.net/qq_36602071/article/details/127911913