基于XML配置的方式
先注册一个Bean
<bean id="person" class="com.EzerbelCN.bean.Person">
<property name="id" value="1"></property>
<property name="name" value="Lilith"></property>
<property name="gender" value="1"></property>
</bean>
然后取出实例
@Test
public void test01() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = (Person)context.getBean("person");
System.out.println(person);
context.close();
}
使用@Configuration注册配置类
//配置类==配置文件
@Configuration
public class MainConfig {
//给容器中注册一个Bean;类型为返回值类型,id默认为方法名
@Bean
public Person person() {
return new Person(2,"Jerry",1);
}
//-------------------------使用别名-------------------------
@Bean("car01")
public Car car() {
return new Car("Farrari", 9999f);
}
}
使用应用的注解配置上下文来获得注册的Bean实例:
@Test
public void test02() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = (Person)context.getBean("person");
System.out.println(person);
Car car = (Car)context.getBean("car01");
System.out.println(car);
context.close();
}
-
使用ComponentScan来指定扫描范围
type=FilterType.ANNOTATION 按照注解类型进行过滤
useDefaultFilters=false 不使用默认的过滤器
@Configuration
@ComponentScan(value="com.EzerbelCN",includeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
},useDefaultFilters=false)
public class MainConfig {
//给容器中注册一个Bean;类型为返回值类型,id默认为方法名
@Bean
public Person person() {
return new Person(2,"Jerry",1);
}
//使用别名
@Bean("car01")
public Car car() {
return new Car("Farrari", 9999f);
}
}
ComponentScan属于可重复注解:

因此可以使用多个@ComponentScan,增加不同的扫描策略,也可以使用ComponentScans:

按不同FilterType进行过滤
a) 按照注解类型扫描:

b) 按照可赋值类型进行过滤:(所有CarService类型的Bean都会被扫描)

c) 使用正则表达式:略
d) 使用自定义方式:

实现TypeFilter接口
package com.EzerbelCN.config;
import java.io.IOException;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
public class MyTypeFilter implements TypeFilter {
/**
*@param metadataReader : 读取到的当前正在扫描类的信息
*@param metadataReaderFactory: a factory for obtaining metadata readers for other classes (such as super classes and interfaces)
*
*/
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();
System.out.println("MyTypeFilter 正在 match ------> " + className);
if(className.contains("car")) {return true;}
return false;
}
}
设置组件的作用域
Bean默认是单实例的,使用@Scope进行相关配置

测试一下,单实例和多实例分别是在何时创建组件?
结果:

懒加载
经过前面测试,可以发现实例模式下,默认是在容器启动时创建实例,可以使用@Lazy懒加载,使之在第一次获取时再创建和初始化。
使用@Conditional按条件注册
0.可以放在方法头部或者类的头部,无论哪个位置都要实现Condition接口:
package com.EzerbelCN.condition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
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 LinuxCondition implements Condition {
/**
* context 判断条件能使用的上下文环境
* metadata 注释信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
ClassLoader classLoader = context.getClassLoader();
//获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
//获取操作系统名
Environment environment = context.getEnvironment();
String osname = environment.getProperty("os.name");
if(osname.toLowerCase().contains("linux")) {return true;}
return false;
}
}
- 1.放在方法的头部,表示只有满足条件时,对应的组件才会被注册:

- 2.放在类的头部,表示只有满足条件时,内部的方法对应的组件才可能被注册:

利用@Import等注册组件
给容器中注册组件的方式:
- 包扫描+组件标注(@Controller/@Service/@Repository/@Component)
- @Bean (可以导入第三方包里面的组件)
- @Import 快速给容器中导入组件
- 使用Spring提供的FactoryBean
导入方式注册
a. 使用@Import(组件.class)标注在配置类,自动导入,默认id为全类名
@Import({Doggy.class,Piggy.class})
b.在@import中使用ImportSelector接口
首先要实现该接口

@Import({Doggy.class,Piggy.class,CustomImportSelector.class})
c.在@import中使用ImportBeanDefinitionRegistrar接口
实现接口

@Import({Doggy.class,Piggy.class,CustomImportSelector.class,CustomImportBeanDefinitionRegistrar.class})
d.使用FactoryBean 接口:

- 注册类中配置

使用该方法注册的Bean实际上为FactoryBean中getObject返回的实例
如何获得FactoryBean本身呢?使用&作为前缀,再从 ioc 中getBean
@Test
public void test08() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Object bean1 = context.getBean("letterFactoryBean");
System.out.println(bean1.getClass());
Object bean2 = context.getBean("&letterFactoryBean");
System.out.println(bean2.getClass());
}
- 测试结果

本文详细介绍了在Spring框架中注册和实例化Bean的多种方法,包括基于XML配置、使用@Configuration注解、通过@ComponentScan指定扫描范围、设置Bean作用域、使用@Conditional按条件注册及利用@Import和FactoryBean导入组件。
3788

被折叠的 条评论
为什么被折叠?



