Spring Boot中@Import三种使用方式

news2025/8/13 3:43:53

@Import是一个非常有用的注解,它的长处在于你可以通过配置来控制是否注入该Bean,也可以通过条件来控制注入哪些Bean到Spring容器中。

比如我们熟悉的:@EnableAsync 、@EnableCaching@EnableScheduling等等统一采用的都是借助@Import注解来实现的。

下面我们就通过示例来了解@Import三种用法!

一、引入普通类

有个用户类如下

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Data</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserConfig</span> {  
    <span style="color:#75715e">/** 用户名*/</span>
    <span style="color:#f92672">private</span> String username;

    <span style="color:#75715e">/**手机号*/</span>
    <span style="color:#f92672">private</span> String phone;
}
</code></span></span>

那么如何通过@Import注入容器呢?

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Import(UserConfig.class)</span>
<span style="color:#75715e">@Configuration</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserConfiguration</span> { 
}
</code></span></span>

当在@Configuration标注的类上使用@Import引入了一个类后,就会把该类注入容器中。

当然除了@Configuration 比如@Component、@Service等一样也可以。

测试

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@SpringBootTest</span>
<span style="color:#75715e">@RunWith(SpringRunner.class)</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserServiceTest</span> {

    <span style="color:#75715e">@Autowired</span>
    <span style="color:#f92672">private</span> UserConfig userConfig;
    
    <span style="color:#75715e">@Test</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">getUser</span><span style="color:#f8f8f2">()</span> {
        <span style="color:#e6db74">String</span> <span style="color:#e6db74">name</span> <span style="color:#ab5656">=</span> userConfig.getClass().getName();
        System.out.println(<span style="color:#e6db74">"name = "</span> + name);
    }
}
</code></span></span>

控制台输出

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-ini"><span style="color:#f92672">name</span> = com.jincou.importselector.model.UserConfig
</code></span></span>

如果@Import的功能仅仅是这样,那其实它并没什么特别的价值,我们可以通过其它方式实现?

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Configuration</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserConfiguration</span> {

    <span style="color:#75715e">@Bean</span>
    <span style="color:#f92672">public</span> UserConfig <span style="color:#a6e22e">userConfig</span><span style="color:#f8f8f2">()</span> {
        <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">UserConfig</span>();
    }   
}
</code></span></span>

再比如直接添加@Configuration注解

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Configuration</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserConfig</span> {
  <span style="color:#75715e">// ......</span>
}
</code></span></span>

确实如果注入静态的Bean到容器中,那完全可以用上面的方式代替,但如果需要动态的带有逻辑性的注入Bean,那才更能体现@Import的价值。

二、引入ImportSelector的实现类

说到ImportSelector这个接口就不得不说这里面最重要的一个方法:selectImports()

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">interface</span> <span style="color:#a6e22e">ImportSelector</span> {

	String[] selectImports(AnnotationMetadata importingClassMetadata);
}
</code></span></span>

这个方法的返回值是一个字符串数组,只要在配置类被引用了,这里返回的字符串数组中的类名就会被Spring容器new出来,然后再把这些对象注入IOC容器中。

所以这有啥用呢?我们还是用一个例子演示一下。

1、静态import场景(注入已知的类)

我们先将上面的示例改造下:

自定义MyImportSelector实现ImportSelector接口,重写selectImports方法

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">MyImportSelector</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">ImportSelector</span> {
    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> String[] selectImports(AnnotationMetadata importingClassMetadata) {
        <span style="color:#75715e">//这里目的是将UserConfig 注入容器中</span>
        <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">String</span>[]{<span style="color:#e6db74">"com.jincou.importselector.model.UserConfig"</span>};
    }
}
</code></span></span>

然后在配置类引用

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Import(MyImportSelector.class)</span>
<span style="color:#75715e">@Configuration</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserConfiguration</span> {

}
</code></span></span>

这样一来同样可以通过成功将UserConfig注入容器中。

如果看到这,你肯定会有疑问。我这又是新建MyImportSelector类,又是实现ImportSelector重写selectImports方法,然后我这么做有个卵用呢?

直接把类上加个@Component注入进去不香吗?这个ImportSelector把简单的功能搞这么复杂。

接下来就要说说如何动态注入Bean了。

2、动态import场景(注入指定条件的类)

