Spring注解驱动-组件注册部分

本文是尚硅谷雷丰阳老师《尚硅谷Spring注解驱动教程》课程的笔记

系列文章目录
1.Spring注解驱动-组件注册部分
2.Spring注解驱动-属性赋值和自动装配部分



Spring注解驱动开发

核心容器

Spring认为所有的组件都应该放在Ioc容器中,组件之间的关系通过容器进行装配。

组件注册-@Configuration&@Bean给容器注册组件

传统的Spring配置
目录:
Spring-annotation
	- src
		-m ain
			- java
				- com.atguigu.bean
					- MainTest
					- Person
			- resources
				- beans.xml
	- pom.xml
1)步骤一:引入Maven依赖------pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu</groupId>
    <artifactId>Spring-annotation</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

</project>
2)步骤二:引入Spring配置文件------beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id = "person" class="com.atguigu.bean.Person">
        <property name="age" value="18"></property>
        <property name="name" value="zhansan"></property>
    </bean>
</beans>
3)步骤三:定义Person------Person
package com.atguigu.bean;

/**
 * @version 1.0
 * @description:
 * @date 2023/1/7 15:06
 */
public class Person {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }
}
4)步骤四:使用Ioc容器获取Person------MainTest
package com.atguigu.bean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @version 1.0
 * @description:
 * @date 2023/1/7 15:19
 */
public class MainTest {
    public static void main(String[] args) {
        // 传入配置文件
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Person person = (Person) classPathXmlApplicationContext.getBean("person");
        System.out.println(person);
    }
}

结果
在这里插入图片描述

使用注解开发

使用配置类代替配置文件,实际上配置类==配置文件
使用注解@Configuration和@Bean
其中:@Configuration用于告诉Spring这是一个配置类;@Bean则是向Ioc容器注册一个Bean

1)步骤一:新建配置类------com/atguigu/config/MainConfig.java
package com.atguigu.config;

import org.springframework.context.annotation.Configuration;
import com.atguigu.bean.Person;
import org.springframework.context.annotation.Bean;

// 告诉Spring这是一个配置类
@Configuration
public class MainConfig {
    // 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
    @Bean
    public Person person(){
        return new Person("lisi", 24);
    }
}
2)步骤二:测试
package com.atguigu.bean;

import com.atguigu.config.MainConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @version 1.0
 * @description:
 * @date 2023/1/7 15:19
 */
public class MainTest {
    public static void main(String[] args) {
//        // 传入配置文件
//        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
//        Person person = (Person) classPathXmlApplicationContext.getBean("person");
//        System.out.println(person);
        ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = annotationConfigApplicationContext.getBean(Person.class);
        System.out.println(bean);
    }
}

结果
在这里插入图片描述

bean改名
查看bean注解可知----》指定名字
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
    @AliasFor("name")
    String[] value() default {};

    @AliasFor("value")
    String[] name() default {};

    Autowire autowire() default Autowire.NO;

    String initMethod() default "";

    String destroyMethod() default "(inferred)";
}
	@Bean("ho")
    public Person person(){
        return new Person("lisi", 24);
    }

	public class MainTest {
	    public static void main(String[] args) {
	//        // 传入配置文件
	//        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
	//        Person person = (Person) classPathXmlApplicationContext.getBean("person");
	//        System.out.println(person);
	        ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
	        Person bean = annotationConfigApplicationContext.getBean(Person.class);
	        System.out.println(bean);
	        String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(Person.class);
	        for (String beans:beanNamesForType) {
	            System.out.println(beans);
	        }
	    }
	}

结果
在这里插入图片描述


组件注册-@ComponentScan自动扫描组件&指定扫描规则

传统情况---》src/main/resources/beans.xml
加入一行
<!-- 包扫描,只要标注了@Controller@Service@Repository@Component都会被自动扫描装配进容器中-->
<!-- 注意:只有标注了才能被扫描,为什么要有多种,是为了分层标识,而且为不同的层可能有特定的用处和功能-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
src/main/java/com/atguigu/config/MainConfig.java
加入注解@ComponentScan(value = "xxx"),value用于指定要扫描的包的路径
// 告诉Spring这是一个配置类
@Configuration
@ComponentScan(value = "com.atguigu")
public class MainConfig {
    // 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
    @Bean("ho")
    public Person person(){
        return new Person("lisi", 24);
    }
}
例子:更新目录
 Spring-annotation
	- src
		-m ain
			- java
				- com.atguigu
					- bean
						- MainTest
						- Person
					- controller
						- BookController
					- dao
						- BookDao
					- service
						- BookService
			- resources
				- beans.xml
	- pom.xml

