Spring源码学习(二)核心注解

1、基于xml的形式定义Bean的信息

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

2、Spring IOC 容器底层注解使用

2.1@Bean

@Configuration
public class MainConfig { 
	@Bean 
	public Person person(){
	return new Person();
	}
}

bean的默认名称是方法名,若@Bean(value=“bean的名称”) 那么bean的名称是指定的

2.2 @CompentScan注解来进行包扫描

2.2.1排除用法 excludeFilters(排除@Controller注解的,和XXService的)
2.2.2包含用法 includeFilters ,注意,若使用包含的用法,需要把useDefaultFilters属性设置为false(true表示扫描全部的)
2.2.3@ComponentScan.Filter type的类型
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class, Service.class})

FilterType.CUSTOM 自定义类型如何使用 实现TypeFilter 重写macth方法

@Override
 public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { 
 	//获取当前类的注解源信息 
 	AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
  	//获取当前类的class的源信息 
	ClassMetadata classMetadata = metadataReader.getClassMetadata(); 
	//获取当前类的资源信息
 	Resource resource = metadataReader.getResource(); 	if(classMetadata.getClassName().contains("dao")) { 
	return true; 
	}
	return false;
 }
 @ComponentScan.Filter(type = FilterType.CUSTOM,value = xxFilterType.class) 

2.3 @Scpoe

  1. 在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建 好了)

  2. 指定@Scope为 prototype 表示为多实例的,而且还是懒汉模式加载(IOC容器启动的时候,并不会创建对象,而是 在第一次使用的时候才会创建)

  3. @Scope指定的作用域方法取值
    a) singleton 单实例的(默认)
    b) prototype 多实例的
    c) request 同一次请求
    d) session 同一个会话级别

2.4 @Lazy

Bean的懒加载@Lazy(主要针对单实例的bean 容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象)

2.5 @Conditional进行条件判断等

//当容器中存在xxCondition时才会初始化FooLog
@Bean
@Conditional(value = xxCondition.class)
public FooLog fooLog(){...}

2.6 往IOC 容器中添加组件的方式

①:通过@CompentScan +@Controller @Service @Respository @compent 适用场景: 针对我们自己写的组件可以通过该方式来进行加载到容器中。

②:通过@Bean的方式来导入组件(适用于导入第三方组件的类)

③:通过@Import来导入组件 (导入组件的id为全类名路径)

  • 通过@Import 的ImportSeletor类实现组件的导入 (导入组件的id为全类名路径)
public class XXImportSelector implements ImportSelector { 
	//可以获取导入类的注解信息
 	@Override 
 	public String[] selectImports(AnnotationMetadata importingClassMetadata) { 
 	return new String[]{"com.cjw.testimport.compent.Dog"}; }
 	}
 }
 	@Configuration
	@Import(value = {Person.class, Car.class, XXImportSelector.class}) 
	public class MainConfig { }
  • 通过@Import的 ImportBeanDefinitionRegister导入组件 (可以指定bean的名称)
public class CjwBeanDefinitionRegister implements ImportBeanDefinitionRegistrar { 
	@Override 
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
		//创建一个bean定义对象 
		RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class); //把bean定义对象导入到容器中 
		registry.registerBeanDefinition("cat",rootBeanDefinition); 
	} 
}
@Configuration 
//@Import(value = {Person.class, Car.class}) 
//@Import(value = {Person.class, Car.class, ImportSelector.class}) 
@Import(value = {Person.class, Car.class, XXImportSelector.class, CjwBeanDefinitionRegister.class}) 
public class MainConfig { }
  • 通过实现FacotryBean接口来实现注册 组件
public class CarFactoryBean implements FactoryBean<Car> { 
	//返回bean的对象 
	@Override 
	public Car getObject() throws Exception { 
		return new Car(); 
	}
	//返回bean的类型 
	@Override 
	public Class<?> getObjectType() {
	 return Car.class; 
	}
	//是否为单例
	@Override 
	public boolean isSingleton() {
	  	return true;
	} 
}

BeanFactory与FactoryBean的区别?
BeanFactory:Bean工厂、Spring的顶层接口,工厂只是按照要求生产Bean、Bean定义信息,要生产什么样的Bean需要ApplicaitionContext决定;

FactoryBean:是一个接口,被他修饰的Bean是一个特殊的Bean,原本Bean被隐藏,而是由FactoryBean的getObject方法返回,这个可以改写你原本的Bean;用&可以获取上级的Bean;

2.7Bean的初始化方法和销毁方法.

