spring注解驱动开发原理剖析

Posted yifenggg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring注解驱动开发原理剖析相关的知识,希望对你有一定的参考价值。

组件注册

@Configuration、@Bean注册组件

先写一个bean

public class Person {
    private String name;
    private  Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = 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 +
                ‘}‘;
    }
}
  • 以前用XML文件配置的方法 。beans.xml:

    <bean id="person" class="com.ciss.bean.Person">
        <property name="age" value="18"></property>
        <property name="name" value="张三"></property>
    </bean>
    

test一下:

public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Object person = applicationContext.getBean("person");
        System.out.println(person);
    }
}
  • 现在用注解
//配置类
@Configuration
public class MainConfig {
    //给容器注册一个bean,类型为返回值的类型,id默认是方法名
    @Bean("person")//设置id为person
    public Person person01(){
        return new Person("lisi",20);
    }
}
public class MainTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);

        String[] names = applicationContext.getBeanNamesForType(Person.class);
        for (String name : names) {
            System.out.println(name);
        }
    }
}

@ComponentScan自动扫描组件

  • 以前用XML文件配置的方法 。beans.xml:
<!--包扫描-->
<context:component-scan base-package="com.ciss"></context:component-scan>
  • 现在用注解
//配置类
@Configuration
//@ComponentScan ,value :指定要扫描的包 ;
//excludeFilters排除要扫描的包
@ComponentScan(value = "com.ciss",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
})
public class MainConfig {
    //给容器注册一个bean,类型为返回值的类型,id默认是方法名
    @Bean("person")
    public Person person01(){
        return new Person("lisi",20);
    }
}
-------------------------------------------

//includeFilters指定要扫描的包 ,useDefaultFilters = false 不用默认扫描方式
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型
//FilterType.ASPECTJ,
//FilterType.REGEX,
//FilterType.CUSTOM :自定义规则
@ComponentScan(value = "com.ciss",includeFilters =  {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = false)
    public class MainConfig {
    //给容器注册一个bean,类型为返回值的类型,id默认是方法名
    @Bean("person")
    public Person person01(){
        return new Person("lisi",20);
    }
}

若自定义规则(@TypeFilter)

@ComponentScan(value = "com.ciss",includeFilters =  {
        @ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)
},useDefaultFilters = false)
public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取正在扫描的类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();
        System.out.println("--->"+className);
        //获取当前类资源
        Resource resource = metadataReader.getResource();
        if (className.contains("er")){
            //包含er就匹配上
            return true;
        }
        return false;
    }
}
  • 测试一哈:
@Test
public void test01(){
    applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
}

@Scope设置组件作用域

@Configuration
public class MainConfig2 {
    @Bean("person")
    /**
     * ConfigurableBeanFactory#SCOPE_PROTOTYPE  //多实例 ioc容器启动并不会调用方法创建对象,而是每次获取的时候(getBean)就会调用方法创建对象
     * ConfigurableBeanFactory#SCOPE_SINGLETON  //单实例 ioc容器启动会调用方法创建对象放到ioc容器中
     * org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST   //request
     * org.springframework.web.context.WebApplicationContext#SCOPE_SESSION   //session
     */
    @Scope("prototype")
    public Person person() {
        return new Person("张三", 24);
    }
}

测试一哈:

@Test
public void test02(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] definitionNames = applicationContext.getBeanDefinitionNames();
    for (String name : definitionNames) {
        System.out.println(name);
    }
    //默认单实例
    Object person = applicationContext.getBean("person");
    Object person1 = applicationContext.getBean("person");
    System.out.println(person==person1);
}

@Lazy懒加载

/* 懒加载:
*   单例bean:默认在容器启动的时候创建对象
*   懒加载:容器启动不创建对象。而是在第一次使用(获取)bean时创建对象,并初始化;
*/

@conditional按照条件注册bean

  • 测试一哈

    • 如果操作系统是windows 就加载bill gate 这个bean组件

    • 如果操作系统是linus 就加载linus 这个bean组件

@Bean("bill gate")
@Conditional(WindowsCondition.class)
public Person person01(){
    return new Person("bill gates",63);
}
@Bean("linus")
@Conditional(LinuxCondition.class)
public Person person02(){
    return new Person("linus",48);
}
  • 实现Condition接口自己写条件
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取BeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //获取bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        //获取环境信息
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("Windows")){
            return true;
        }
        return false;
    }
}
--------------------------------------------------------------
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //获取BeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //获取bean定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        //获取环境信息
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        if (property.contains("linux")){
            return true;
        }
        return false;
    }
}
  • @conditional还可以放在类上,表示满足该条件的话,才加载这个类中所有的组件

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

/**
 * 给容器中注册组件
 * 1、包扫描+组件标注注解(@controller,@service,@repository,@component)
 * 2、@bean[导入第三方包的组件]
 * 3、@import【快速给容器中倒入一个组件】
 		1)import(要导入的组件),容器会自动注册这个组件,id默认是全类名
 		2)返回需要导入的组件的全类名数组
       3)实现ImportBeanDefinitionRegistrar接口,手工注册组件
 */

6.1@import(要导入的组件)

  • 创建几个bean:Color和Red。Blue和Yellow。RainRow

  • 在配置类中(MainConfig2.class)加一个注解:@Import({Color.class, Red.class})

  • 测试一哈:

@Test
public void testImport(){
    applicationContext=new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }
}

结果:

技术图片

6.2使用ImportSelector

  • 在配置类中(MainConfig2.class)加一个注解:@Import({Color.class, Red.class, MyImportSelector.class})
public class MyImportSelector implements ImportSelector {
    //返回值就是想要导入到容器中的组件的全类名
    //AnnotationMetadata:当前标注@import的类的所有注解信息
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.ciss.bean.Blue","com.ciss.bean.Yellow"};
    }
}
  • 测试一哈:代码同上

技术图片