对应的BookDao加上@RepositoryBookService加上@ServiceBookController加上@Controller
新建一个测试类
src/test/java/com/atguigu/test/IOCTest.java
package com.atguigu.test;

import com.atguigu.config.MainConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import javax.lang.model.element.VariableElement;

/**
 * @version 1.0
 * @description:
 * @date 2023/1/7 19:48
 */
public class IOCTest {
    @Test
    public void test01(){
        ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

结果
在这里插入图片描述

对于@ComponentScan注解包含includeFiltersexcludeFilters,都属于是数组。用于过滤哪些需要包含、哪些需要排除

    ComponentScan.Filter[] includeFilters() default {};
    ComponentScan.Filter[] excludeFilters() default {};

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }

其中ComponentScan.Filter[]是一个Filter数组,而Filter默认的过滤规则为FilterType.ANNOTATION,按注解;而FilterType有多种过滤规则。

	package org.springframework.context.annotation;
	public enum FilterType {
	    ANNOTATION,
	    ASSIGNABLE_TYPE,
	    ASPECTJ,
	    REGEX,
	    CUSTOM;
	
	    private FilterType() {
	    }
	}

FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型
FilterType.ASPECTJ:使用ASPECTJ表达式(不常用)
FilterType.REGEX:使用正则表达式
FilterType.CUSTOM:使用自定义规则

excludeFilters

指定扫描的时候按照什么规则排除那些组件

更新新的过滤规则,在src/main/java/com/atguigu/config/MainConfig.java的@ComponentScan更新配置
// 告诉Spring这是一个配置类
@Configuration
@ComponentScan(value = "com.atguigu", excludeFilters = {
        // 排除规则:排除类型为注解,类型为Controller.class和Service.class,即不扫描带@Controller和@Service的类
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
public class MainConfig {
    // 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
    @Bean("ho")
    public Person person(){
        return new Person("lisi", 24);
    }
}

结果
可以发现bookService和bookController不在容器中
在这里插入图片描述

includeFIlters

指定扫描的时候只需要包含哪些组件
但是Spring默认是扫描所有的组件,需要更改这个配置才能使用includeFilters。
在最原始的时候是需要在xml文件中指定修改use-default-filters="false"
<context:component-scan base-package="com.atguigu" use-default-filters="false"></context:component-scan>
而使用注解的话,在ComponentScan中有一个boolean useDefaultFilters() default true;

@Configuration
@ComponentScan(value = "com.atguigu", includeFilters = {
        // 排除规则:排除类型为注解,类型为Controller.class和Service.class,即不扫描带@Controller和@Service的类
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class})
}, useDefaultFilters = false)
public class MainConfig {
    // 给容器中注册一个Bean; 类型为返回值的类型,id默认是使用方法名作为id
    @Bean("ho")
    public Person person(){
        return new Person("lisi", 24);
    }
}

结果
在这里插入图片描述

组件注册-自定义TypeFilter指定过滤规则

步骤一:新建配置类src/main/java/com/atguigu/config/MyTypeFilter.java
public class MyTypeFilter implements TypeFilter {
    /**
     * match
     *
     * @param metadataReader:读取到的当前正在扫描的类信息
     * @param metadataReaderFactory:可以获取到其他任何类信息的
     *
     * @return boolean
     */
    @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();
        System.out.println("目前正在扫描的包名为:"+className);
        if(className.contains("er")){
            // 匹配成功就会被包含在容器中
            return true;
        }
        return false;
    }
}
步骤二:更新匹配规则
@Configuration
@ComponentScan(value = "com.atguigu", includeFilters = {
        // 排除规则:排除类型为注解,类型为Controller.class和Service.class,即不扫描带@Controller和@Service的类
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {BookService.class}),
        // 启用自定义扫描,扫描规则为MyTypeFilter.class
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)
public class MainConfig {
}

结果

目前正在扫描的包名为:com.atguigu.test.IOCTest
目前正在扫描的包名为:com.atguigu.bean.MainTest
目前正在扫描的包名为:com.atguigu.bean.Person
目前正在扫描的包名为:com.atguigu.config.MyTypeFilter
目前正在扫描的包名为:com.atguigu.dao.BookDao
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
person
myTypeFilter
bookController
bookService
ho

组件注册-@Scope

步骤1:新建新的配置类src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
public class MainConfig2 {
    @Bean("person")
    public Person person(){
        return new Person("zhangsan", 24);
    }
}

步骤2:新建测试类
@Test
public void test02(){
    ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
    Object person = annotationConfigApplicationContext.getBean("person");
    Object person1 = annotationConfigApplicationContext.getBean("person");
    System.out.println(person == person1);
}