我们来思考一种场景,就是你想通过开关来控制是否注入该Bean,或者说通过配置来控制注入哪些Bean,这个时候就有了ImportSelector的用武之地了。

我们来举个例子,通过ImportSelector的使用实现条件选择是注入本地缓存还是Redis缓存

1)、定义缓存接口和实现类

顶层接口

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">interface</span> <span style="color:#a6e22e">CacheService</span> {
    
    <span style="color:#f92672">void</span> <span style="color:#a6e22e">setData</span><span style="color:#f8f8f2">(String key)</span>;
}
</code></span></span>

本地缓存 实现类

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">LocalServicempl</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">CacheService</span> {
    
    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">setData</span><span style="color:#f8f8f2">(String key)</span> {
        System.out.println(<span style="color:#e6db74">"本地存储存储数据成功 key= "</span> + key); 
    }
}
</code></span></span>

redis缓存实现类

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">RedisServicempl</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">CacheService</span> {

    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">setData</span><span style="color:#f8f8f2">(String key)</span> {
        System.out.println(<span style="color:#e6db74">"redis存储数据成功 key= "</span> + key); 
    }
}
</code></span></span>

2)、定义ImportSelector实现类

以下代码中根据EnableMyCache注解中的不同值来切换缓存的实现类再spring中的注册。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">MyCacheSelector</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">ImportSelector</span> {
    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> String[] selectImports(AnnotationMetadata importingClassMetadata) {
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableMyCache.class.getName());
        <span style="color:#75715e">//通过 不同type注入不同的缓存到容器中</span>
        <span style="color:#e6db74">CacheType</span> <span style="color:#e6db74">type</span> <span style="color:#ab5656">=</span> (CacheType) annotationAttributes.get(<span style="color:#e6db74">"type"</span>);
        <span style="color:#f92672">switch</span> (type) {
            <span style="color:#f92672">case</span> LOCAL: {
                <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">String</span>[]{LocalServicempl.class.getName()};
            }
            <span style="color:#f92672">case</span> REDIS: {
                <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">String</span>[]{RedisServicempl.class.getName()};
            }
            <span style="color:#f92672">default</span>: {
                <span style="color:#f92672">throw</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">RuntimeException</span>(MessageFormat.format(<span style="color:#e6db74">"unsupport cache type {0}"</span>, type.toString()));
            }
        }
    }
}
</code></span></span>

3)、定义注解

@EnableMyCache注解就像一个开关,通过这个开关来是否将特定的Bean注入容器。

定义一个枚举

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Target(ElementType.TYPE)</span>
<span style="color:#75715e">@Retention(RetentionPolicy.RUNTIME)</span>
<span style="color:#75715e">@Documented</span>
<span style="color:#75715e">@Import(MyCacheSelector.class)</span>
<span style="color:#f92672">public</span> <span style="color:#75715e">@interface</span> EnableMyCache {
    CacheType <span style="color:#a6e22e">type</span><span style="color:#f8f8f2">()</span> <span style="color:#f92672">default</span> CacheType.REDIS;
}
</code></span></span>
<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">enum</span> <span style="color:#a6e22e">CacheType</span> {
    LOCAL, REDIS;
}
</code></span></span>

4)、测试

这里选择本地缓存。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@EnableMyCache(type = CacheType.LOCAL)</span>
<span style="color:#75715e">@SpringBootTest</span>
<span style="color:#75715e">@RunWith(SpringRunner.class)</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserServiceTest</span> {

    <span style="color:#75715e">@Autowired</span>
    <span style="color:#f92672">private</span> CacheService cacheService;

    <span style="color:#75715e">@Test</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">test</span><span style="color:#f8f8f2">()</span> {
        cacheService.setData(<span style="color:#e6db74">"key"</span>);
    }
}
</code></span></span>

控制台输出

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java">本地存储存储数据成功 key= key
</code></span></span>

切换成redis缓存

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@EnableMyCache(type = CacheType.REDIS)</span>
<span style="color:#75715e">@SpringBootTest</span>
<span style="color:#75715e">@RunWith(SpringRunner.class)</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserServiceTest</span> {

    <span style="color:#75715e">@Autowired</span>
    <span style="color:#f92672">private</span> CacheService cacheService;

    <span style="color:#75715e">@Test</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">test</span><span style="color:#f8f8f2">()</span> {
        cacheService.setData(<span style="color:#e6db74">"key"</span>);
    }
}
</code></span></span>