6.3实现ImportBeanDefinitionRegistrar接口,自己注册组件

  • 在配置类中(MainConfig2.class)加一个注解:@Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
  • 然后:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /**
     *
     * @param importingClassMetadata:当前类的注解信息
     * @param registry :把所有需要添加到容器中的bean,
     *                   调用BeanDefinitionRegistry的registerBeanDefinition手工注册进来
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean red = registry.containsBeanDefinition("com.ciss.bean.Red");
        boolean blue = registry.containsBeanDefinition("com.ciss.bean.Blue");
        if (red&&blue){
            //指定bean名
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainRow.class);
            registry.registerBeanDefinition("RainRow", rootBeanDefinition);
        }
    }
}
  • 测试一哈:代码同上

技术图片

使用Spring提供的FactoryBean(工厂Bean)注册组件

/*使用Spring提供的FactoryBean(工厂Bean)注册组件
*      1)默认获取到的是工厂bean调用getObject创建的对象
*      2)要获取工厂Bean本身,我们需要给id前面加一个&
*          例如:&colorFactoryBean
*/
public class ColorFactoryBean implements FactoryBean<Color> {
    @Override
    //工厂bean获取的是调用getObject创建的对象
    public Color getObject() throws Exception {
        System.out.println("ColorFactory Bean...");
        return new Color();
    }

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

    @Override
    //是否是单实例
    public boolean isSingleton() {
        return true;
    }
}

技术图片

生命周期

方式

  1. 指定初始化和销毁方法
    • 通过@bean指定init-method和destroy-method
  2. 通过让Bean实现InitializingBean接口(定义初始化逻辑)
    - DisposableBean接口(定义销毁方法)
  3. 可以使用JSR250
    • @see javax.annotation.PostConstruct:在bean创建完成并且属性赋值完成,再执行初始化方法
    • @see javax.annotation.PreDestroy:在容器销毁bean之前通知我们进行清理工作

@Bean指定初始化和销毁方法

1.1通过@bean指定init-method和destroy-method

  • 创建一个bean
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..");
    }
}
/**
 * bean创建--初始化--销毁的过程
 * 容器管理bean的生命周期;
 * 可以自定义初始化和销毁方法,容器bean进行到当前生命周期来调用我们自定义的初始化和销毁方法
 *
 * 构造(对象创建)
 *      单实例:在容器启动的时候创建对象
 *      多实例:在每次获取的时候创建对象
 * 初始化:
 *       对象创建完成,并赋值好,调用初始方法。
  * 销毁:
 *      单实例:容器关闭的时候
 *      多实例:容器不会管理这个bean,容器不会调用销毁方法。
 
 */
@Configuration
public class MainConfigOfLifeCycle {
    @Bean(initMethod = "init",destroyMethod = "destroy")
    public Car car(){
        return new Car();
    }
}
  • 测试一哈:
@Test
public void test04(){
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
    System.out.println("容器创建完成。。");
    applicationContext.close();
}

1.2实现InitializingBean、DisposableBean接口

@Component
public class Cat implements InitializingBean, DisposableBean {
    public Cat() {
        System.out.println("cat constructor..");
    }

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

    @Override
    public void destroy() throws Exception {
        System.out.println("cat..destroy..");
    }
}
  • 测试代码同上

1.3使用JSR250

@Component
public class Dog {
    public Dog() {
        System.out.println("dog...constructor..");
    }
    @PostConstruct
    public void init(){
        System.out.println("dog...postConstructor..");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("dog..predestroy");
    }
}
  • 测试代码同上

实现接口:BeanPostProcessor后置处理器

  • postProcessBeforeInitialization方法:在bean初始化之前调用

  • postProcessAfterInitialization方法:在bean初始化之后调用

  • 源码原理:

    1. populateBean(beanName, mbd, instanceWrapper);//给bean进行属性赋值
    2. initializeBean(beanName, exposedObject, mbd);
    {
        applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        invokeInitMethods(beanName, wrappedBean, mbd);//执行bean自定义初始化
        applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization"+s);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization"+s);
        return o;
    }
}
  • 测试代码同上

  • 总结:Spring底层对BeanPostProcessor的使用

    • bean赋值、注入其他组件、@Autowired、生命周期注解功能,@Async、xxxBeanProcessor

属性赋值

@Value、@PropertySource(加到配置类上)赋值

  • 以前的配置文件写法:
<context:property-placeholder location="classpath:personproperties"></context:property-placeholder>

现在的写法

  • 创建一个Bean

    public class Person {
        /**
         * 使用@Value赋值
         * 1. 基本数值
         * 2. 可以写SpEl;#{}
         * 3.可以写${};取出配置文件的值(在运行环境变量里面的值)
         */
        @Value("张三")
        private String name;
        @Value("#{20-2}")
        private  Integer age;
        @Value("${person.nickName}")
        private String nickName;
        /**
        *set、get、toString 方法略
        */
    
  • 创建一个配置类

    //读取外部配置文件中的k-v,保存到运行的环境变量中
    @PropertySource("classpath:person.properties")
    @Configuration
    public class MainConfigOfPropertyValues {
        @Bean
        public Person person() {
            return new Person();
        }
    }
    
  • 创建一个配置文件

person.nickName=小张三
  • 测试一哈:
@Test
public void test01(){
    printBeans(applicationContext);
    System.out.println("===============");
    Person person = (Person) applicationContext.getBean("person");
    System.out.println(person);
    applicationContext.close();
}

private void printBeans(AnnotationConfigApplicationContext annotationConfigApplicationContext){
    String[] names = annotationConfigApplicationContext.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
}
  • 结果:

技术图片

  • 若想取到配置文件中的值,还可以用如下办法(在上面的test方法添加如下代码):
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty("person.nickName");
System.out.println(property);
  • 结果:

技术图片

自动装配

@Autowired、@Qualifier、@Primary

/**
 * 自动装配:
 *      Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值;
 * 1)@AutoWired :自动注入
 *      1)默认优先按照类型去容器中找对应的的组件;
 *      2)如果找到多个类型相同的组件,再将属性的名称作为组件的id去容器中查找
 *      3)@Qualifier :使用@Qualifier指定需要装配的组件的id,而不是使用属性名
 *      4)自动装配 在默认情况下 一定要将属性赋值好,没有就会报错;
 *                            可以使用@Autowired(required = false)就不会报错了
 *      5)@Primary: 让Spring进行自动装配的时候,默认使用首选的bean;
 *                  也可以继续使用@Qualifier指定
 注: @Qualifier 和 @AutoWired 一 起
 	 @Primary 加在 注册的bean组件 上
 */
  • BookDao(名字默认是类名首字母小写
//名字默认是类名首字母小写
@Repository
public class BookDao {
    private  String label="1";

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    @Override
    public String toString() {
        return "BookDao{" +
                "label=‘" + label + ‘‘‘ +
                ‘}‘;
    }
}
  • 配置类
@Configuration
@ComponentScan({"com.ciss.service","com.ciss.dao","com.ciss.controller"})
public class MainConfigOfAutoWired {
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setLabel("2");
        return bookDao;
    }
}
  • BookService
