網(wǎng)站首頁 編程語言 正文
一、注入方式
向Spring容器中注入Bean的方法很多,比如:
- 利用
<Bean>...<Bean>
Xml文件描述來注入 - 利用JavaConfig的
@Configuration
和@Bean
注入 - 利用springboot的自動(dòng)裝配,即實(shí)現(xiàn)
ImportSelector
來批量注入 - 利用
ImportBeanDefinitionRegistrar
來實(shí)現(xiàn)注入
二、@Enable注解簡介
我們常常使用@EnableScheduling
、@EnableWebMvc
等,@Enable
注解的主要作用就是利用@Import
注解來實(shí)現(xiàn)IoC對象注入,比如Spring自帶的@EnableScheduling
,分析一下:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({SchedulingConfiguration.class})
@Documented
public @interface EnableScheduling {
}
可以看到其實(shí)就是導(dǎo)入了一個(gè)配置類@Import({SchedulingConfiguration.class})
,
@Configuration(proxyBeanMethods = false)
@Role(2)
public class SchedulingConfiguration {
public SchedulingConfiguration() {
}
@Bean(name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"})
@Role(2)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
return new ScheduledAnnotationBeanPostProcessor();
}
}
這里就是用的@Configuration
和@Bean
注入。
再例如springboot啟用類注解@SpringBootApplication
里面的@EnableAutoConfiguration
:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
@AliasFor(annotation = EnableAutoConfiguration.class)
Class<?>[] exclude() default {};
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
/**
* Environment property that can be used to override when auto-configuration is
* enabled.
*/
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
其實(shí)就是AutoConfigurationImportSelector
類來實(shí)現(xiàn)了自動(dòng)裝配的邏輯。
三、利用ImportBeanDefinitionRegistrar接口來裝配
本文講的是ImportBeanDefinitionRegistrar
接口結(jié)合@Enable
注解來實(shí)現(xiàn)注入:
首先我們要自己寫一個(gè)@Enable
注解@EnableMyBean
:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MyDeanDefinitionRegister.class)
public @interface EnableMyBean {
}
寫出我們的待注入對象:
public class MyBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "MyBean{" +
"name='" + name + '\'' +
'}';
}
}
編寫@Import
的類MyDeanDefinitionRegister(實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口):
public class MyDeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(MyBean.class);
String className = MyBean.class.getName();
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("name", "lisi");
//添加屬性
rootBeanDefinition.setPropertyValues(propertyValues);
//注入到spring容器
registry.registerBeanDefinition(className, rootBeanDefinition);
}
}
springboot啟動(dòng)類,加上我們自己寫的注解:
@SpringBootApplication
@EnableMyBean
public class Applicaiton {
public static void main(String[] args) {
SpringApplication.run(Applicaiton.class, args);
}
}
寫個(gè)單元測試:
@SpringBootTest
class Test1 {
@Autowired
MyBean bean;
@Autowired
ApplicationContext applicationContext;
@Test
void test1() {
System.out.println(bean);
}
}
結(jié)果如下:
MyBean{name='lisi'}
可見我們已經(jīng)成功將MyBean注入到Spring容器了。
四、帶條件的注入方式
假設(shè)我們有以下批量注入需求(同時(shí)滿足一下條件)才能注入:
1、要求把某個(gè)包下的類都加到容器
2、要加一個(gè)自定義注解,只有在這個(gè)包下加了自定義注解的才能被加到容器!
首先注解上面加入?yún)?shù):
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MyDeanDefinitionRegister.class)
public @interface EnableMyBean {
String[] basePackages() default {};
}
再寫一個(gè)自定義的條件注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Meeting {
}
啟動(dòng)類修改,添加包掃描:
@SpringBootApplication
@EnableMyBean(basePackages = {"com.my.test.meeting"})
public class Applicaiton {
public static void main(String[] args) {
SpringApplication.run(Applicaiton.class, args);
}
}
待注入的類:
@Meeting
public class Money {
}
@Meeting
public class Work {
}
//這個(gè)類就不加@Meeting注解了,不想它加入到容器,太狗了
public class Dog {
}
修改類MyDeanDefinitionRegister(實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口)邏輯:
public class MyDeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//獲取@EnableMyBean注解的屬性
Map<String, Object> attributes = importingClassMetadata.getAnnotationAttributes(EnableMyBean.class.getName());
//獲取包掃描
ClassPathScanningCandidateComponentProvider pathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false);
//添加過濾,帶有@Meeting注解的類
pathScanningCandidateComponentProvider.addIncludeFilter(new AnnotationTypeFilter(Meeting.class));
String[] basePackages = (String[]) attributes.get("basePackages");
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//選擇該包下的
candidateComponents.addAll(pathScanningCandidateComponentProvider.findCandidateComponents(basePackage));
}
//注入Bean
for (BeanDefinition candidateComponent : candidateComponents) {
registry.registerBeanDefinition(candidateComponent.getBeanClassName(), candidateComponent);
}
}
//如果想要掃描到接口,則需要調(diào)用該方法獲取掃描器
private ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
boolean isCandidate = false;
if (beanDefinition.getMetadata().isIndependent()) {
if (!beanDefinition.getMetadata().isAnnotation()) {
isCandidate = true;
}
}
return isCandidate;
}
};
}
}
單元測試一下:
@SpringBootTest
class Test1 {
@Autowired
ApplicationContext applicationContext;
@Test
void test1() {
Arrays.stream(applicationContext.getBeanDefinitionNames()).forEach(System.out::println);
}
}
結(jié)果:
com.my.test.meeting.Money
com.my.test.meeting.Work
可以看到Money、Work都成功注入了,而沒有Dog,因?yàn)樗鼪]有@Meeting注解
五、直接利用beanFactory注入
這里作為額外補(bǔ)充:
public class Compont2
{
}
@Component
public class ContextAware implements ApplicationContextAware {
@Autowired
private DefaultListableBeanFactory beanFactory;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Class<Compont2> c2 = Compont2.class;
beanFactory.createBean(c2);
String name = c2.getName();
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(c2);
beanFactory.registerBeanDefinition(name, beanDefinitionBuilder.getBeanDefinition());
}
}
至此已經(jīng)注入完畢,可以被依賴了:
@Component
public class ContextInitializingBean1 implements InitializingBean {
@Autowired
private Compont2 compont2;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("ContextInitializingBean1 " + compont2);
}
}
原文鏈接:https://rabbit.blog.csdn.net/article/details/130133788
- 上一篇:沒有了
- 下一篇:沒有了
相關(guān)推薦
- 2022-04-26 使用jquery庫實(shí)現(xiàn)電梯導(dǎo)航效果_jquery
- 2022-09-07 詳解利用Pandas求解兩個(gè)DataFrame的差集,交集,并集_python
- 2022-04-28 Pytorch中torch.flatten()和torch.nn.Flatten()實(shí)例詳解_pyt
- 2023-04-19 微信小程序授權(quán)登錄三種實(shí)現(xiàn)方式
- 2023-01-08 基于C#實(shí)現(xiàn)屏幕取色器的示例詳解_C#教程
- 2022-10-26 jQuery?基礎(chǔ)選擇器與屬性選擇器_jquery
- 2022-11-08 Python?運(yùn)算符Inplace?與Standard?_python
- 2023-04-02 Python使用conda如何安裝requirement.txt的擴(kuò)展包_python
- 欄目分類
-
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支