控制台输出

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java">redis存储数据成功 key= key
</code></span></span>

这个示例不是就是Bean的动态注入了吗?

3、Spring如何使用ImportSelector的场景

SpringBoot有两个常用注解 @EnableAsync @EnableCaching 其实就是通过ImportSelector来动态注入Bean

看下@EnableAsync注解,它有通过@Import({AsyncConfigurationSelector.class})

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Target({ElementType.TYPE})</span>
<span style="color:#75715e">@Retention(RetentionPolicy.RUNTIME)</span>
<span style="color:#75715e">@Documented</span>
<span style="color:#75715e">@Import({AsyncConfigurationSelector.class})</span>
<span style="color:#f92672">public</span> <span style="color:#75715e">@interface</span> EnableAsync {
    Class<? <span style="color:#f92672">extends</span> <span style="color:#a6e22e">Annotation</span>> annotation() <span style="color:#f92672">default</span> Annotation.class;

    <span style="color:#e6db74">boolean</span> <span style="color:#a6e22e">proxyTargetClass</span><span style="color:#f8f8f2">()</span> <span style="color:#f92672">default</span> <span style="color:#ae81ff">false</span>;

    AdviceMode <span style="color:#a6e22e">mode</span><span style="color:#f8f8f2">()</span> <span style="color:#f92672">default</span> AdviceMode.PROXY;

    <span style="color:#e6db74">int</span> <span style="color:#a6e22e">order</span><span style="color:#f8f8f2">()</span> <span style="color:#f92672">default</span> <span style="color:#ae81ff">2147483647</span>;
}
</code></span></span>

AsyncConfigurationSelector.class

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">AsyncConfigurationSelector</span> <span style="color:#f92672">extends</span> <span style="color:#a6e22e">AdviceModeImportSelector</span><EnableAsync> {
    <span style="color:#f92672">private</span> <span style="color:#f92672">static</span> <span style="color:#f92672">final</span> <span style="color:#e6db74">String</span> <span style="color:#e6db74">ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME</span> <span style="color:#ab5656">=</span> <span style="color:#e6db74">"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"</span>;

    <span style="color:#f92672">public</span> <span style="color:#a6e22e">AsyncConfigurationSelector</span><span style="color:#f8f8f2">()</span> {
    }

    <span style="color:#75715e">@Nullable</span>
    <span style="color:#f92672">public</span> String[] selectImports(AdviceMode adviceMode) {
        <span style="color:#f92672">switch</span>(adviceMode) {
        <span style="color:#f92672">case</span> PROXY:
            <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">String</span>[]{ProxyAsyncConfiguration.class.getName()};
        <span style="color:#f92672">case</span> ASPECTJ:
            <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">String</span>[]{<span style="color:#e6db74">"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration"</span>};
        <span style="color:#f92672">default</span>:
            <span style="color:#f92672">return</span> <span style="color:#ae81ff">null</span>;
        }
    }
}
</code></span></span>

是不是和我上面写的示例一样。

总之,向这种还不能决定去注入哪个处理器(如果你能决定,那就直接@Import那个类好了,没必要实现接口了),就可以实现此接口,写出一些判断逻辑,不同的配置情况注入不同的处理类。

三、引入ImportBeanDefinitionRegister的实现类

当配置类实现了 ImportBeanDefinitionRegistrar 接口,你就可以自定义往容器中注册想注入的Bean。

这个接口相比与 ImportSelector 接口的主要区别就是,ImportSelector接口是返回一个类,你不能对这个类进行任何操作,但是 ImportBeanDefinitionRegistrar 是可以自己注入 BeanDefinition,可以添加属性之类的。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">MyImportBean</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">ImportBeanDefinitionRegistrar</span> {

    <span style="color:#75715e">/**
     * <span style="color:#808080">@param</span> importingClassMetadata 当前类的注解信息
     * <span style="color:#808080">@param</span> registry               注册类,其registerBeanDefinition()可以注册bean
     */</span>
    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">registerBeanDefinitions</span><span style="color:#f8f8f2">(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)</span> {

    }
}
</code></span></span>

1、举一个简单的示例

我们通过先通过一个简单的小示例,来理解它的基本使用

假设有个用户配置类如下

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Data</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserConfig</span> {
    <span style="color:#75715e">/** 用户名*/</span>
    <span style="color:#f92672">private</span> String username;
    <span style="color:#75715e">/**手机号*/</span>
    <span style="color:#f92672">private</span> String phone;
}
</code></span></span>