@Service
public class BookService {
    @Autowired
    @Qualifier("bookDao2")
    private BookDao bookDao;

    @Override
    public String toString() {
        return "BookService{" +
                "bookDao=" + bookDao +
                ‘}‘;
    }
}
  • 测试一哈:
public class IOCTest_AutoWired {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigOfAutoWired.class);
    @Test
    public void test01(){
        BookService bookService = applicationContext.getBean(BookService.class);
        System.out.println(bookService);
    }
}
  • 结果:
    • 不加 @Qualifier("bookDao2")时,是label=‘1’
    • 加 @Qualifier("bookDao2")时,如下图:

技术图片

@Resource、@Inject

/*2)Spring还支持使用@Resource(JSR250)和@Inject(JSR330)【java规范的注解】
*  @Resource:
*      可以和@AutoWired一样实现自动装配功能,默认是按照组件名称进行装配的;
*      但是没有支持@Primary和@Autowired(required = false)
* @Inject:
* 		需要导入Javax.inject的包,和Autowired功能一样,但是没有支持@Primary和@Autowired(required = false)
*/

@AutoWired :放在构造器、方法、属性

/*@AutoWired :放在构造器、方法、属性;都是从IOC容器中获取参数组件的值
*      1)【标注在方法位置】
*      2)【标在构造器上】;如果组件只有一个有参构造器,那么这个有参构造器的@AutoWired可以省略,参数位置的组件还是可以自动从容器中获取
*      3) 【放在参数位置】
*/
@Component
public class Boss {
    private Car car;
	
    //@Autowired
    public Boss( @Autowired Car car) {//这个@Autowired可以省略!
        //也就是说:如果不加@Autowired,有参构造器中也是默认有@Autowired的 
        this.car = car;
    }
    
    public Car getCar() {
        return car;
    }
    //@Autowired
    public void setCar(@Autowired  Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "Boss{" +
                "car=" + car +
                ‘}‘;
    }
}
@Component
public class Car {
    
}
  • 测试一哈:
Boss boss = applicationContext.getBean(Boss.class);
System.out.println(boss);
Car car = applicationContext.getBean(Car.class);
System.out.println(car);
  • 结果:同一个Car

    技术图片

还有一种特别重要的用法

//在配置类中加入组件,应该先将Car加入到IOC容器中
@Bean
public Color color(@Autowired Car car){//@Autowired不加,也默认存在!
    Color color = new Color();
    color.setCar(car);
    return color;
}
  • 测试一哈:
Color color = applicationContext.getBean(Color.class);
System.out.println(color);
  • 结果:用的都是IOC容器中那个Car

技术图片

Aware注入Spring底层组件原理

/*自定义组件想要使用Spring容器底层的一些组件(例如:ApplicationContext,BeanFactory,xxx),
*      可以自定义组件实现xxxAware接口:在创建对象的时候,会调用接口规定的方法注入相关组件;Aware
* 把Spring底层一些组件注入到自定义的bean中;
*         xxxAware:功能使用xxxProcessor; 
* 		  例如,ApplicationContextAware ==》ApplicationContextAwareProcessor
*/
@Component//加入到IOC容器中,就自动回调这些方法了
public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware{
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("IOC:"+applicationContext);
        this.applicationContext=applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("当前bean的名字:"+name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        String s = resolver.resolveStringValue("你好,${os.name} ,#{18*42}");
        System.out.println("字符串:"+s);
    }
}
  • 结果:

技术图片

  • 源码分析

    技术图片

技术图片

若是ApplicationContextAware的实例,则调用setApplicationContext方法

技术图片

