代码地址
spring01
觉得博主还可以给个Star
1.@Import的使用
在com.entity下创建UserEntity.java
package com.entity;
public class UserEntity {
}
com.config下创建MyConfig.java
package com.config;
import com.entity.UserEntity;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(UserEntity.class)
public class MyConfig {
}
com下创建Application.java
package com;
import com.config.MyConfig;
import com.entity.UserEntity;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
UserEntity userEntity = applicationContext.getBean("userEntity", UserEntity.class);
System.out.println(userEntity);
}
}
测试代码如上,运行结果:
我们会发现,我们的操作步骤和昨天差不多,但是却会报错出“没有找到‘UserEntity’对象”,接下来,我们把注入的bean名称全部打印出来
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println(beanDefinitionNames[i]);
}
运行结果:
我们会发现它的bean名称为“com.entity.UserEntity”,这时候我们才能发现,与我们寻常使用注解注入bean的名字不同,它注入的名称是全路径,所以我们的代码应该改为
UserEntity userEntity = applicationContext.getBean("com.entity.UserEntity", UserEntity.class);
这样运行的结果就没有任何问题了
2.@EnableXXX
我们见过很多的Enable开头的注解,比如@EnableScheduling,@EnableAsync等等,我们可以进去看看,它们的内部是怎样的
我们都可以看到一个很熟悉的身影@Import,是的,他就是核心,主要就是为了导入外部的类
3.FactoryBean
FactoryBean表示往IOC容器存储(注入对象),BeanFactory表示从IOC容器中获取对象
com.entity创建FactoryBeanEntity.java
package com.entity;
public class FactoryBeanEntity {
}
com.config创建FactoryBeanConfig.java并且实现接口FactoryBean
package com.config;
import com.entity.FactoryBeanEntity;
import org.springframework.beans.factory.FactoryBean;
public class FactoryBeanConfig implements FactoryBean<FactoryBeanEntity> {
@Override
public FactoryBeanEntity getObject() throws Exception {
return new FactoryBeanEntity();
}
@Override
public Class<?> getObjectType() {
return FactoryBeanEntity.class;
}
@Override
public boolean isSingleton() {
// 是否为单例 true为单例 false 为多例
return true;
}
}
在MyConfig.java中的@Import加入“FactoryBeanConfig.class”
下面我们测试一下是否注入成功
Application.java加入代码
FactoryBeanEntity factoryBeanEntity = applicationContext.getBean("factoryBeanEntity", FactoryBeanEntity.class);
System.out.println(factoryBeanEntity);
运行结果:
与第一个知识点一样,也报错没有找到bean,那么我们把所有的beanName打印出来
发现我们里面并没有“factoryBeanEntity”,而是只出现了“com.config.FactoryBeanConfig”
那我们从“com.config.FactoryBeanConfig”去一探究竟,更改一下代码
// 此处打断点
Object factoryBeanConfig = applicationContext.getBean("com.config.FactoryBeanConfig");
System.out.println(factoryBeanConfig);
我们会发现
这样就明了了,原来注入的名字是“com.config.FactoryBeanConfig”,而对应的对象是“FactoryBeanEntity”,那么我们就可以直接强转类型试试
FactoryBeanEntity factoryBeanConfig = (FactoryBeanEntity)applicationContext.getBean("com.config.FactoryBeanConfig");
System.out.println(factoryBeanConfig);
结果是可以强转为FactoryBeanEntity,说明FactoryBeanEntity注入成功
4.@Conditional的使用
@Conditional我们主要用于条件注册,比如我们在不同的操作系统中,要使用不同的bean
com.config下创建ConditionConfig.java实现Condition接口
package com.config;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class ConditionConfig implements Condition {
/**
*
* @param conditionContext 获取当前上下文
* @param annotatedTypeMetadata 获取当前注解的信息
*/
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取当前系统环境
Environment environment = conditionContext.getEnvironment();
String osName = environment.getProperty("os.name");
if(osName.equals("Windows 10")){
// 注册
return true;
}
// 不进行注册
return false;
}
}
com.entity创建Win10Entity.java
package com.entity;
public class Win10Entity {
}
MyConfig.java
package com.config;
import com.entity.UserEntity;
import com.entity.Win10Entity;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@Configuration
//@EnableAsync
//@EnableScheduling
@Import({
UserEntity.class,FactoryBeanConfig.class})
public class MyConfig {
@Bean
@Conditional(ConditionConfig.class)
public Win10Entity win10Entity(){
return new Win10Entity();
}
}
运行并打印所有beanName
就这样,我们可以实现通过@Conditional控制对象在 不同环境下的注册
5.ImportSelector接口使用
ImportSelector选择性注册bean
com.entity创建Select01Entity.java
package com.entity;
public class Select01Entity {
}
com.config创建ImportSelectorConfig并实现接口ImportSelector
package com.config;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class ImportSelectorConfig implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{
"com.entity.Select01Entity"};
}
}
打印除所有的beanName,可以发现“com.entity.Select01Entity”注入成功
5.ImportBeanDefinitionRegistrar使用
com.config包下创建ImportBeanDefinitionRegistrarConfig.java并且实现接口ImportBeanDefinitionRegistrar
package com.config;
import com.entity.SmsEntity;
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;
import org.springframework.stereotype.Component;
public class ImportBeanDefinitionRegistrarConfig implements ImportBeanDefinitionRegistrar {
/**
* @param annotationMetadata 注解信息
* @param beanDefinitionRegistry bean的基本信息
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
// 手动注册信息到ioc
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(SmsEntity.class);
beanDefinitionRegistry.registerBeanDefinition("smsEntity",rootBeanDefinition);
}
}
在MyConfig.java的@Import加入ImportBeanDefinitionRegistrarConfig.class即可
问题思考
- Spring IOC线程是否安全
- @Service和@Component区别
- @Primary和@Qualifier区别
1.SpringIOC线程安全,底层通过beanDefinitionMap存放
2.两个注解底层相同,只为写的时候更好区分
3.两者使用在有个实现类均用一个接口的情况,@Qualifier指定使用实现类,@Primary指定两个实现类优先使用某个实现类