bean的创建----->初始化----->销毁方法
由容器管理Bean的生命周期,我们可以通过自己指定bean的初始化方法和bean的销毁方法

  • initMethod destroyMechod
@Configuration 
public class MainConfig { 
	//指定了bean的生命周期的初始化方法和销毁方法.
	@Bean(initMethod = "init",destroyMethod = "destroy") 
	public Car car() { 
			return new Car(); 
	} 
}

针对单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法

针对多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受 IOC容器的管理.

  • 通过 InitializingBean和DisposableBean 的二个接口实现bean的初始化以及销毁方法
@Component 
public class Person implements InitializingBean,DisposableBean { 
	public Person() { 
		System.out.println("Person的构造方法"); 
	}
	@Override 
	public void destroy() throws Exception { 
		System.out.println("DisposableBean的destroy()方法 "); 
	}
	@Override 
	public void afterPropertiesSet() throws Exception { 
		System.out.println("InitializingBean的 afterPropertiesSet方法"); 
	} 
}
  • :通过JSR250规范 提供的注解@PostConstruct 和@ProDestory标注的方法
@Component 
public class Book { 
	public Book() { 
		System.out.println("book 的构造方法"); 
	}
	@PostConstruct
	public void init() {
		System.out.println("book 的PostConstruct标志的方法"); 
	}
	@PreDestroy 
	public void destory() { 
		System.out.println("book 的PreDestory标注的方法"); 
	} 
}
  • 通过Spring的BeanPostProcessor的 bean的后置处理器会拦截所有bean创建过程

    postProcessBeforeInitialization 在init方法之前调用

    postProcessAfterInitialization 在init方法之后调用

    BeanPostProcessor的执行时机

populateBean(beanName, mbd, instanceWrapper) 
initializeBean{ 
	applyBeanPostProcessorsBeforeInitialization() 	
	invokeInitMethods{
	isInitializingBean.afterPropertiesSet 
	//自定义的init方法 
	}
	applyBeanPostProcessorsAfterInitialization()方法 
}

2.8 通过@Value +@PropertySource来给组件赋值

public class Person { 
	//通过普通的方式 
	@Value("哈哈") 
	private String firstName; 
	//spel方式来赋值 
	@Value("#{28-8}") 
	private Integer age; 
	//通过读取外部配置文件的值 
	@Value("${person.lastName}") 
	private String lastName; 
	}
@Configuration 
@PropertySource(value = {"classpath:person.properties"}) //指定外部文件的位置 
public class MainConfig { 
	@Bean 
	public Person person() { 
		return new Person(); 
		} 
	}

2.9自动装配

@AutoWired
  • 自动装配首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配
  • 假设我们需要指定特定的组件来进行装配,我们可以通过使用@Qualifier(“cjwDao”)来指定装配的组件 或者在配置类上的@Bean加上@Primary注解
  • 假设我们容器中即没有cjwDao 和cjwDao2,那么在装配的时候就会抛出异常,若我们想不抛异常 ,我们需要指定 required为false的时候可以了。
  • @Resource(JSR250规范) 和@AutoWired的功能差不多一样,但是不支持@Primary 和@Qualifier的支持
  • @InJect(JSR330规范)需要导入jar包依赖 功能和支持@Primary功能 ,但是没有Require=false的功能
  • 使用autowired 可以标注在方法上(set 、构造方法、类@Bean的入参)

2.10自定义组件(实现XXXAware接口来实现)

需要使用spring ioc的底层组件的时候,比如 ApplicationContext等

@Component 
public class XXCompent implements ApplicationContextAware,BeanNameAware { 
	private ApplicationContext applicationContext; 
	@Override 
	public void setBeanName(String name) { 
		System.out.println("current bean name is :【"+name+"】"); 
	}
	@Override 
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
		this.applicationContext = applicationContext;
	} 
}

2.11通过@Profile注解 来根据环境来激活标识不同的Bean

  1. @Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效
  2. @Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活
  3. 没有标志为@Profile的bean 不管在什么环境都可以被激活
@Bean 
@Profile(value = "test") 
public DataSource testDs() { 
	return buliderDataSource(new DruidDataSource()); 
}
//标识开发环境才会被激活 
@Bean 
@Profile(value = "dev") 
public DataSource devDs() { 
	return buliderDataSource(new DruidDataSource()); 
}

切换环境

//方法一:通过运行时jvm参数来切换 -Dspring.profiles.active=test|dev|prod
//方法二:通过代码的方式来激活
public static void main(String[] args) {
	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); 		
	ctx.getEnvironment().setActiveProfiles("test","dev"); 
	ctx.register(MainConfig.class); ctx.refresh(); printBeanName(ctx); 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值