@Profile根据环境注册bean

  • 引入依赖
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
  • 配置类(注意看赋值的三种方式
/**
 * Profile:
 *      Spring为我们提供的可以根据当前环境,动态激活和切换一系列组建的功能
 *
 *   开发环境、测试环境、生产环境
 *   数据源:A 、B 、C
 *   @Profile: 指定组件在哪个环境下才能被注册到容器中,不指定时,任何环境都能注册这个组件。
 *   1)加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中,默认是default环境
 *   2)若写在配置类上,只有是指定环境的时候,整个配置类里面的所有配置才能开始生效
 *   3)没有标注环境标识的bean,在任何环境下都是加载的
 */
@Configuration
@PropertySource("classpath:/jdbcConfig.properties")
public class MainConfigOfProfile implements EmbeddedValueResolverAware {

    @Value("${jdbc.user}")
    private String user;
    private StringValueResolver stringValueResolver;
    private String driverClass;

    @Bean
    @Profile("test")
    public DataSource dataSourceTest(@Value("${jdbc.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setDriverClass(driverClass);
        return null;
    }

    @Bean
    @Profile("dev")
    public DataSource dataSourceDev(@Value("${jdbc.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/jdbc");
        dataSource.setDriverClass(driverClass);
        return null;
    }

    @Bean
    @Profile("prod")
    public DataSource dataSourceProd(@Value("${jdbc.password}") String pwd) throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(pwd);
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_cache");
        dataSource.setDriverClass(driverClass);
        return null;
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        this.stringValueResolver=resolver;
        driverClass = stringValueResolver.resolveStringValue("com.mysql.jdbc.Driver");
    }
}
  • 测试一哈:

    public class IOCTest_Profile {
        //1. 使用命令行参数的形式:在虚拟机参数位置加载 -Dspring.profiles.active=dev
        
        AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
        @Test
        public void test01(){
            String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
            for (String s : beanNamesForType) {
                System.out.println(s);
            }
        }
    
    }
    ===================================================================
    //2. 使用代码的方式
    @Test
    public void test02(){
        //设置需要激活的环境
        applicationContext.getEnvironment().setActiveProfiles("test","prod");
        //注册主配置类
        applicationContext.register(MainConfigOfProfile.class);
        //启动刷新容器
        applicationContext.refresh();
        String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
            for (String s : beanNamesForType) {
                System.out.println(s);
            }
        }
    
    • 使用代码的方式的原理

      有参构造器就直接将组件注册刷新了。所以可以调无参构造器,然后自己手动注册刷新!

    技术图片

    • 默认是default环境

技术图片

结果:

技术图片

AOP

AOP功能测试及原理

  • 导入依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>
  • 以前的xml中需要加入如下:
<!--开启基于注解版的切面功能-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
/**
 * AOP:【动态代理】
 *      是指程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
 * 1. 导入aop模块 :spring-aspects
 * 2. 定义一个业务逻辑类:MathCalculator,在业务逻辑运行的时候进行日志打印【方法之前、运行结束、异常等等】
 * 3. 定义一个日志切面类:LogAspects,切面类里面的方法需要动态感知MathCalculator.div运行的状态
 * 4. 将切面类和业务逻辑类都加入到IOC容器中
 * 5. 告诉Spring那个类是切面类【给切面类加注解:@Aspect】
 * 6. 【重要!!】必须给配置类中加@EnableAspectJAutoProxy注解【启用基于注解的Aop模式】
 三步:
 * 	1)、将业务逻辑组件和切面类都加入到容器中;告诉Spring哪个是切面类(@Aspect)
 * 	2)、在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
 *  3)、开启基于注解的aop模式;@EnableAspectJAutoProxy
 *  
 * AOP原理:【看给容器中注册了什么组件,这个组件什么时候工作,这个组件的功能是什么?】
 * 		@EnableAspectJAutoProxy;
 * 1、@EnableAspectJAutoProxy是什么?
 * 		@Import(AspectJAutoProxyRegistrar.class):给容器中导入AspectJAutoProxyRegistrar
 * 			利用AspectJAutoProxyRegistrar自定义给容器中注册bean;BeanDefinetion
 * 			internalAutoProxyCreator=AnnotationAwareAspectJAutoProxyCreator
 * 
 * 		给容器中注册一个AnnotationAwareAspectJAutoProxyCreator;
 * 
 * 2、 AnnotationAwareAspectJAutoProxyCreator:
 * 		AnnotationAwareAspectJAutoProxyCreator
 * 			->AspectJAwareAdvisorAutoProxyCreator
 * 				->AbstractAdvisorAutoProxyCreator
 * 					->AbstractAutoProxyCreator
 * 							implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
 * 						关注后置处理器(在bean初始化完成前后做事情)、自动装配BeanFactory
 * 
 * AbstractAutoProxyCreator.setBeanFactory()
 * AbstractAutoProxyCreator.有后置处理器的逻辑;
 * 
 * AbstractAdvisorAutoProxyCreator.setBeanFactory()-》initBeanFactory()
 * 
 * AnnotationAwareAspectJAutoProxyCreator.initBeanFactory()
 *
 *
 * 流程:
 * 		1)、传入配置类,创建ioc容器
 * 		2)、注册配置类,调用refresh()刷新容器;
 * 		3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;
 * 			1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
 * 			2)、给容器中加别的BeanPostProcessor
 * 			3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
 * 			4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
 * 			5)、注册没实现优先级接口的BeanPostProcessor;
 * 			6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
 * 				创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
 * 				1)、创建Bean的实例
 * 				2)、populateBean;给bean的各种属性赋值
 * 				3)、initializeBean:初始化bean;
 * 						1)、invokeAwareMethods():处理Aware接口的方法回调
 * 						2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
 * 						3)、invokeInitMethods();执行自定义的初始化方法
 * 						4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
 * 				4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
 * 			7)、把BeanPostProcessor注册到BeanFactory中;
 * 				beanFactory.addBeanPostProcessor(postProcessor);
 * =======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程========
 * 
 * 			AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBeanPostProcessor
 * 		4)、finishBeanFactoryInitialization(beanFactory);完成BeanFactory初始化工作;创建剩下的单实例bean
 * 			1)、遍历获取容器中所有的Bean,依次创建对象getBean(beanName);
 * 				getBean->doGetBean()->getSingleton()->
 * 			2)、创建bean
 * 				【AnnotationAwareAspectJAutoProxyCreator在所有bean创建之前会有一个拦截,InstantiationAwareBeanPostProcessor,会调用postProcessBeforeInstantiation()】
 * 				1)、先从缓存中获取当前bean,如果能获取到,说明bean是之前被创建过的,直接使用,否则再创建;
 * 					只要创建好的Bean都会被缓存起来
 * 				2)、createBean();创建bean;
 * 					AnnotationAwareAspectJAutoProxyCreator 会在任何bean创建之前先尝试返回bean的实例
 * 					【BeanPostProcessor是在Bean对象创建完成初始化前后调用的】
 * 					【InstantiationAwareBeanPostProcessor是在创建Bean实例之前先尝试用后置处理器返回对象的】
 * 					1)、resolveBeforeInstantiation(beanName, mbdToUse);解析BeforeInstantiation
 * 						希望后置处理器在此能返回一个代理对象;如果能返回代理对象就使用,如果不能就继续
 * 						1)、后置处理器先尝试返回对象;
 * 							bean = applyBeanPostProcessorsBeforeInstantiation():
 * 								拿到所有后置处理器,如果是InstantiationAwareBeanPostProcessor;
 * 								就执行postProcessBeforeInstantiation
 * 							if (bean != null) {
								bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
							}
 * 
 * 					2)、doCreateBean(beanName, mbdToUse, args);真正的去创建一个bean实例;和3.6流程一样;
 * 					3)、
 * 			
 * 		
 * AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】	的作用:
 * 1)、每一个bean创建之前,调用postProcessBeforeInstantiation();
 * 		关心MathCalculator和LogAspect的创建
 * 		1)、判断当前bean是否在advisedBeans中(保存了所有需要增强bean)
 * 		2)、判断当前bean是否是基础类型的Advice、Pointcut、Advisor、AopInfrastructureBean,
 * 			或者是否是切面(@Aspect)
 * 		3)、是否需要跳过
 * 			1)、获取候选的增强器(切面里面的通知方法)【List<Advisor> candidateAdvisors】
 * 				每一个封装的通知方法的增强器是 InstantiationModelAwarePointcutAdvisor;
 * 				判断每一个增强器是否是 AspectJPointcutAdvisor 类型的;返回true
 * 			2)、永远返回false
 * 
 * 2)、创建对象
 * postProcessAfterInitialization;
 * 		return wrapIfNecessary(bean, beanName, cacheKey);//包装如果需要的情况下
 * 		1)、获取当前bean的所有增强器(通知方法)  Object[]  specificInterceptors
 * 			1、找到候选的所有的增强器(找哪些通知方法是需要切入当前bean方法的)
 * 			2、获取到能在bean使用的增强器。
 * 			3、给增强器排序
 * 		2)、保存当前bean在advisedBeans中;
 * 		3)、如果当前bean需要增强,创建当前bean的代理对象;
 * 			1)、获取所有增强器(通知方法)
 * 			2)、保存到proxyFactory
 * 			3)、创建代理对象:Spring自动决定
 * 				JdkDynamicAopProxy(config);jdk动态代理;
 * 				ObjenesisCglibAopProxy(config);cglib的动态代理;
 * 		4)、给容器中返回当前组件使用cglib增强了的代理对象;
 * 		5)、以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程;
 * 		
 * 	
 * 	3)、目标方法执行	;
 * 		容器中保存了组件的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象,xxx);
 * 		1)、CglibAopProxy.intercept();拦截目标方法的执行
 * 		2)、根据ProxyFactory对象获取将要执行的目标方法拦截器链;
 * 			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
 * 			1)、List<Object> interceptorList保存所有拦截器 5
 * 				一个默认的ExposeInvocationInterceptor 和 4个增强器;
 * 			2)、遍历所有的增强器,将其转为Interceptor;
 * 				registry.getInterceptors(advisor);
 * 			3)、将增强器转为List<MethodInterceptor>;
 * 				如果是MethodInterceptor,直接加入到集合中
 * 				如果不是,使用AdvisorAdapter将增强器转为MethodInterceptor;
 * 				转换完成返回MethodInterceptor数组;
 * 
 * 		3)、如果没有拦截器链,直接执行目标方法;
 * 			拦截器链(每一个通知方法又被包装为方法拦截器,利用MethodInterceptor机制)
 * 		4)、如果有拦截器链,把需要执行的目标对象,目标方法,
 * 			拦截器链等信息传入创建一个 CglibMethodInvocation 对象,
 * 			并调用 Object retVal =  mi.proceed();
 * 		5)、拦截器链的触发过程;
 * 			1)、如果没有拦截器执行执行目标方法,或者拦截器的索引和拦截器数组-1大小一样(指定到了最后一个拦截器)执行目标方法;
 * 			2)、链式获取每一个拦截器,拦截器执行invoke方法,每一个拦截器等待下一个拦截器执行完成返回以后再来执行;
 * 				拦截器链的机制,保证通知方法与目标方法的执行顺序;
 * 		
 * 	总结:
 * 		1)、  @EnableAspectJAutoProxy 开启AOP功能
 * 		2)、 @EnableAspectJAutoProxy 会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
 * 		3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器;
 * 		4)、容器的创建流程:
 * 			1)、registerBeanPostProcessors()注册后置处理器;创建AnnotationAwareAspectJAutoProxyCreator对象
 * 			2)、finishBeanFactoryInitialization()初始化剩下的单实例bean
 * 				1)、创建业务逻辑组件和切面组件
 * 				2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程
 * 				3)、组件创建完之后,判断组件是否需要增强
 * 					是:切面的通知方法,包装成增强器(Advisor);给业务逻辑组件创建一个代理对象(cglib);
 * 		5)、执行目标方法:
 * 			1)、代理对象执行目标方法
 * 			2)、CglibAopProxy.intercept();
 * 				1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
 * 				2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;
 * 				3)、效果:
 * 					正常执行:前置通知-》目标方法-》后置通知-》返回通知
 * 					出现异常:前置通知-》目标方法-》后置通知-》异常通知
 * 		
 */
@Configuration
@EnableAspectJAutoProxy
public class MainConfigOfAOP {

    //将业务逻辑类都加入到IOC容器中
    @Bean
    public MathCalculator mathCalculator(){
        return new MathCalculator();
    }
    //切面类加入到IOC容器中
    @Bean
    public LogAspects logAspects(){
        return new LogAspects();
    }
}
  • 定义一个业务逻辑类:MathCalculator

    public class MathCalculator {
    
        public int div(int i, int j){
            return i/j;
        }
    }
    
  • 定义一个日志切面类:LogAspects

  @Aspect//告诉spring哪个是切面类
  public class LogAspects {
  
      //抽取公共的切入点表达式
      //1. 本类使用
      //2. 其他的切面引用(加全类名就行)
      @Pointcut("execution(public int com.ciss.aop.MathCalculator.*(..))")
      //使用一个返回值为void,方法体为空的方法来命名切入点,方法名即为切点名
      public void pointCut(){}
  
      @Before("pointCut()")
      public void logStart(JoinPoint joinPoint){
          Object[] args = joinPoint.getArgs();
          System.out.println(joinPoint.getSignature().getName()+"运行。。。参数列表是:{ "+ Arrays.asList(args) +"}");
      }
      //无论方法正常结束还是异常结束,都会调用
      @After("pointCut()")
      public void logEnd(JoinPoint joinPoint){
          System.out.println(joinPoint.getSignature().getName()+"结束。。");
      }
      @AfterReturning(value = "pointCut()",returning = "result")
      public void logReturn(JoinPoint joinPoint ,Object result){
          //【注意】joinPoint必须出现在参数列表的第一位
          System.out.println(joinPoint.getSignature().getName()+"正常返回。。。结果是:{ "+result+"}");
      }
      @AfterThrowing(value = "pointCut()",throwing = "exception")
      public void logException(JoinPoint joinPoint ,Exception exception){
          System.out.println(joinPoint.getSignature().getName()+"异常。。。异常是:{"+exception.getMessage()+"}");
      }
  }
  • 测试一哈:
public class IOCTest_AOP {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
    @Test
    public void test01(){
        //想要用AOP功能,须从容器中获取已注册的业务逻辑类
        MathCalculator mathCalculator = applicationContext.getBean(MathCalculator.class);
        int div = mathCalculator.div(1, 0);
    }

}
  • 结果:

技术图片

声明式事务

环境搭建及测试

  • 新建配置类
/**
 *声明式事务
 *
 * 环境搭建:
 * 1、导入相关依赖:
 *          数据源、数据库驱动、Spring-jdbc模块
 * 2、配置数据源、jdbcTemplate操作数据
 * 3、给方法标注@Transactional 表示当前方法是一个事务方法
 * 4、@EnableTransactionManagement开启基于注解的事务管理功能
 * 5、配置事务管理器来控制事务
 *     @Bean
 *     public PlatformTransactionManager platformTransactionManager()
 */
@EnableTransactionManagement
@Configuration
@ComponentScan("com.ciss.tx")
@PropertySource("classpath:/jdbcConfig.properties")
public class TxConfig {

    @Value("${jdbc.user}")
    private String user;
    @Value("${jdbc.password}")
    private  String password;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.driverClass}")
    private String driverClass;
    @Bean
    public DataSource dataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setUser(user);
        dataSource.setPassword(password);
        dataSource.setJdbcUrl(url);
        dataSource.setDriverClass(driverClass);
        return dataSource;
    }
    @Bean
    public JdbcTemplate jdbcTemplate() throws PropertyVetoException {
        //spring对@Configuration类会特殊处理,给容器加组件的方法,多次调用都只是从容器中找组件
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
        return jdbcTemplate;
    }
    //注册事务管理器在容器中
    @Bean
    public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException {
        return new DataSourceTransactionManager(dataSource());
    }
}

  • Dao层