结果
在这里插入图片描述

可以注意到,在工厂中获取多次,实际上获取的person也是同一个(单实例)
要改变这种情况,需要引入另一个注解@Scope,该注解有一个属性String scopeName() default "";里面使用ConfigurableBeanFactory
ConfigurableBeanFactory定义了两种模式String SCOPE_SINGLETON = "singleton";(单例模式,默认)和String SCOPE_PROTOTYPE = "prototype";(多例模式)
因此可以通过@Scope修改为多例模式

实际上相当于beans.xml中
   <bean id = "person" class="com.atguigu.bean.Person" scope="prototype">
       <property name="age" value="18"></property>
       <property name="name" value="zhansan"></property>
   </bean>
@Configuration
src/main/java/com/atguigu/config/MainConfig2.java
public class MainConfig2 {
    @Scope("prototype")
    @Bean("person")
    public Person person(){
        return new Person("zhangsan", 24);
    }
}

此时的结果改为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
person
false

注意:
singleton:单实例(默认值):ioc容器启动会调用方法创建对象放到ioc容器中,以后每次获取就是直接从容器(map.get)中拿。
prototype:多实例情况下,ioc容器启动并不会去调用方法创建对象放在ioc容器中。每次获取的时候才会调用方法创建对象。
request:同一个请求创建一个实例
session:同一个session创建一个实例

组件注册-@Lazy-bean

单实例bean:默认在容器启动的时候创建对象(放在单例池中),以后每次调用都不会创建;
懒加载@Lazy:容器创建不创建对象。第一个使用(获取)Bean创建对象,并初始化;

加入@Lazy

ioc容器创建完成...
person

加入@Lazy

src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
public class MainConfig2 {
    @Scope("prototype")
    @Bean("person")
    @Lazy
    public Person person(){
        return new Person("zhangsan", 24);
    }
}

结果:
	ioc容器创建完成...

组件注册-@Conditional-按条件注册bean

@ConditionalSpringBoot底层大量使用该注解,按照一定的条件进行判断,满足条件给容器中注册bean。不像原来的@Bean,加上就注入到Ioc容器中。@Conditional是按条件注册。

src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
public class MainConfig2 {
    @Scope("prototype")
    @Lazy
    @Bean("person")
    public Person person(){
        return new Person("zhangsan", 24);
    }

    @Bean("bill")
    public Person person01(){
        return new Person("Bill Gates", 62);
    }

    @Bean("linus")
    public Person person02(){
        return new Person("linux", 48);  }
}

src/test/java/com/atguigu/test/IOCTest.java
public class IOCTest {
    ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

    @Test
    public void test03(){
        System.out.println("ioc容器创建完成...");
        String[] beanNamesForType = annotationConfigApplicationContext.getBeanNamesForType(Person.class);
        for (String s : beanNamesForType) {
            System.out.println(s);
        }
                // 所有person定义的Map
        Map<String, Person> beansOfType = annotationConfigApplicationContext.getBeansOfType(Person.class);
        System.out.println(beansOfType);
    }
}
//容器中新建了3个
结果:
	ioc容器创建完成...
	person
	bill
	linus
	{person=Person{name='zhangsan', age=24}, bill=Person{name='Bill Gates', age=62}, linus=Person{name='linux', age=48}}

目前的需求发生了改变,如果操作系统是Windows则创建Bill,若是Linux则创建linus
因此需要用到按条件创建Bean----->@Conditional

查看Conditional,可看到该注解即可标在类上,也可标在方法上。需要传入一个Condition(数组)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
	Class<? extends Condition>[] value();
}
查看Condition发现这是一个接口,需要写实现类。有一个matches的方法用于判断T/F
// 有两个参数,第一个参数ConditionContext是判断条件能使用的上下文(环境),第二个参数AnnotatedTypeMetadata是注释信息
@FunctionalInterface
public interface Condition {
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}

实现
1.由于是Condition作为判断,因此需要实现该接口,并实现方法

src/main/java/com/atguigu/condition/LinuxCondition.java
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //1.能获取到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;
    }
}

src/main/java/com/atguigu/condition/WindowsCondition.java
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //1.能获取到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("Windows")) {
            return true;
        }
        return false;
    }
}

2.修改对应方法

src/main/java/com/atguigu/config/MainConfig2.java

   	@Conditional({WindowsCondition.class})
    @Bean("bill")
    public Person person01(){return new Person("Bill Gates", 62);}
    
    @Conditional({LinuxCondition.class})
    @Bean("linus")
    public Person person02(){return new Person("linux", 48); }