我们通过实现ImportBeanDefinitionRegistrar的方式来完成注入。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">MyImportBean</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">ImportBeanDefinitionRegistrar</span> {

    <span style="color:#75715e">/**
     * <span style="color:#808080">@param</span> importingClassMetadata 当前类的注解信息
     * <span style="color:#808080">@param</span> registry               注册类,其registerBeanDefinition()可以注册bean
     */</span>
    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">registerBeanDefinitions</span><span style="color:#f8f8f2">(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)</span> {
        <span style="color:#75715e">//构建一个 BeanDefinition , Bean的类型为 UserConfig,这个Bean的属性username的值为后端元宇宙</span>
        <span style="color:#e6db74">AbstractBeanDefinition</span> <span style="color:#e6db74">beanDefinition</span> <span style="color:#ab5656">=</span> BeanDefinitionBuilder.rootBeanDefinition(UserConfig.class)
                .addPropertyValue(<span style="color:#e6db74">"username"</span>, <span style="color:#e6db74">"后端元宇宙"</span>)
                .getBeanDefinition();
        <span style="color:#75715e">//把 UserConfig 这个Bean的定义注册到容器中</span>
        registry.registerBeanDefinition(<span style="color:#e6db74">"userConfig"</span>, beanDefinition);
    }
}
</code></span></span>

通过配置类 中引入MyImportBean对象。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Import(MyImportBean.class)</span>
<span style="color:#75715e">@Configuration</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserImportConfiguration</span> {

}
</code></span></span>

我们再来测试下

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@EnableMyCache(type = CacheType.REDIS)</span>
<span style="color:#75715e">@SpringBootTest</span>
<span style="color:#75715e">@RunWith(SpringRunner.class)</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserServiceTest</span> {

    <span style="color:#75715e">@Autowired</span>
    <span style="color:#f92672">private</span> UserConfig userConfig;

    <span style="color:#75715e">@Test</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">test</span><span style="color:#f8f8f2">()</span> {
        <span style="color:#e6db74">String</span> <span style="color:#e6db74">username</span> <span style="color:#ab5656">=</span> userConfig.getUsername();
        System.out.println(<span style="color:#e6db74">"username = "</span> + username);
    }
}
</code></span></span>

控制台输出

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java">username = 后端元宇宙
</code></span></span>

说明通过ImportBeanDefinitionRegistrar方式,已经把UserConfig注入容器成功,而且还为给bean设置了新属性。

然后我们再来思考一个问题,就比如我们在其它地方已经将UserConfig注入容器,这里会不会出现冲突,或者不冲突的情况下,属性能不能设置成功?

我们来试下

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Import(MyImportBean.class)</span>
<span style="color:#75715e">@Configuration</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserImportConfiguration</span> {

    <span style="color:#75715e">/**
     * 这里通过<span style="color:#808080">@Bean</span>注解,将UserConfig注入Spring容器中,而且名称也叫userConfig
     */</span>
    <span style="color:#75715e">@Bean</span>
    <span style="color:#f92672">public</span> UserConfig <span style="color:#a6e22e">userConfig</span><span style="color:#f8f8f2">()</span> {
        <span style="color:#f92672">return</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">UserConfig</span>();
    }
}
</code></span></span>

然后我们再来跑下上面的测试用例,发现报错了。

2、举一个复杂点的例子

Mybatis的@MapperScan就是用这种方式实现的,@MapperScan注解,指定basePackages,扫描Mybatis Mapper接口类注入到容器中。

这里我们自定义一个注解@MyMapperScan来扫描包路径下所以带@MapperBean注解的类,并将它们注入到IOC容器中。

1)、先定义一个@MapperBean注解,就相当于我们的@Mapper注解

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">/**
 * 定义包路径。(指定包下所有添加了MapperBean注解的类作为bean)
 * 注意这里 <span style="color:#808080">@Import</span>(MyMapperScanImportBean.class) 的使用
 */</span>
<span style="color:#75715e">@Retention(RetentionPolicy.RUNTIME)</span>
<span style="color:#75715e">@Target(ElementType.TYPE)</span>
<span style="color:#75715e">@Documented</span>
<span style="color:#f92672">public</span> <span style="color:#75715e">@interface</span> MapperBean {
}
</code></span></span>