@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    public int insertUser(){
        String sql="INSERT INTO tbl_user(username,age) VALUES(?,?)";
        String s = UUID.randomUUID().toString().substring(0, 5);
        int i = jdbcTemplate.update(sql, s, 18);
        return i;
    }
}
  • Service层
@Service
public class UserService {

    @Autowired
    private UserDao userDao;
    //表示这是一个事务方法,如果有异常出现,就回回滚。
    @Transactional
    public void insertUser(){
        int i = userDao.insertUser();
        int j=10/0;
        if (i != 0) {
            System.out.println("插入完成。");
        }
    }
}
  • 测试一哈
public class IOCTest_tx {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(TxConfig.class);
    @Test
    public void test01(){
        UserService userService = applicationContext.getBean(UserService.class);
        userService.insertUser();
    }
}
  • 结果:

加了@Transactional注解就回回滚,不加就不会回滚啦。

【源码】声明式事务

 /*原理:
* 1)@EnableTransactionManagement
*          利用TransactionManagementConfigurationSelector给容器导入;
*          两个组件
*          AutoProxyRegistrar
*          ProxyTransactionManagementConfiguration
* 2)AutoProxyRegistrar:
*          给容器中注册一个InfrastructureAdvisorAutoProxyCreator组件;
*          利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用
* 3)ProxyTransactionManagementConfiguration:
*          1.给容器中注册事务增强器要用事务注解的信息:AnnotationTransactionAttributeSource解析事务注解
*          2.事务拦截器:
*                  TransactionInterceptor:保存了事务属性信息,事务管理器;他是一个MethodInterceptor
*                  在目标方法执行的时候;
*                      执行拦截器链;
*                      事务拦截器;
*                          1)、先获取事务相关的属性TransactionAttribute
*                          2)、再获取PlatformTransactionManager,如果事先没有添加指定的TransactionManager,最终会从容器中按照类型获取一个PlatformTransactionManager(即自定义的);
*                          3)、执行目标方法
*                              如果异常,获取到事务管理器,利用事务管理器回滚操作。
*                              如果正常,利用事务管理器提交事务。
*/