3.结果

Windows 10
ioc容器创建完成...
person
bill

扩展:也可以通过registry查看是否含有某个bean,没有就进行注册

boolean person = registry.containsBeanDefinition("person");

也可以将@Conditional标在类上,只有满足Condition的条件,这个类中的所有bea注册才能生效

@Conditional({LinuxCondition.class})
@Configuration
public class MainConfig2 {
	...
}

结果:
	Windows 10
	ioc容器创建完成...
	{}

组件注册-@Import-给容器中快速导入一个组件

回顾:给容器中注册组件:
1)包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)【具有局限性,只能扫描自定义的,其他引入的包扫描不到】
2)@Bean【导入的第三方包里面的组件】

 @Conditional({WindowsCondition.class})
 @Bean("bill")
 public Person person01(){
     return new Person("Bill Gates", 62);
 }

3)@Import【相比于第二种需要创建一个类,能直接通过无参构造器快速给容器导入一个组件】
——1) @Import(要导入到容器中的组件),容器中就会自动注册这个组件,id默认是全类名
——2) ImportSelector:返回需要导入的组件的全类名数组;
——3)ImportBeanDefinitionRegistrar:手动注册bean到容器中
4)使用Spring提供的FactoryBean(工厂Bean)
——1)默认获取到的是工厂bean调用getObject创建的对象
——2)要获取工厂Bean本身,我们需要给id前面加一个&(&colorFactoryBean)

例子:

1)新建一个组件src/main/java/com/atguigu/bean/Color.java
public class Color {
}

2)进行测试,很明显没有注册到容器中
public class IOCTest {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);

    @Test
    public void testImport(){
        printBeans(annotationConfigApplicationContext);
    }
    // 抽取公共方法输出容器里面所有组件
    private void printBeans(AnnotationConfigApplicationContext context){
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

使用@Import导入Color

src/main/java/com/atguigu/config/MainConfig2.java
@Configuration
@Import(Color.class)
public class MainConfig2 {
	...
}

结果:注意,@Import默认的id是组件的全类名
	...
	org.springframework.context.event.internalEventListenerFactory
	mainConfig2
	com.atguigu.bean.Color
	person
	bill
查看@Import可以看到是一个数组,即可以导入多个
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	Class<?>[] value();

}

另外新建一个Red.java
@Configuration
@Import({Color.class, Red.class})
public class MainConfig2 {
}
结果:
	mainConfig2
	com.atguigu.bean.Color
	com.atguigu.bean.Red
	person
	bill

组件注册-@Import-使用ImportSelector

Ioc容器
Color.class
Red.class
MyImportSelector.class
Bule.class
Yellow.class
查看ImportSelector源码,可知是一个接口,规定一个方法selectImport,是要导入的全类名数组
public interface ImportSelector {
	// AnnotationMetadata:当前标注@Import注解的类的所有注解信息
	String[] selectImports(AnnotationMetadata importingClassMetadata);
}

新建src/main/java/com/atguigu/condition/MyImportSelector.java
新建src/main/java/com/atguigu/bean/Red.java
新建src/main/java/com/atguigu/bean/Yellow.java
// 自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
    @Override
    // AnnotationMetadata:当前标注@Import注解的类的所有注解信息,比如下面的 MainConfig2 可获取到@Configuration和@Import信息
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    	// 不能返回null,不然会导致空指针异常
        // return new String[0];
        return new String[]{"com.atguigu.bean.Blue", "com.atguigu.bean.Yellow"};
    }
}

修改对应代码
@Configuration
@Import({Color.class, Red.class, MyImportSelector.class})
public class MainConfig2 {
}

结果:
	mainConfig2
	com.atguigu.bean.Color
	com.atguigu.bean.Red
	com.atguigu.bean.Blue
	com.atguigu.bean.Yellow
	person
	bill

组件注册-@Import-使用ImportBeanDefinitionRegistrar

如果已经注册red和blue
Ioc容器
Color.class
Red.class
MyImportSelector.class
Bule.class
Yellow.class
MyImportBeanDefinitionRegistrar
RainBow.class

手动注册Bean

查看ImportBeanDefinitionRegistrar源码,可知也是一个接口,有一个方法selectImports,给容器中自己添加一些组件
// 
public interface ImportBeanDefinitionRegistrar {
	// importingClassMetadata:当前类的注解信息
	// registry:Bean定义的注册类
	    /**
     * registerBeanDefinitions
     *
     * @param importingClassMetadata    当前类的注解信息
     * @param registry  BeanDefinition的注册类
     *                  把所有需要添加到容器中的bean,BeanDefinitionRegistry有一个registerBeanDefinition方法
     *                  调用BeanDefinitionRegistry.registerBeanDefinition方法手工注册进来
     *
     */
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}


	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}

}
新建类src/main/java/com/atguigu/condition/MyImportBeanDefinitionRegistrar.java
新建类com/atguigu/bean/RainBow.java	