2)、一个需要注入的bean,这里加上@MapperBean注解。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">package</span> com.jincou.importselector.mapperScan;
<span style="color:#f92672">import</span> com.jincou.importselector.config.MapperBean;

<span style="color:#75715e">@MapperBean</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">User</span> {
}
</code></span></span>

3)、再定一个扫描包路径的注解@MyMapperScan 就相当于mybatis的@MapperScan注解。

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@Retention(RetentionPolicy.RUNTIME)</span>
<span style="color:#75715e">@Target(ElementType.TYPE)</span>
<span style="color:#75715e">@Documented</span>
<span style="color:#75715e">@Import(MyMapperScanImportBean.class)</span>
<span style="color:#f92672">public</span> <span style="color:#75715e">@interface</span> MyMapperScan {

   <span style="color:#75715e">/**
    * 扫描包路径
    */</span>
    String[] basePackages() <span style="color:#f92672">default</span> {};
}
</code></span></span>

4)、MyMapperScanImportBean实现ImportBeanDefinitionRegistrar接口

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">MyMapperScanImportBean</span> <span style="color:#f92672">implements</span> <span style="color:#a6e22e">ImportBeanDefinitionRegistrar</span>, ResourceLoaderAware {

    <span style="color:#f92672">private</span> <span style="color:#f92672">final</span> <span style="color:#f92672">static</span> <span style="color:#e6db74">String</span> <span style="color:#e6db74">PACKAGE_NAME_KEY</span> <span style="color:#ab5656">=</span> <span style="color:#e6db74">"basePackages"</span>;
    <span style="color:#f92672">private</span> ResourceLoader resourceLoader;
    
    <span style="color:#75715e">/**
     * 搜索指定包下所有添加了MapperBean注解的类,并且把这些类添加到ioc容器里面去
     * 
     * <span style="color:#808080">@param</span> importingClassMetadata 当前类的注解信息
     * <span style="color:#808080">@param</span> registry               注册类,其registerBeanDefinition()可以注册bean
     */</span>
    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">registerBeanDefinitions</span><span style="color:#f8f8f2">(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)</span> {
        <span style="color:#75715e">//1. 从BeanIocScan注解获取到我们要搜索的包路径</span>
        <span style="color:#e6db74">AnnotationAttributes</span> <span style="color:#e6db74">annoAttrs</span> <span style="color:#ab5656">=</span> AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MyMapperScan.class.getName()));
        <span style="color:#f92672">if</span> (annoAttrs == <span style="color:#ae81ff">null</span> || annoAttrs.isEmpty()) {
            <span style="color:#f92672">return</span>;
        }
        String[] basePackages = (String[]) annoAttrs.get(PACKAGE_NAME_KEY);
        <span style="color:#75715e">// 2. 找到指定包路径下所有添加了MapperBean注解的类,并且把这些类添加到IOC容器里面去</span>
        <span style="color:#e6db74">ClassPathBeanDefinitionScanner</span> <span style="color:#e6db74">scanner</span> <span style="color:#ab5656">=</span> <span style="color:#f92672">new</span> <span style="color:#a6e22e">ClassPathBeanDefinitionScanner</span>(registry, <span style="color:#ae81ff">false</span>);
        scanner.setResourceLoader(resourceLoader);
        <span style="color:#75715e">//路径包含MapperBean的注解的bean</span>
        scanner.addIncludeFilter(<span style="color:#f92672">new</span> <span style="color:#a6e22e">AnnotationTypeFilter</span>(MapperBean.class));
        <span style="color:#75715e">//扫描包下路径</span>
        scanner.scan(basePackages);
    }

    <span style="color:#75715e">@Override</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">setResourceLoader</span><span style="color:#f8f8f2">(ResourceLoader resourceLoader)</span> {
        <span style="color:#e6db74">this</span>.resourceLoader = resourceLoader;
    }
}
</code></span></span>

5)测试