扩展原理

BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

/**
 * 扩展原理:
 * BeanPostProcessor:bean后置处理器,bean创建对象初始化前后进行拦截工作的
 * 1、BeanFactoryPostProcessor:BeanFactory后置处理器
 *          在BeanFactory标准初始化之后调用;所有的bean定义已经保存加载到BeanFactory,但是bean的实例还未创建。
 *
 * 步骤:
 *      1)ioc容器创建对象
 *      2)invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessors
 *          如何找到所有的执行BeanFactoryPostProcessor并执行他们的方法??
 *              1)直接在BeanFactory中找到所有类型是BeanFactoryPostProcessor的组件,并执行他们的方法。
 *              2)步骤1在初始化创建其他组件前面执行。
 * 
 *2、BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor
 *          方法:postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
 *          在所有bean定义信息将要被加载,bean实例还未创建的时候
 *          优先于BeanFactoryPostProcessor执行,可以利用BeanDefinitionRegistryPostProcessor给容器中再额外添加一些组件
 *
 */
@Configuration
@ComponentScan("com.ciss.ext")
public class ExtConfig {

    @Bean
    public Blue blue(){
        return new Blue();
    }

}
  • 自己定义BeanFactoryPostProcessor
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor....postProcessBeanFactory....");
        int count = beanFactory.getBeanDefinitionCount();
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        System.out.println("当前beanFactory中有"+count+"个bean");
        System.out.println(Arrays.asList(beanDefinitionNames));
    }
}
  • 自己定义BeanDefinitionRegistryPostProcessor
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    //BeanDefinitionRegistry :bean定义信息的保存中心,以后BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个bean定义信息创建bean实例
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        System.out.println("postProcessBeanDefinitionRegistry....bean数量:"+registry.getBeanDefinitionCount());
        //RootBeanDefinition beanDefinition = new RootBeanDefinition(Blue.class);
        //或者
        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Blue.class).getBeanDefinition();
        registry.registerBeanDefinition("hello",beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanDefinitionRegistryPostProcessor....bean数量:"+beanFactory.getBeanDefinitionCount());
    }
}
  • 测试一哈:
public class IOCTest_ext {
    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(ExtConfig.class);
    @Test
    public void test01(){
    }
}
  • 结果:

技术图片

ApplicationListener

  • 【原理】
  /*3、ApplicationListener:监听容器中发布的事件,事件驱动模型开发;
   *      public interface ApplicationListener<E extends ApplicationEvent> extends EventListener
   *      监听ApplicationEvent及下面的子事件
   * 步骤:
   *   1)写一个监听器来监听某个事件(ApplicationEvent及其子类)
   *       或者用@EventListener
   *原理:使用EventListenerMethodProcessor处理器来解析方法上的@EventListener;
   *   2)把监听器加入到容器中
   *   3)只要容器中有相关事件的发布,我们就能监听到这个事件
   *          ContextRefreshedEvent:容器刷新完成(所有bean都完全创建)会发布这个事件
  *    4)自定义发布一个事件:
   * 【原理】
      ContextRefreshedEvent、IOCTest_Ext$1[source=我发布的时间]、ContextClosedEvent;
   *  1)、ContextRefreshedEvent事件:
   *     1)、容器创建对象:refresh();
   *     2)、finishRefresh();容器刷新完成会发布ContextRefreshedEvent事件
   *  2)、自己发布事件;
   *  3)、容器关闭会发布ContextClosedEvent;
   *
   *  【事件发布流程】:
   *     3)、publishEvent(new ContextRefreshedEvent(this));
   *           1)、获取事件的多播器(派发器):getApplicationEventMulticaster()
   *           2)、multicastEvent派发事件:
   *           3)、获取到所有的ApplicationListener;
   *              for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
   *              1)、如果有Executor,可以支持使用Executor进行异步派发;
   *                 Executor executor = getTaskExecutor();
   *              2)、否则,同步的方式直接执行listener方法;invokeListener(listener, event);
   *               拿到listener回调onApplicationEvent方法;
   *
   *  【事件多播器(派发器)】
   *     1)、容器创建对象:refresh();
   *     2)、initApplicationEventMulticaster();初始化ApplicationEventMulticaster;
   *        1)、先去容器中找有没有id=“applicationEventMulticaster”的组件;
   *        2)、如果没有this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
   *           并且加入到容器中,我们就可以在其他组件要派发事件,自动注入这个applicationEventMulticaster;
   *
   *  【容器中有哪些监听器】
   *     1)、容器创建对象:refresh();
   *     2)、registerListeners();
   *        从容器中拿到所有的监听器,把他们注册到applicationEventMulticaster中;
   *        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
   *        //将listener注册到ApplicationEventMulticaster中
   *        getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
   *
   *   SmartInitializingSingleton 原理:->afterSingletonsInstantiated();
   *        1)、ioc容器创建对象并refresh();
   *        2)、finishBeanFactoryInitialization(beanFactory);初始化剩下的单实例bean;
   *           1)、先创建所有的单实例bean;getBean();
   *           2)、获取所有创建好的单实例bean,判断是否是SmartInitializingSingleton类型的;
   *              如果是就调用afterSingletonsInstantiated();
   */
  • 自定义ApplicationListener