1)定义MyImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     * registerBeanDefinitions
     *
     * @param importingClassMetadata    当前类的注解信息
     * @param registry  BeanDefinition的注册类
     *                  把所有需要添加到容器中的bean,BeanDefinitionRegistry有一个registerBeanDefinition方法
     *                  调用BeanDefinitionRegistry.registerBeanDefinition方法手工注册进来
     *
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 查询容器中
        boolean red = registry.containsBeanDefinition("com.atguigu.bean.Red");
        boolean blue = registry.containsBeanDefinition("com.atguigu.bean.Blue");
        if (red && blue) {
            // 指定Bean的定义信息(Bean的类型,Bean的作用域等)
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainBow.class);
            // 注册一个Bean,指定bean名
            registry.registerBeanDefinition("rainBow", rootBeanDefinition);
        }
    }
}

结果:
	mainConfig2
	com.atguigu.bean.Color
	com.atguigu.bean.Red
	com.atguigu.bean.Blue
	com.atguigu.bean.Yellow
	person
	bill
	rainBow

查看registry.registerBeanDefinition源码
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
对于BeanDefinition,查看源码可知是一个接口
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
	...
}
调用其中RootBeanDefinition实现类
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
	...
}

组件注册-使用FactoryBean注册组件

首先查看FactoryBean源码,可看出这个是一个接口,容器会调用getObject方法,返回的对象,把这个对象放在容器中,而getObjectType返回对象的类型,isSingleton判断是否单例
public interface FactoryBean<T> {
	
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();	

	default boolean isSingleton() {
		return true;
	}
}
步骤1)新建src/main/java/com/atguigu/bean/ColorFactoryBean.java
public class ColorFactoryBean implements FactoryBean<Color> {

    // 返回Color对象,这个对象会返回到容器中
    @Override
    public Color getObject() throws Exception {
        System.out.println("ColorFactoryBean...");
        return new Color();
    }

    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     * isSingleton 控制是否单例
     *
     *
     * @return boolean
     * true:这个容器是单实例,在容器中只会保存一份
     * false:多实例,每次获取都会创建一个新的,调用getObject方法
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

步骤2)在src/main/java/com/atguigu/config/MainConfig2.java注册
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }

步骤3)修改com.atguigu.test.IOCTest#testImport
    @Test
    public void testImport(){
        printBeans(annotationConfigApplicationContext);
        // 工厂bean获取的是调用getObject创建的对象
        Object colorFactoryBean = annotationConfigApplicationContext.getBean("colorFactoryBean");
        System.out.println("bean的类型:" + colorFactoryBean.getClass());
    }

结果:
	mainConfig2
	com.atguigu.bean.Color
	com.atguigu.bean.Red
	com.atguigu.bean.Blue
	com.atguigu.bean.Yellow
	person
	bill
	colorFactoryBean
	rainBow
	ColorFactoryBean...
	bean的类型:class com.atguigu.bean.Color

根据结果可知,虽然加载的名字是colorFactoryBean,但实际上这个colorFactoryBean的类型是Color

创建两个bean查看是否一样
   @Test
    public void testImport(){
        printBeans(annotationConfigApplicationContext);
        // 工厂bean获取的是调用getObject创建的对象
        Object colorFactoryBean1 = annotationConfigApplicationContext.getBean("colorFactoryBean");
        Object colorFactoryBean2 = annotationConfigApplicationContext.getBean("colorFactoryBean");
        System.out.println("bean的类型:" + colorFactoryBean1.getClass());
        System.out.println(colorFactoryBean1 == colorFactoryBean2);
    }

结果:(可看到是同一个bean对象)
	ColorFactoryBean...
	bean的类型:class com.atguigu.bean.Color
	trueisSingletion()修改为return false
    @Override
    public boolean isSingleton() {
        return true;
    }

结果:(可看出不是同一个对象了)
	ColorFactoryBean...
	ColorFactoryBean...
	bean的类型:class com.atguigu.bean.Color
	false

需求:想直接输出FacotryBean

在getBean加上&即可
Object colorFactoryBean3 = annotationConfigApplicationContext.getBean("&colorFactoryBean");
System.out.println("bean4的类型:" + colorFactoryBean3.getClass());
结果:
	bean4的类型:class com.atguigu.bean.ColorFactoryBean