这里扫描的路径就是上面User实体的位置

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#75715e">@RunWith(SpringRunner.class)</span>
<span style="color:#75715e">@SpringBootTest</span>
<span style="color:#75715e">@MyMapperScan(basePackages = {"com.jincou.importselector.mapperScan"})</span>
<span style="color:#f92672">public</span> <span style="color:#f92672">class</span> <span style="color:#a6e22e">UserServiceTest</span> {

    <span style="color:#75715e">@Autowired</span>
    <span style="color:#f92672">private</span> User user;

    <span style="color:#75715e">@Test</span>
    <span style="color:#f92672">public</span> <span style="color:#f92672">void</span> <span style="color:#a6e22e">test</span><span style="color:#f8f8f2">()</span> {
        System.out.println(<span style="color:#e6db74">"username = "</span> + user.getClass().getName());
    }
}
</code></span></span>

运行结果

<span style="color:#4b4b4b"><span style="background-color:#ffffff"><code class="language-java">username = com.jincou.importselector.mapperScan.User
</code></span></span>

完美,成功!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/33355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TMD,JVM类加载原来是这样的!!!!

接上篇&#xff1a;https://boxuegu.blog.csdn.net/article/details/128000217 通过字节码&#xff0c;我们了解了class文件的结构 通过运行数据区&#xff0c;我们了解了jvm内部的内存划分及结构 接下来&#xff0c;让我们看看&#xff0c;字节码怎么进入jvm的内存空间&…

电脑硬盘分区软件哪个好用,无损分区软件哪个好

为了合理地利用磁盘空间&#xff0c;会进行磁盘分区的操作。由于磁盘分区涉及到计算机相关的操作知识&#xff0c;很多的用户都不会。所以&#xff0c;只能借助于专业的磁盘分区工具&#xff0c;那么&#xff0c;电脑硬盘分区软件哪个好用&#xff1f;在本文中&#xff0c;易我…

走进常熟东南相互电子,看AI如何深入产业让工厂更智能

苏州常熟一家4万多平方米的生产车间内&#xff0c;一块块指甲盖大小的PCB电路板&#xff0c;在装有人工智能算法模型的的摄像头下&#xff0c;快速精准地完成外观检测&#xff0c;让头发丝大小的瑕疵无处可藏。 成立于2006年的东南相互电子&#xff0c;是一家集半导体与元器件…

ActiveMQ 反序列化漏洞(CVE-2015-5254)特征分析

介绍 Apache ActiveMQ是美国阿帕奇&#xff08;Apache&#xff09;软件基金会所研发的一套开源的消息中间件&#xff0c;它支持Java消息服务、集群、Spring Framework等。 Apache ActiveMQ 5.13.0之前5.x版本中存在安全漏洞&#xff0c;该漏洞源于程序没有限制可在代理中序列…

Flutter高仿微信-第37篇-单聊-红包

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 详情请参考 Flutter高仿微信-第29篇-单聊 &#xff0c; 这里只是提取红包功能的…

第二章:Pythonocc官方demo 案例47(获取物体的最优的包容体)

源代码&#xff1a; #!/usr/bin/env python ## ##This file is part of pythonOCC. ## ##pythonOCC is free software: you can redistribute it and/or modify ##it under the terms of the GNU Lesser General Public License as published by ##the Free Software Foundati…

Hadoop笔记-02 安装

文章目录1 VBOX安装CentOS71.1 安装VBOX软件1.2 下载CentOS7镜像文件1.3 初始化VBOX虚拟盘1.4 CentOS7网络配置1.5 CentOS7 yum源配置1.6 CentOS7 一般配置1.6.1关闭防火墙1.6.2 修改hostname1.6.3 配置DNS绑定1.6.4 关闭selinux2 JDK等基础安装配置2.1 安装JDK前检查2.2 安装t…

《Happy Birthday》游戏开发记录(送给朋友的小礼物)

游戏开发的学习记录⑦ 项目&#xff1a;Happy Birthday &#xff08;一个小小小游戏&#xff0c;基于unity给朋友做的一个生日小礼物&#x1f381;&#xff0c;之前都是礼物加信&#x1f48c;&#xff0c;今年想用自己的技能&#xff0c;把信的内容以另一种方式送给她。但在做…

STM32实战总结:HAL之modbus

什么是modbus&#xff1f; Modbus是一种串行通信协议&#xff0c;是Modicon公司&#xff08;现在的施耐德电气 Schneider Electric&#xff09;于1979年为使用可编程逻辑控制器&#xff08;PLC&#xff09;通信而发表。Modbus已经成为工业领域通信协议的业界标准&#xff08;De…

OsgEarth3基础3D图形实现