@Component
public class MyApplicationListener implements ApplicationListener {
    //当容器中发布此事件以后,方法触发
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("收到事件:"+event);
    }
}

【或者】使用@EventListener注解

@Service
public class UserService {

    //EventListener要监听的事件
    @EventListener(ApplicationEvent.class)
    public void listen(ApplicationEvent event){
        System.out.println("UserService..监听到的事件:"+event);
    }
}
  • 结果

技术图片

【Spring容器创建过程源码剖析】

Spring容器的refresh()【创建刷新】

1、prepareRefresh()刷新前的预处理;
1)、initPropertySources()初始化一些属性设置;子类自定义个性化的属性设置方法;
2)、getEnvironment().validateRequiredProperties();检验属性的合法等
3)、earlyApplicationEvents= new LinkedHashSet();保存容器中的一些早期的事件;
2、obtainFreshBeanFactory();获取BeanFactory;
1)、refreshBeanFactory();刷新【创建】BeanFactory;
创建了一个this.beanFactory = new DefaultListableBeanFactory();
设置id;
2)、getBeanFactory();返回刚才GenericApplicationContext创建的BeanFactory对象;
3)、将创建的BeanFactory【DefaultListableBeanFactory】返回;
3、prepareBeanFactory(beanFactory);BeanFactory的预准备工作(BeanFactory进行一些设置);
1)、设置BeanFactory的类加载器、支持表达式解析器...
2)、添加部分BeanPostProcessor【ApplicationContextAwareProcessor】
3)、设置忽略的自动装配的接口EnvironmentAware、EmbeddedValueResolverAware、xxx;
4)、注册可以解析的自动装配;我们能直接在任何组件中自动注入
BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext
5)、添加BeanPostProcessor【ApplicationListenerDetector】
6)、添加编译时的AspectJ;
7)、给BeanFactory中注册一些能用的组件;
environment【ConfigurableEnvironment】、
systemProperties【Map<String, Object>】、
systemEnvironment【Map<String, Object>】
4、postProcessBeanFactory(beanFactory);BeanFactory准备工作完成后进行的后置处理工作;
1)、子类通过重写这个方法来在BeanFactory创建并预准备完成以后做进一步的设置
以上是BeanFactory的创建及预准备工作
5、invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法;
BeanFactoryPostProcessor:BeanFactory的后置处理器。在BeanFactory标准初始化之后执行的;
两个接口:BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
执行BeanFactoryPostProcessor的方法;
先执行BeanDefinitionRegistryPostProcessor
1)、获取所有的BeanDefinitionRegistryPostProcessor;
2)、看先执行实现了PriorityOrdered优先级接口的BeanDefinitionRegistryPostProcessor、
postProcessor.postProcessBeanDefinitionRegistry(registry)
3)、在执行实现了Ordered顺序接口的BeanDefinitionRegistryPostProcessor;
postProcessor.postProcessBeanDefinitionRegistry(registry)
4)、最后执行没有实现任何优先级或者是顺序接口的BeanDefinitionRegistryPostProcessors;
postProcessor.postProcessBeanDefinitionRegistry(registry)
再执行BeanFactoryPostProcessor的方法
1)、获取所有的BeanFactoryPostProcessor
2)、看先执行实现了PriorityOrdered优先级接口的BeanFactoryPostProcessor、
postProcessor.postProcessBeanFactory()
3)、在执行实现了Ordered顺序接口的BeanFactoryPostProcessor;
postProcessor.postProcessBeanFactory()
4)、最后执行没有实现任何优先级或者是顺序接口的BeanFactoryPostProcessor;
postProcessor.postProcessBeanFactory()
6、registerBeanPostProcessors(beanFactory);注册BeanPostProcessor(Bean的后置处理器)【 intercept bean creation】
不同接口类型的BeanPostProcessor;在Bean创建前后的执行时机是不一样的
BeanPostProcessor、
DestructionAwareBeanPostProcessor、
InstantiationAwareBeanPostProcessor、
SmartInstantiationAwareBeanPostProcessor、
MergedBeanDefinitionPostProcessor【internalPostProcessors】、
1)、获取所有的 BeanPostProcessor;后置处理器都默认可以通过PriorityOrdered、Ordered接口来指定优先级
2)、先注册PriorityOrdered优先级接口的BeanPostProcessor;
把每一个BeanPostProcessor;添加到BeanFactory中
beanFactory.addBeanPostProcessor(postProcessor);
3)、再注册Ordered接口的
4)、最后注册没有实现任何优先级接口的
5)、最终注册MergedBeanDefinitionPostProcessor;
6)、注册一个ApplicationListenerDetector;来在Bean创建完成后检查是否是ApplicationListener,如果是
applicationContext.addApplicationListener((ApplicationListener<?>) bean);
7、initMessageSource();初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
1)、获取BeanFactory
2)、看容器中是否有id为messageSource的,类型是MessageSource的组件
如果有赋值给messageSource,如果没有自己创建一个DelegatingMessageSource;
MessageSource:取出国际化配置文件中的某个key的值;能按照区域信息获取;
3)、把创建好的MessageSource注册在容器中,以后获取国际化配置文件的值的时候,可以自动注入MessageSource;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
MessageSource.getMessage(String code, Object[] args, String defaultMessage, Locale locale);
8、initApplicationEventMulticaster();初始化事件派发器;
1)、获取BeanFactory
2)、从BeanFactory中获取applicationEventMulticaster的ApplicationEventMulticaster;
3)、如果上一步没有配置;创建一个SimpleApplicationEventMulticaster
4)、将创建的ApplicationEventMulticaster添加到BeanFactory中,以后其他组件直接自动注入
9、onRefresh();留给子容器(子类)
1、子类重写这个方法,在容器刷新的时候可以自定义逻辑;
10、registerListeners();给容器中将所有项目里面的ApplicationListener注册进来;
1、从容器中拿到所有的ApplicationListener
2、将每个监听器添加到事件派发器中;
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
3、派发之前步骤产生的事件;
11、finishBeanFactoryInitialization(beanFactory);初始化所有剩下的单实例bean;
1、beanFactory.preInstantiateSingletons();初始化后剩下的单实例bean
1)、获取容器中的所有Bean,依次进行初始化和创建对象
2)、获取Bean的定义信息;RootBeanDefinition
3)、Bean不是抽象的,是单实例的,是懒加载;
1)、判断是否是FactoryBean;是否是实现FactoryBean接口的Bean;
2)、不是工厂Bean。利用getBean(beanName);创建对象
0、getBean(beanName); ioc.getBean();
1、doGetBean(name, null, null, false);
2、先获取缓存中保存的单实例Bean。如果能获取到说明这个Bean之前被创建过(所有创建过的单实例Bean都会被缓存起来)
从private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);获取的
3、缓存中获取不到,开始Bean的创建对象流程;
4、标记当前bean已经被创建
5、获取Bean的定义信息;
6、【获取当前Bean依赖的其他Bean;如果有按照getBean()把依赖的Bean先创建出来;】
7、启动单实例Bean的创建流程;
1)、createBean(beanName, mbd, args);
2)、Object bean = resolveBeforeInstantiation(beanName, mbdToUse);让BeanPostProcessor先拦截返回代理对象;
【InstantiationAwareBeanPostProcessor】:提前执行;
先触发:postProcessBeforeInstantiation();
如果有返回值:触发postProcessAfterInitialization();
3)、如果前面的InstantiationAwareBeanPostProcessor没有返回代理对象;调用4)
4)、Object beanInstance = doCreateBean(beanName, mbdToUse, args);创建Bean
1)、【创建Bean实例】;createBeanInstance(beanName, mbd, args);
利用工厂方法或者对象的构造器创建出Bean实例;
2)、applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition(mbd, beanType, beanName);
3)、【Bean属性赋值】populateBean(beanName, mbd, instanceWrapper);
赋值之前
1)、拿到InstantiationAwareBeanPostProcessor后置处理器;
postProcessAfterInstantiation();
2)、拿到InstantiationAwareBeanPostProcessor后置处理器;
postProcessPropertyValues();

						==赋值之前==

					 		3)、应用Bean属性的值;为属性利用setter方法等进行赋值;
					 		applyPropertyValues(beanName, mbd, bw, pvs);
					 4)、【Bean初始化】initializeBean(beanName, exposedObject, mbd);
					 		1)、【执行Aware接口方法】invokeAwareMethods(beanName, bean);执行xxxAware接口的方法
					 		BeanNameAwareBeanClassLoaderAwareBeanFactoryAware
					 		2)、【执行后置处理器初始化之前】applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
					 		BeanPostProcessor.postProcessBeforeInitialization();
					 		3)、【执行初始化方法】invokeInitMethods(beanName, wrappedBean, mbd);
					 				1)、是否是InitializingBean接口的实现;执行接口规定的初始化;
					 				2)、是否自定义初始化方法;
					 		4)、【执行后置处理器初始化之后】applyBeanPostProcessorsAfterInitialization
					 		BeanPostProcessor.postProcessAfterInitialization();
					 		5)、注册Bean的销毁方法;
			5)、将创建的Bean添加到缓存中singletonObjects;
			ioc容器就是这些Map;很多的Map里面保存了单实例Bean,环境信息。。。。;
	所有Bean都利用getBean创建完成以后;
	检查所有的Bean是否是SmartInitializingSingleton接口的;如果是;就执行afterSingletonsInstantiated();