查看源码
org/springframework/beans/factory/BeanFactory.java
public interface BeanFactory {

	String FACTORY_BEAN_PREFIX = "&";

}

生命周期-@Bean指定初始化和销毁方法

bean的生命周期:

  • bean创建–>初始化–>销毁的过程

容器管理bean的生命周期;
我们可以自定义初始化和销毁方法;容器在bean进行到生命周期爱的时候来调用我们自定义的初始化和销毁方法
构建(对象创建)

  • 单实例:在容器启动时创建对象
  • 多实例:在每次获取的时候创建对象(@Scope(“prototype”))

BeanPostProcessor.postProcessBeforeInitialization
初始化:

  • 对象创建完成,并赋值好,调用初始化方法。。。

BeanPostProcessor.postProcessAfterInitialization
销毁:

  • 单实例:容器关闭的时候进行销毁
  • 多实例:容器不会管理整个bean;容器不会调用销毁方法

遍历得到容器中所有的BeanPostProcessor,然后挨个执行beanPostProcessor。
一旦返回null,跳出for循环,不会执行后面的beanPostProcessorsBeforeInitialization

// 给bean进行属性赋值
populateBean(beanName, mbd, instanceWrapper){
	applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	invokeInitMethods(beanName, wrappedBean, mbd);执行自定义初始化
	applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

1)指定初始化和销毁方法

  • 通过@Bean指定init-method=“xxx” destroy-method=“xxx”

2)通过让Bean实现InitializingBean(定义初始化逻辑),DisposableBean(定义销毁逻辑)
3)可以使用JSR250;

  • @PostConstruct:在bean创建完成并且属性赋值完成;来执行初始化方法
  • @PreDestro:在容器销毁bean之前通知我们进行清理工作

4)BeanPostProcessor【interface】:bean的后置处理器;

  • 在bean初始化前后进行一些处理工作;
  • postProcessBeforeInitialization:在初始化之前工作
  • postProcessAfterInitialization:在初始化之后工作

使用xml方法

    <bean id = "person" class="com.atguigu.bean.Person" scope="prototype" init-method="xxx" destroy-method="xxx">
        <property name="age" value="18"></property>
        <property name="name" value="zhansan"></property>
    </bean>

使用注解

com/atguigu/bean/Car.java
public class Car {

    public Car() { System.out.println("car constructor..."); }

    public void init() { System.out.println("car...init..."); }

    public void destroy() { System.out.println("car...destroy..."); }
}

新建com/atguigu/config/MainConfigOfLifeCycle.java并注册Car
@Configuration
public class MainConfigOfLifeCycle {
    
    @Bean
    public Car car() {
        return new Car();
    }
}

新建测试类com/atguigu/test/IOCTest_LifeCycle.java
public class IOCTest_LifeCycle {
    @Test
    public void test01() {
        // 1.创建ioc容器
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");
        // 关闭容器
        context.close();
    }
}

结果:
	car constructor...
	car...init...
	容器创建完成...
	car...destroy...

生命周期-InitializingBean和DisposableBean

查看接口InitializingBean
public interface InitializingBean {
 	// 作用时机,BeanFactory创建好并且把bean所有的属性都设置好
	void afterPropertiesSet() throws Exception;

}

查看接口DisposableBean 
public interface DisposableBean {

	void destroy() throws Exception;

}

创建src/main/java/com/atguigu/bean/Cat.java
@Component
public class Cat implements InitializingBean, DisposableBean {

    public Cat() {
        System.out.println("cat constructor...");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("cat...destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat...afterPropertiesSet...");
    }
}

@ComponentScan("com.atguigu.bean")
@Configuration
public class MainConfigOfLifeCycle {

    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car car() {
        return new Car();
    }
}

测试结果:
	cat constructor...
	cat...afterPropertiesSet...
	car constructor...
	car...init...
	容器创建完成...
	car...destroy...
	cat...destroy...

生命周期-@PostConstruct&@PreDestroy

查看注解PostConstruct源码
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}

创建src/main/java/com/atguigu/bean/Dog.java
@Component
public class Dog {
    public Dog() {
        System.out.println("dog constructor...");
    }

    // 对象创建并赋值之后调用
    @PostConstruct
    public void init() {
        System.out.println("dog...@PostConstruct...");
    }

    // 容器移除对象之前
    @PreDestroy
    public void destory() {
        System.out.println("dog...@PreDestroy...");
    }
}

测试:
	cat constructor...
	cat...afterPropertiesSet...
	dog constructor...
	dog...@PostConstruct...
	car constructor...
	car...init...
	容器创建完成...
	car...destroy...
	dog...@PreDestroy...
	cat...destroy...

