用注解的方式將一個對象交給Spring來管理架专,有三種做法:
1、@Bean
2玄帕、@Componet(@Service部脚、@Configuration等歸為一類)
3、@Import
這里主要講第三種做法裤纹,打開Spring源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
@Import注解只有一個value方法委刘,注釋中指明該注解必須作用于@Configuration定義的類上丧没,value可以為想要交給Spring管理的類文件數(shù)組、ImportSelector或ImportBeanDefinitionRegistrar锡移,接下來我們依次執(zhí)行三種做法
- 1呕童、指定class數(shù)組
首先定義兩個類
public class Apple {
}
public class Banana {
}
然后定義配置類,并用@Import注解裝飾淆珊,輸入兩個自定義類
import com.lwl.entity.Apple;
import com.lwl.entity.Banana;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({Apple.class, Banana.class})
public class AppConfig {
}
測試類中打印容器中類的名稱
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
for (String s : applicationContext.getBeanDefinitionNames()) {
System.out.println(s);
}
}
}
輸出結(jié)果中可以看到Apple和Banana都被成功注入:
- 2夺饲、實現(xiàn)ImportSelector接口
定義一個新的實體,需求是通過ImportSelector將其注入Spring容器
public class Berry {
}
自定義selector實現(xiàn)ImportSelector接口施符,在方法中返回自定義的類路徑往声,Spring會自動將該路徑下的類注入到容器中
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class BerryImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.lwl.entity.Berry"};
}
}
修改配置代碼,在@Import中加入BerryImportSelector :
@Configuration
@Import({Apple.class, Banana.class, BerryImportSelector.class})
public class AppConfig {
}
測試代碼不變戳吝,打印結(jié)果:
Berry確實被注入進來了
- 3浩销、實現(xiàn)ImportBeanDefinitionRegistrar接口
再定義一個新的實體:
public class Tomato {
}
創(chuàng)建TomatoRegistrar實現(xiàn)ImportBeanDefinitionRegistrar接口,在方法當中將類注冊到容器里骨坑,并將beanName修改為MyTomato:
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class TomatoRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(Tomato.class);
beanDefinitionRegistry.registerBeanDefinition("MyTomato", beanDefinition);
}
}
修改AppConfig代碼撼嗓,將TomatoRegistrar放入@Import中:
@Configuration
@Import({Apple.class, Banana.class, BerryImportSelector.class, TomatoRegistrar.class})
public class AppConfig {
}
測試結(jié)果:
總結(jié)
在平時的業(yè)務(wù)開發(fā)當中,將對象放入容器欢唾,使用@Bean和@Compont基本就能夠滿足需求,但是@Import注解能夠方便擴展功能粉捻,舉例:
- 1礁遣、控制類注入時機
我希望能夠通過一個簡單的開關(guān)來控制是否注入Berry類,我們可以定義一個注解
import org.springframework.context.annotation.Import;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Import({BerryImportSelector.class})
public @interface EnableBerry {
}
修改@AppConfig肩刃,刪除@Import中的BerryImportSelector.class祟霍,
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({Apple.class, Banana.class, TomatoRegistrar.class})
public class AppConfig {
}
這時候運行測試,發(fā)現(xiàn)Berry沒有被注入到容器中:
如果在AppConfig類加上@EnableBerry注解
@Configuration
@Import({Apple.class, Banana.class, TomatoRegistrar.class})
@EnableBerry
public class AppConfig {
}
再次執(zhí)行測試盈包,Berry成功注入:
SpringCloud中的@EnableEureka沸呐、@EnableDiscoveryClient就是利用這個原理
- 2、通過代理來改變bean定義
Spring-Mybatis的@MapperScan注解呢燥,是由@Import注解所修飾崭添,并注入了MapperScannerRegistrar類:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({MapperScannerRegistrar.class})
public @interface MapperScan {
它在registerBeanDefinitions方法中掃描了基礎(chǔ)包,
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
scanner.doScan(StringUtils.toStringArray(basePackages));
}
然后提取mapper產(chǎn)生代理類叛氨,最后注冊到容器當中