OsgEarth3基础3D图形实现主要难点Geometry能力姿态支持任意立方体 PolygonCube矩形立方体 Box圆锥体 Cone圆柱体 Cylinder四棱锥 Pyramid球体 Sphere源码示例ElementGeometry圆锥Cone这里尝试在通过OsgEarth提供的各种图形绘制方法&#xff0c;实现基础的3D图形。每个图形除了基…

推荐一个非常实用的程序员导航网站,码农必备!

这是一个非常好用的程序员导航网站&#xff0c;拥有该网站&#xff0c;就拥有一站式导航&#xff0c;再也不用为找网址而发愁了&#xff01; 先直接上网址&#xff1a;https://hao.panziye.com/ 现在来说说为什么推荐该程序员导航网站&#xff01; 1、支持自定义导航网址 该…

pytorch的安装教程

1. 官网 pytorch.org 哎呀呀呀&#xff0c;这是嘛呀哪里有download的按钮啊 别急 &#xff0c;往下拉就ok了哈哈 得看你自己电脑的配置了&#xff0c;自己选就行 、、注意哦 我们得复制一条指令 、 有anaconda的吧 在自己想要的环境里面 黏贴就行 有了 pytorch 可以干嘛呢…

Electron:BrowserView使用方法

我们知道&#xff0c;使用BrowserWindow来创建一个新的窗口&#xff0c;那么如果想在窗口中战胜斯更多的web内容&#xff0c;比如嵌入其他网站的内容&#xff0c;那就使用BrowserView了。 BrowserView的位置是相对于父窗口&#xff0c;比如&#xff1a; 代码如下&#xff1a;…

python项目使用pyinstaller打包

一、安装pyinstaller 打包要使用pyinstaller,使用pip来安装一下这个第三方库,打开命令行输入pip install pyinstaller 二、打包含有多个文件的python项目 1、首先打开电脑的cmd命令行,并切换到项目的根目录 项目路径输入cmd回车,可直接打开含有项目路径的cmd窗口 2、…

【推荐系统】行列式点过程(DPP)算法推导

一、背景 推荐系统主要解决用户和物品之间的相关性&#xff0c;以及推荐列表的多样性。相关性主要通过用户兴趣和物品之间的匹配程度来衡量&#xff0c;希望把用户感兴趣的物品推荐给用户&#xff0c;可以通过CTR预估模型来构建。多样性的衡量没有那么直观&#xff0c;一种方法…

std::unique_ptr(基础和仿写)

目录 一、C参考手册说明 1、解释注释 2、 参考代码 二、对std::unique_ptr分析 1、创建一个unique_ptr 2、无法进行复制构造和赋值操作 3、可以进行移动赋值 4.可以返回unique——ptr 5、管理动态数组 6、在容器中保存指针 三、对std::unique_ptr设计 1、对于的那个…

关于生命周期的面试题vue

1.第一次进入到页面&#xff08;组件&#xff09;会执行哪些生命周期 beforeCreate 》 没有data&#xff0c;没有elcreated 》 有data&#xff0c;没有elbeforeMount 》 有data&#xff0c;没有el&#xff08;其实已经在准备了&#xff09;mounted 》 有data&#xff0c;有el …

SRM供应商管理系统有什么作用?

目前国内稍具规模的企业都导入了企业资源管理ERP系统&#xff0c;实现了内部管理数字化转型&#xff0c;提升了内部各部门之间的协同能力。但是企业供应链管理涉及大量的外部资源&#xff0c;特别是数量庞大的供应商资源&#xff0c;而大部分的ERP系统很难实现采购同供应商之间…

感恩节,感谢2022的转变,有在好好生活!

疫情之下的感恩节 原来今天是感恩节。2022年快要结束了&#xff0c;在这样一个特别的节日里&#xff0c;就不写技术类文章了&#xff0c;写一写我的2022年&#xff0c;这一年&#xff0c;我的学习、工作和生活都有发生改变&#xff0c;感谢过去的时光&#xff0c;改变让我有在…

Linux下:文件与路径、用户管理、常用命令、vim

文章目录第一章&#xff1a; Linux文件与路径1.1 文件结构1.2 基本概念1.3 基本命令信息1.3.1 查看linux 系统信息&#xff08;修改主机名&#xff09;1.3.2 ls1.3.3 cd/pwd1.3.4 pushd命令创建目录栈 第二章&#xff1a; 文件/目录的创建、删除、复制、阅读2.1 mkdir2.2 touc…