生命周期-BeanPostProcessor-后置处理器

BeanPostProcessor是在创建Bean的时候,先扫描所有BeanPostProcessorpostProcessBeforeInitialization,符合条件的调用。然后再创建对应的Bean对象。然后再扫描所有BeanPostProcessorpostProcessAfterInitialization,符合条件的调用。

扫描AnnotationConfigApplicationContext所在的类并注入这个类和基础类
尝试获取,但获取失败,需要创建
注入属性
AnnotationConfigApplicationContext
this()
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
register(annotatedClasses);
this.reader.register(annotatedClasses);
org.springframework.context.annotation.AnnotatedBeanDefinitionReader#register
refresh();
doCreateBean
doCreateBean
initializeBean
applyBeanPostProcessorsBeforeInitialization
invokeInitMethods
applyBeanPostProcessorsAfterInitialization
查看BeanPostProcessor源码
public interface BeanPostProcessor {
// bean是刚创建的实例名字,beanName是这个实例在容器中的名字
// 返回值是要返回将要使用的bean,可以返回传进来的bean,也可以对bean进行包装然后返回出去
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

新建src/main/java/com/atguigu/bean/MyBeanPostProcessor.java
/**
 * @version 1.0
 * @description: 后置处理器:初始化前后进行处理工作
 * 将后置处理器加入到容器中
 * @date 2023/1/11 14:39
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean);
        return bean;
    }
}

可以观察到每个对象即使没有调用,但都执行了postProcessBeforeInitializationpostProcessAfterInitialization。则是因为MyBeanPostProcessorpostProcessBeforeInitializationpostProcessAfterInitialization没有设置条件。每个Bean创建的时候都扫描到这个MyBeanPostProcessor然后执行。

结果:
	cat constructor...
	postProcessBeforeInitialization...cat=>com.atguigu.bean.Cat@6c7a164b
	cat...afterPropertiesSet...
	postProcessAfterInitialization...cat=>com.atguigu.bean.Cat@6c7a164b
	dog constructor...
	postProcessBeforeInitialization...dog=>com.atguigu.bean.Dog@536dbea0
	dog...@PostConstruct...
	postProcessAfterInitialization...dog=>com.atguigu.bean.Dog@536dbea0
	car constructor...
	postProcessBeforeInitialization...car=>com.atguigu.bean.Car@30b6ffe0
	car...init...
	postProcessAfterInitialization...car=>com.atguigu.bean.Car@30b6ffe0
	容器创建完成...

生命周期-BeanPostProcessor原理

实际上,BeanPostProcesso是初始化,Bean对象注入到Ioc容器时调用的。
postProcessBeforeInitializationpostProcessAfterInitialization打上断点
在这里插入图片描述
查看方法调用栈
在这里插入图片描述

在这里插入图片描述
可看到调用AnnotationConfigApplicationContext的构造器,

	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		// 无参构造,主要用于创建AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner
		this();
		// 扫描对应的.class文件,调用AnnotatedBeanDefinitionReader进行注入
		register(annotatedClasses);
		// 对Bean进行创建等操作
		refresh();
	}

其中的register(annotatedClasses):扫描对应的.class文件,调用AnnotatedBeanDefinitionReader进行注入

	public void register(Class<?>... annotatedClasses) {
		Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
		this.reader.register(annotatedClasses);
	}

在这里插入图片描述

最后调用了refresh()方法

	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}
	...
}

主要是调用了finishBeanFactoryInitialization(beanFactory);(初始化所有剩下的单实例对象)

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
				@Override
				public String resolveStringValue(String strVal) {
					return getEnvironment().resolvePlaceholders(strVal);
				}
			});
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
	}

这里主要看最后一步beanFactory.preInstantiateSingletons();(初始化所有单例bean)

	@Override
	public void preInstantiateSingletons() throws BeansException {
	...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							@Override
							public Boolean run() {
								return ((SmartFactoryBean<?>) factory).isEagerInit();
							}
						}, getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					getBean(beanName);
				}
			}
		}
	}
这里主要看getBean(beanName)【尝试获取Bean@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
然后调用doGetBean---》再调用getSingleton
	@Override
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
再看getSingleton,这里又调用了singletonFactory.getObject();获取单实例--》一直尝试获取
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return (singletonObject != NULL_OBJECT ? singletonObject : null);
	}
查看调用栈可知,由于【获取失败】,因此调用了createBean。而createBean调用了doCreateBean创建对象
	@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
		...
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isDebugEnabled()) {
			logger.debug("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}

调用doCreateBean有个initializeBean(beanName, exposedObject, mbd);
	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
			throws BeanCreationException {
		...
	try {
		// 为bean的属性进行赋值【即先为bean赋值再调用initializeBean】
		populateBean(beanName, mbd, instanceWrapper);
		if (exposedObject != null) {
		// initializeBean(beanName, exposedObject, mbd)相当于后置处器的调用
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
	}
	...
}
initializeBean(beanName, exposedObject, mbd)相当于【后置处理器】的调用,前面还有一个populateBean(beanName, mbd, instanceWrapper);
为bean的属性进行赋值【即先为bean赋值再调用initializeBean】
而initializeBean(beanName, exposedObject, mbd)函数则是:
	protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
		...
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
		// 执行初始化方法 PostConstruct等
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
				catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

		if (mbd == null || !mbd.isSynthetic()) {
		// 执行初始化后方法
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		...	
	}
由于还没销毁,直接查看applyBeanPostProcessorsBeforeInitialization,通过源码可以看出
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

生命周期-BeanPostProcessor在Spring底层的使用

该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。

查看BeanPostProcessor接口。org/springframework/beans/factory/config/BeanPostProcessor.java
查看其实现类

在这里插入图片描述

找到ApplicationContext,作用是可以帮我们组件注入到Ioc容器。

例子:

com/atguigu/bean/Dog.java
Dog实现ApplicationContextAware接口。即实现setApplicationContext方法,此时会传入一个ApplicationContext 
@Component
public class Dog implements ApplicationContextAware {
	// 新建ApplicationContext 用于接收
	private ApplicationContext applicationContext;

    public Dog() {
        System.out.println("dog constructor...");
    }

    // 对象创建并赋值之后调用
    @PostConstruct
    public void init() {
        System.out.println("dog...@PostConstruct...");
    }

    // 容器移除对象之前
    @PreDestroy
    public void destory() {
        System.out.println("dog...@PreDestroy...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

这个功能是由ApplicationContextAwareProcessor实现

查看org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization方法
	@Override
	@Nullable
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// 如果没有实现则直接返回bean
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
			return bean;
		}
				AccessControlContext acc = null;

		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

这里有一个 bean instanceof ApplicationContextAware 用于判断有没有实现这个接口。如果有就调用invokeAwareInterfaces(bean),在里面注入值。(监听者模式?)

查看invokeAwareInterfaces方法,他会判断有没有实现ApplicationContextAware,如果是则把当前bean转化为ApplicationContextAware,再调用setApplicationContext,把Ioc容器注入进去。
	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationStartupAware) {
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

例子2:Spring提供校验Validation(类似于JSR303)

实现BeanPostProcessor接口,这里的postProcessBeforeInitializationpostProcessAfterInitialization设置了条件

// 在JavaBean创建完注入属性时,可以进行校验。通过判断afterInitialization,在初始化前后调用doValidate进行校验
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {

	@Nullable
	private Validator validator;

	private boolean afterInitialization = false;
	
	...
	// 初始化之前
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if (!this.afterInitialization) {
			doValidate(bean);
		}
		return bean;
	}
	// 初始化之后 
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if (this.afterInitialization) {
			doValidate(bean);
		}
		return bean;
	}
	...
}

例子3:@PostConstruct和@PreDestroy

// @PostConstruct和@PreDestroy是怎样起作用的?
@Component
public class Dog implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Dog() {
        System.out.println("dog constructor...");
    }

    // 对象创建并赋值之后调用
    @PostConstruct
    public void init() {
        System.out.println("dog...@PostConstruct...");
    }

    // 容器移除对象之前
    @PreDestroy
    public void destory() {
        System.out.println("dog...@PreDestroy...");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

打入断点进行调试
在这里插入图片描述

查看调用栈可以看出调用了InitDestroyAnnotationBeanPostProcessor

// 传递 javax.annotation.PostConstruct
public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
		this.initAnnotationType = initAnnotationType;
	}
// 传递 javax.annotation.PreDestroy 
public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
	this.destroyAnnotationType = destroyAnnotationType;
}


// 实现PostConstruct
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			metadata.invokeInitMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
			throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
		}
		return bean;
	}

注意看LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());可以找到生命周期注解
在这里插入图片描述

例子4:@Autowired

implements
extends
AutowiredAnnotationBeanPostProssor
MergedBeanDefinitionPostProcessor
BeanPostProcessor

在创建完对象后对属性进行赋值
注意这里的AutowiredAnnotationBeanPostProcessor比较特殊,不是直接实现BeanPostProcessor

使用的是AutowiredAnnotationBeanPostProcessor 
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
		MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
	...
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值