0.原始注入bean方式
resource下建立beans.xml;
<bean id="car" class="com.peimx.spring.compnent.bean.Car">
<property name="brand" value="AODI"></property>
<property name="price" value="18000"></property>
</bean>
方法调用检测
public static void main(String[] args) {
//上下文注入bean中配置
ApplicationContext ap = new ClassPathXmlApplicationContext("beans.xml");
for (String beanDefinitionName : ap.getBeanDefinitionNames()) {//获取bean名称数组
System.out.println(beanDefinitionName);
}
Car car = (Car)ap.getBean("car");//通过id获取bean实例
System.out.println(car.getBrand());
System.out.println(car.getPrice());
}
结果输出
car
AODI
18000
- @Bean方式注入
建立一个配置类
@Configurable
public class MainConfig {
@Bean("plane") //可直接@Bean,默认取方法名称作为id
public Plane plane(){
return new Plane();
}
}
方法调用检测
ApplicationContext apps = new AnnotationConfigApplicationContext(MainConfig.class);
for (String beanDefinitionName : apps.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
Plane plane = (Plane) apps.getBean("plane");
System.out.println(plane.getBrand());
结果输出
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
plane
null//属性未初始化,所以无值
- 文件扫描规则@CompnentScan
(0)文件列表
(1)定义范围
bean上加@compent注解
@Component
public class Car extends Transportation {
}
配置文件
@ComponentScan(value = "com.peimx.spring.compnent.bean")
public class MainConfig {
}
结果输出
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
car
plane
train
null
(2)过滤器
@ComponentScan(value = "com.peimx.spring.compnent",
excludeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Service.class}),//注解方式
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes = { Train.class}),//指定类型
@Filter(type=FilterType.CUSTOM,classes = {MyFilter.class}),//自定义过滤器
@Filter(type=FilterType.ASPECTJ,value = {}),//按照Aspectj的表达式,基本上不会用到
@Filter(type=FilterType.REGEX,value = {})//正则表达式类型
},
useDefaultFilters = true)
此处应注意:useDefaultFilters 默认为true,使用includeFilters条件筛选时,应设为false
其中自定义过滤器
public class MyFilter implements TypeFilter {
/*
* metadataReader:读取当前正在扫描类的信息
* metadataReaderFactory:可以获取到其它任何类的信息
* */
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
System.out.println("--------filter--"+metadataReader.getClassMetadata().getClassName());
ClassMetadata classMetadata = metadataReader.getClassMetadata(); //获取当前类的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //获取当前类注解的信息
Resource resource = metadataReader.getResource(); //获取当前路径
System.out.println(resource.getDescription());
if(metadataReader.getClassMetadata().getClassName().equals("com.peimx.spring.compnent.bean.Car")){
return false;
}
return true;//true放行,false 拦截
}
输出结果:
--------filter--com.peimx.spring.compnent.bean.Car
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\bean\Car.class]
--------filter--com.peimx.spring.compnent.bean.Plane
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\bean\Plane.class]
--------filter--com.peimx.spring.compnent.bean.Train
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\bean\Train.class]
--------filter--com.peimx.spring.compnent.bean.Transportation
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\bean\Transportation.class]
--------filter--com.peimx.spring.compnent.config.MyFilter
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\config\MyFilter.class]
--------filter--com.peimx.spring.compnent.controller.CarController
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\controller\CarController.class]
--------filter--com.peimx.spring.compnent.controller.OutPrint
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\controller\OutPrint.class]
--------filter--com.peimx.spring.compnent.dao.CarDao
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\dao\CarDao.class]
--------filter--com.peimx.spring.compnent.service.CarService
file [D:\aStudy\project\spring\target\classes\com\peimx\spring\compnent\service\CarService.class]
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
car //由过滤器可知,只有car返回false,即结果集排除所有只留car
此处小结论:filter之间是并集合关系,也就是说各个过滤器集合合并在一起共同组成过滤器总结果集。
总结:
@ComponentScan(value = "com.peimx.spring.compnent",
excludeFilters = {
@Filter(type = FilterType.ANNOTATION,classes = {Service.class}),//注解方式
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes = { Train.class}),//指定类型
@Filter(type=FilterType.CUSTOM,classes = {MyFilter.class}),//自定义过滤器
@Filter(type=FilterType.ASPECTJ,value = {}),//按照Aspectj的表达式,基本上不会用到
@Filter(type=FilterType.REGEX,value = {})//正则表达式类型
},
useDefaultFilters = true)
//excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
- scope扫描规则
配置类
@Configurable
public class MainConfig {
@Bean("plane")
@Scope("prototype")
public Plane plane(){
return new Plane();
}
}
方法调用检测
ApplicationContext apps = new AnnotationConfigApplicationContext(MainConfig.class);
for (String beanDefinitionName : apps.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
Plane plane1 = (Plane) apps.getBean("plane");
Plane plane2 = (Plane) apps.getBean("plane");
System.out.println(plane1==plane2);//判断两次取到对象是否相同
结果输出
@Scope("prototype")时,返回false,即每次获取都生成新对象;
@Scope("singleson") 或不配置时,返回true,即同一对象,只实例化一次
结论:
prototype:多实例:IOC容器启动并不会去调用方法创建对象放在容器中,而是 每次获取的时候才会调用方法创建对象,见test02
singleton:单实例(默认):IOC容器启动会调用方法创建对象放到IOC容器中
以后每交获取就是直接从容器(理解成从map.get对象)中拿
request:主要针对WEB应用,同一次请求创建一个实例
session:同一个session创建一个实例(后面两个用得不多,了解即可)
- lazy懒加载
配置类
@Bean("plane")
@Lazy
public Plane plane(){
System.out.println("给容器添加bean");
return new Plane();
}
检测类
ApplicationContext apps = new AnnotationConfigApplicationContext(MainConfig.class);
System.out.println("ioc 创建完成");
Plane plane = (Plane) apps.getBean("plane");
结果
ioc 创建完成
给容器添加bean
结论:单实例默认在容器启动的时候加载对象。懒加载主要针对单实例,容器启动的时候不创建,仅当第一次使用的时候创建和初始化。
- @Conditional条件注册bean
条件配置
public class WindowsCondition implements Condition {
/*
* ConditionContext:判断条件能使用的上下文
* AnnotatedTypeMetadata:注解信息
* */
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String env = context.getEnvironment().getProperty("os.name");
if(env.equals("Windows 10")){
return true; //条件通过
}
return false;//条件未通过
}
}
配置
@Conditional(WindowsCondition.class)
@Bean("car")
public Car car(){
return new Car();
}
结果
car//满足条件通过打印,若不满足则无结果输出
- @Import注册bean
自定义配置
(1)注册类
/*
* importingClassMetadata : 注解信息
* registry : BeanDefinition注册类
* */
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition1 = registry.containsBeanDefinition("com.peimx.spring.compnent.bean.Train");//判断是否有train
if(!definition1){
RootBeanDefinition beanDefinition = new RootBeanDefinition(Train.class);
registry.registerBeanDefinition("train",beanDefinition);
}
}
(2)注册类
public class MyImportSelector implements ImportSelector {
/*
* AnnotationMetadata 注解信息类
* */
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.peimx.spring.compnent.bean.Car"};
}
}
配置类
@Configurable
@Import({Plane.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
}
结果
com.peimx.spring.compnent.bean.Plane //import注入的id为全路径
com.peimx.spring.compnent.bean.Car
train //注册类自定义名称
7. FactoryBean方式加载bean
配置
/* 使用spring提供的FactoryBean(工厂bean)
* beans.factory.FatoryBean源码跟进去
* 容器调用getObject()返回对象,把对象放到容器中;
* getObjectType()返回对象类型
* isSingleton()是否单例进行控制
* 新建JamesFactoryBean实现FactoryBean
* 在config里新建jamesFactoryBean()方法
* 写完测试用例后:
* a,默认获取到的是工厂bean调用getObject创建的对象
* b,要获取工厂Bean本身,需要在id前加个 &jamesFactoryBean
*/
public class MyFactoryBean implements FactoryBean<Plane> {
@Override
public Plane getObject() throws Exception {
return new Plane();
}
@Override
public Class<?> getObjectType() {
return Plane.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
配置类
@Bean
public MyFactoryBean myFactoryBean(){
return new MyFactoryBean();
}
测试
ApplicationContext apps = new AnnotationConfigApplicationContext(MainConfig.class);
for (String beanDefinitionName : apps.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
Object object = apps.getBean("myFactoryBean");
System.out.println(object.getClass());
结果
mainConfig
myFactoryBean
class com.peimx.spring.compnent.bean.Plane //打印class 可验证已经注入