Spring组件的注册方式
- 前言
- Bean的几种注册方式
- 1.xml方式注册
- 2.@Configuration ,@bean方式注册
- 3.xml包扫描注册
- 4.@Import注册
- 5.使用spring提供的FactoryBean(工厂Bean)
- 相关注解
- 1.@Scope注解设置组件作用域
- 2.@Lazy注解实现单实例懒加载
- 3.@Conditional按条件注册
- end...
前言
首先,感谢尚硅谷等平台,让我白嫖学习到了很多。毕业后一直想快速提升自己,看了很多平台的课程, 因为没有做笔记,看过的课程忘记的很快,因此,今后的学习都会在csdn上做做笔记,加深印象的同时也方便自己回顾。
Bean的几种注册方式
1.xml方式注册
注册:
<bean id="person" class="com.atgugui.bean.Person">
<property name="age" value="22"></property>
<property name="name" value="zx"></property>
</bean>
获取:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person) applicationContext.getBean("person");
2.@Configuration ,@bean方式注册
注册:
@Configuration // 告诉Spring这是一个配置类
public class MainConfig {
// @Bean注解是给IOC容器中注册一个bean,类型自然就是返回值的类型,id默认是用方法名作为id
@Bean
public Person person() {
return new Person("zx", 22);
}
}
获取:
// MainConfig:配置类,Person:注入类,可通过applicationContext 获取id等注入信息
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = applicationContext.getBean(Person.class);
3.xml包扫描注册
包扫描:只要是标注了@Controller、@Service、@Repository、@Component其中任意一个注解
注册:
<context:component-scan base-package="com.zx.**"></context:component-scan>
此配置可在配置类(标注@Configuration )中替换为@ComponentScan(value = “com.zx.**”) 此注解还可配置只包含、排除等,只包含需关闭自动配置(useDefaultFilters=false),例如:
@ComponentScan(value=“com.meimeixia”, excludeFilters={
/*
* type:指定排除的规则,有按照注解进行排除,按照给定的类型进行排除、按照正则表达式进行排除、按照自定义规则等
* classes:例子中是排除@Controller和@Service标注的组件
*/
@Filter(type=FilterType.ANNOTATION, classes={Controller.class, Service.class})
// 只要是BookService类型的组件都会被加载到容器中,包括子类
@Filter(type=FilterType.ASSIGNABLE_TYPE, classes={BookService.class})
}, useDefaultFilters=false)
// 自定义规则,指定实现的自定义类
@Filter(type=FilterType.CUSTOM, classes={MyTypeFilter.class})
}, useDefaultFilters=false) // value指定要扫描的包
})public class MyTypeFilter implements TypeFilter {
/**
* 参数:
* metadataReader:读取到的当前正在扫描的类的信息
* metadataReaderFactory:可以获取到其他任何类的信息的(工厂)
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类的资源信息,类的路径
Resource resource = metadataReader.getResource();
// 获取当前正在扫描的类的类名
String className = classMetadata.getClassName();
// 指定规则
if (className.contains("er")) {
return true; // 匹配成功,包含在容器中
}
return false; // 匹配不成功,排除
}
}
获取:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
String[] definitionNames =applicationContext.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
// 结果,spring自身组件+加了@controller等注解的类
4.@Import注册
@import用于快速向容器中导入一个组件,id默认是组件的全类名
例子
@Configuration
@Import(Color.class)
public class MainConfig {
}
ImportSelector接口导入bean
例子
/**
* 自定义逻辑,返回需要导入的组件
* @author liayun
*
*/
public class MyImportSelector implements ImportSelector {
// 返回值:导入到容器中的组件的全类名
// AnnotationMetadata:当前标注@Import注解的类的所有注解信息,不仅能获取到@Import注解里面的信息,还能获取到其他注解的信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 方法不能返回null值,否则会报空指针异常,可以返回一个空数组
//return new String[]{};
// 返回需要的组件
return new String[]{"com.zx.bean.CS", "com.zx.bean.GO"};
}
}
-----------------------------分隔线---------------------------------
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class})
public class MainConfig {
@Bean("***")
···
}
ImportBeanDefinitionRegistrar接口导入bean
例子
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类
*
* 我们可以通过调用BeanDefinitionRegistry接口中的registerBeanDefinition方法,手动注册需要添加到容器中的bean
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition1 = registry.containsBeanDefinition("com.zx.bean.Red");
boolean definition2 = registry.containsBeanDefinition("com.zx.bean.Bule");
if (definition1 && definition2) {
// 指定bean的定义信息 (包括bean的类型、作用域等等)
RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); // bean的定义信息
// 注册一个bean,指定bean的名称
registry.registerBeanDefinition("rainBow", beanDefinition);
}
}
}
-----------------------分隔线------------------------
@Configuration
@Import({Color.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
}
5.使用spring提供的FactoryBean(工厂Bean)
通过实现FactoryBean,实现相关方法完成bean的注册
注册
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
// 返回一个Color对象
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class; // 返回Class
}
// return true,单实例,在容器中只会保存一份;
// return false,多实例,每次获取都会创建一个新的bean
@Override
public boolean isSingleton() {
return false;
}
}
-------------------------分隔线--------------------------
@Bean
public ColorFactoryBean colorFactoryBean() {
return new ColorFactoryBean();
}
获取
如要在Spring容器中获取到FactoryBean对象本身,可以加上&,如 Object bean = applicationContext.getBean("&colorFactoryBean");
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
// 获取的bean是调用getObject方法创建的对象(Color)
Object bean2 = applicationContext.getBean("colorFactoryBean");
Object bean3 = applicationContext.getBean("colorFactoryBean");
// 获取FactoryBean对象本身
Object bean = applicationContext.getBean("&colorFactoryBean");
相关注解
1.@Scope注解设置组件作用域
ConfigurableBeanFactory#SCOPE_PROTOTYPE (多实例的)
ConfigurableBeanFactory#SCOPE_SINGLETON (默认值:单实例的)
org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST (同一次请求创建一个实例)
org.springframework.web.context.WebApplicationContext#SCOPE_SESSION (同一个session创建一个实例)
prototype:多实例的,IOC容器启动不会去调用方法创建对象放在容器中,每次获取的时候才去调用方法创建对象
singleton:但实例的,IOC容器启动会调用方法创建对象放到IOC容器中,以后每次获取就是直接从容器 nap.get() 中拿
例子
@Scope("prototype") 单实例
@Bean("person")
public Person person() {
return new Person("zx", 22);
}
2.@Lazy注解实现单实例懒加载
懒加载:又称延时加载,仅针对单实例bean生效。 单实例bean,默认在Spring容器启动的时候就加载,添加@Lazy注解后就会延迟加载,在Spring容器启动的时候并不会加载,而是在第一次使用bean的时候才会创建。
例子
@Lazy
@Bean("person")
public Person person() {
return new Person("zx", 22);
}
3.@Conditional按条件注册
spring4.0后新增,可以标注在类上和方法上,在springBoot中大量使用。
参数:Class<? extends Condition>[] value(); 继承codition的类数组
例子
public class LinuxCondition implements Condition {
/**
* ConditionContext:判断条件能使用的上下文(环境)
* AnnotatedTypeMetadata:当前标注了@Conditional注解的注释信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 判断操作系统是否是Linux系统
// 1. 获取到bean的创建工厂(能获取到IOC容器使用到的BeanFactory,它就是创建对象以及进行装配的工厂)
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2. 获取到类加载器
ClassLoader classLoader = context.getClassLoader();
// 3. 获取当前环境信息,它里面就封装了我们这个当前运行时的一些信息,包括环境变量,以及包括虚拟机的一些变量
Environment environment = context.getEnvironment();
// 4. 获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("linux")) {
return true;
}
return false;
}
------------------------分隔线---------------------------
@Conditional({LinuxCondition.class})
@Bean("linus")
public Person person02() {
return new Person("linus", 48);
}
end…