12、finishRefresh();完成BeanFactory的初始化创建工作;IOC容器就创建完成;
1)、initLifecycleProcessor();初始化和生命周期有关的后置处理器;LifecycleProcessor
默认从容器中找是否有lifecycleProcessor的组件【LifecycleProcessor】;如果没有new DefaultLifecycleProcessor();
加入到容器;
写一个LifecycleProcessor的实现类,可以在BeanFactory
void onRefresh();
void onClose();
2)、 getLifecycleProcessor().onRefresh();
拿到前面定义的生命周期处理器(BeanFactory);回调onRefresh();
3)、publishEvent(new ContextRefreshedEvent(this));发布容器刷新完成事件;
4)、liveBeansView.registerApplicationContext(this);

【总结】
1)、Spring容器在启动的时候,先会保存所有注册进来的Bean的定义信息;
1)、xml注册bean;
2)、注解注册Bean;@Service、@Component、@Bean、xxx
2)、Spring容器会合适的时机创建这些Bean
1)、用到这个bean的时候;利用getBean创建bean;创建好以后保存在容器中;
2)、统一创建剩下所有的bean的时候;finishBeanFactoryInitialization();
3)、后置处理器;BeanPostProcessor
1)、每一个bean创建完成,都会使用各种后置处理器进行处理;来增强bean的功能;
AutowiredAnnotationBeanPostProcessor:处理自动注入
AnnotationAwareAspectJAutoProxyCreator:来做AOP功能;
xxx....
增强的功能注解:
AsyncAnnotationBeanPostProcessor
....
4)、事件驱动模型;
ApplicationListener;事件监听;
ApplicationEventMulticaster;事件派发:

?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?

?































































































































































以上是关于spring注解驱动开发原理剖析的主要内容,如果未能解决你的问题,请参考以下文章

Spring注解驱动开发-----扩展原理

Spring注解驱动开发之AOP容器篇

Spring注解驱动开发之web

Spring2.5学习3.2_编码剖析@Resource注解的实现原理

中高级Java大厂高频面试题,Spring注解驱动开发

Spring全注解开发--扩展原理