IOC
准备:
|
@Bean
默认情况下bean的名称和方法名称相同,但也可以使用name属性来指定。
public class MainConfig {
public Person person() {
return new Person("jony", 19);
}
}
public void doTest() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
// 输出:
// ... person1@ComponentScan
value:指定要扫描的包
excludeFilters = Filter[] 指定扫描的时候按照什么规则排除哪些组件
includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
FilterType.ANNOTATION 按照注解
FilterType.ASSIGNABLE_TYPE 按照给定的类型
FilterType.ASPECTJ 使用ASPECTJ表达式
FilterType.REGEX 使用正则指定
FilterType.CUSTOM 使用自定义规则
useDefaultFilters 默认为true,加载所有组件,即使用默认的 Filter 进行包扫描,默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描
示例:自定义过滤规则需要实现TypeFilter接口
public class MainConfig {
public Person person() {
return new Person("jony", 19);
}
}
public class MyTypeFilter implements TypeFilter {
/**
* @param metadataReader 读取到当前正在扫描的类信息
* @param metadataReaderFactory 读取到其他的类信息
* @return boolean
*/
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("===> " + className);
if (className.contains("service")) {
return true;
}
return false;
}
}
// 输出:
// ... personService
// person1@Scope
singleton:默认,容器启动时就会创建对象,放到IoC容器中;
prototype:容器启动并不会去调用方法创建对象,而是在每次获取时 才会创建对象。
public Person person() {
System.out.println("向容器中添加person...");
return new Person("Tom", 19);
}@Lazy
针对单实例Bean,容器启动时不创建对象,第一次使用(获取)Bean创建对象,并初始化。
@Conditional
按照一定的条件进行判断,满足条件给容器中注册Bean,可用在方法或类上
示例:
public Person personCon() {
return new Person("windows", 30);
}
public Person personCon2() {
return new Person("linux", 35);
}public class LinuxCon implements Condition {
/**
* @param conditionContext 判断条件能使用的上下文(环境)
* @param annotatedTypeMetadata 注释信息
* @return boolean
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取IOC使用的BeanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
// 获取当前环境信息
Environment environment = conditionContext.getEnvironment();
// 获取bean定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
// 可以判断容器中bean注册情况, 也可以给容器中注册bean
boolean definitionRes = registry.containsBeanDefinition("person");
String property = environment.getProperty("os.name");
if (property.contains("Windows")) {
return false;
}
return true;
}
}public class WindowsCon implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取当前环境信息
Environment environment = conditionContext.getEnvironment();
String property = environment.getProperty("os.name");
return property.contains("Windows");
}
}@Import
@Import(要导入到容器中到组件),容器中就会自动注册这个组件,id默认是全类名
示例:新建一个Cat类
public class MainConfig2 {
...
}
public class MainApplication2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
// 输出:
// ... com.example.springlearn.bean.CatImportSelector:返回需要导入的组件的全数组
示例:创建一个Dog类
public class MyImportSelector implements ImportSelector {
/**
* @param annotationMetadata 当前标注@Import注解的类的所有注解信息
* @return java.lang.String[]
*/
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{"com.example.springlearn.bean.Dog"};
}
}ImportBeanDefinitionRegistrar:手动注册Bean
示例:创建一个Rabbit类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata
* @param registry BeanDefinition注册类, 把所有需要添加到容器中的bean 调用 registry.registerBeanDefinition 手动注册进来
* @param importBeanNameGenerator
* @Description // 当前类的注解信息
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
boolean rabbit = registry.containsBeanDefinition("rabbit");
if (!rabbit) {
// 指定bean定义信息 (bean的类型 作用域等...)
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Rabbit.class);
// 注册一个bean 指定bean名
registry.registerBeanDefinition("rrrabbit", rootBeanDefinition);
}
}
}
public class MainConfig2 {
...
}
// 输出:
// ... com.example.springlearn.bean.Cat
// com.example.springlearn.bean.Dog
// rrrabbitFactoryBean
示例:
public class CatFactoryBean implements FactoryBean<Cat> {
/**
* @Description // 返回一个Cat对象, 这个对象会添加到容器中
* @return com.example.springlearn.bean.Cat
*/
public Cat getObject() throws Exception {
System.out.println("Cat getObject()");
return new Cat();
}
public Class<?> getObjectType() {
return Cat.class;
}
public boolean isSingleton() {
// true 单例, false 多实例
return true;
}
}
public class MainConfig2 {
public CatFactoryBean catFactoryBean() {
return new CatFactoryBean();
}
...
}
public void doTest() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
// 工厂bean获取的是调用getObject()创建的对象
Object catFactoryBean = annotationConfigApplicationContext.getBean("catFactoryBean");
System.out.println("bean的类型: " + catFactoryBean.getClass());
Object factoryBean = annotationConfigApplicationContext.getBean("&catFactoryBean");
System.out.println("bean的类型: " + factoryBean.getClass());
}
// 输出:
// ... Cat getObject()
// bean的类型: class com.example.springlearn.bean.Cat
// bean的类型: class com.example.springlearn.bean.CatFactoryBean默认获取到的是工厂bean调用getObject()创建的对象;
要获取工厂Bean本身,需要在id前加&;
/** |
生命周期
/** |
指定初始化和销毁方法
public class Car {
public Car() {
System.out.println("car constructor...");
}
public void initCar() {
System.out.println("car init...");
}
public void destroyCar() {
System.out.println("car destroy...");
}
}
public class MainConfigOfLifeCycle {
public Car car() {
return new Car();
}
}
public class TestLifeCycle {
public void doTest() {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("ioc container finished");
// 关闭容器
annotationConfigApplicationContext.close();
}
}singleton: 容器关闭后执行destroyMethod方法;
prototype: 获取的时候才会初始化,容器关闭后不会执行destroyMethod方法,需手动调用;
实现接口 InitializingBean和DisposableBean
public class Bus implements InitializingBean, DisposableBean {
public void destroy() throws Exception {
System.out.println("Bus destroy...");
}
public void afterPropertiesSet() throws Exception {
System.out.println("Bus afterPropertiesSet...");
}
}@PostConstruct和@PreDestroy
public class Bicycle {
public Bicycle() {
System.out.println("Bicycle constructor...");
}
// 对象创建并赋值后调用
public void init() {
System.out.println("Bicycle PostConstruct...");
}
// 容器移除对象前调用
public void destroy() {
System.out.println("Bicycle PreDestroy...");
}
}自定义BeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization..." + bean + " " + beanName);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization..." + bean + " " + beanName);
return bean;
}
}BeanPostProcessor【interface】, bean的后置处理器, 在bean初始化前后进行一些处理工作:
- postProcessBeforeInitialization: 在初始化之前工作
- postProcessAfterInitialization: 在初始化之后工作
BeanPostProcessor原理
遍历得到容器中所有的BeanPostProcessor: 逐个执行 beforeInitialization,一旦返回null,跳出for循环,不会执行后面的 BeanPostProcessor.PostProcessorsBeforeInitialization;
BeanPostProcessor原理:
populateBean(beanName, mbd, instanceWrapper); 给bean进行属性赋值
initializeBean(beanName, exposedObject, mbd) {
applyBeanPostProcessorsBeforeInitialization(bean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd); 执行自定义初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
属性赋值
@Value
@PropertySource
// 使用@PropertySource读取外部配置文件中的 k/v 保存到运行的环境变量中; 加载完外部的配置文件以后使用${}取出配置文件中的值
public class MainConfigOfPropertyValues {
public Person person() {
return new Person();
}
}public class Person {
private String name;
/**
* 使用@Value赋值:
* 1) 基本数值
* 2) 可以写SpEL, #{}
* 3) 可以写${} 取出配置文件【properties】中的值 (在运行环境变量里的值)
*/
private Integer age;
...
}因为是运行时变量,所以可以用applicationContext.getEnvironment
public class TestPropertyValues {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
public void doTest() {
ConfigurableEnvironment environment = annotationConfigApplicationContext.getEnvironment();
String property = environment.getProperty("p.age");
System.out.println(property);
}
}