Spring底层原理学习笔记--第五讲--(常见工厂后处理器与工厂后处理器模拟实现)

常见工厂后处理器

A05Application.java

java 复制代码
package com.lucifer.itheima.a05;

import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class A05Application {
    public static void main(String[] args) {
        // GenericApplicationContext是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config",Config.class);
        context.registerBean(ConfigurationClassPostProcessor.class);  //能解析@Component @Bean @Import @ImportResource注解
        context.registerBean(MapperScannerConfigurer.class,bd->{  // 能解析@MapperScanner注解
            bd.getPropertyValues().add("basePackage","com.lucifer.itheima.a05.mapper");
        });
        // 初始化容器
        context.refresh();

        for (String name:context.getBeanDefinitionNames()){
            //没有加        context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //config(只有一个bean,也就是Config类中的组件扫描没有生效,Config类中的三个@Bean也没有生效)

            // 加上         context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //bean2
            //bean1
            //sqlSessionFactoryBean
            //dataSource
            System.out.println(name);
        }

        //销毁容器
        context.close();
    }

}

Config.java

java 复制代码
package com.lucifer.itheima.a05;

import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com.lucifer.itheima.a05.component")
public class Config {

    @Bean
    public Bean1 bean1(){
        return new Bean1();
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean(initMethod = "init")
    public DruidDataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
}

Bean1.java

java 复制代码
package com.lucifer.itheima.a05;


public class Bean1 {
}

Bean2.java

java 复制代码
package com.lucifer.itheima.a05.component;

import lombok.extern.slf4j.Slf4j;


@Slf4j
public class Bean2 {
    public Bean2(){
        log.info("我被 Spring 管理啦");
    }
}

Mapper1.java

java 复制代码
package com.lucifer.itheima.a05.mapper;

import org.apache.ibatis.annotations.Mapper;


@Mapper
public interface Mapper1 {
}

Mapper2.java

java 复制代码
package com.lucifer.itheima.a05.mapper;

import org.apache.ibatis.annotations.Mapper;


@Mapper
public interface Mapper2 {
}

工厂后处理器模拟实现-组件扫描1

A05Application.java

java 复制代码
package com.lucifer.itheima.a05;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;


@Component
public class A05Application {

    public static void main(String[] args) throws IOException {
        // GenericApplicationContext是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config",Config.class);
//        context.registerBean(ConfigurationClassPostProcessor.class);  //能解析@Component @Bean @Import @ImportResource注解
//        context.registerBean(MapperScannerConfigurer.class,bd->{  // 能解析@MapperScanner注解
//            bd.getPropertyValues().add("basePackage","com.lucifer.itheima.a05.mapper");
//        });

        ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class,ComponentScan.class);
        if (componentScan != null) {
            for (String p:componentScan.basePackages()) {
                // 输出结果为
                //com.lucifer.itheima.a05.component
                System.out.println(p);

                //com.lucifer.itheima.a05.component -> classpath*:com/lucifer/itheima/a05/component/**/*.class
                String path = "classpath*:" + p.replace(".","/") + "/**/*.class";
                //输出结果为
                //classpath*:com/lucifer/itheima/a05/component/**/*.class
                System.out.println(path);
                CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                //CachingMetadataReaderFactory可以遍历类的原信息
                Resource[] resources = context.getResources(path);
                for (Resource resource : resources){
                    // 输出结果为 file [E:\Project\target\classes\com\lucifer\itheima\a05\component\Bean2.class]
                    System.out.println(resource);
                    MetadataReader reader = factory.getMetadataReader(resource);//会去读取我们的每一个class,这里是Bean2.class
                    //输出结果为
//                    类名:com.lucifer.itheima.a05.component.Bean2
//                    是否加了 @Component:true
//                    是否加了 @Component派生注解:false
//                    类名:com.lucifer.itheima.a05.component.Bean4
//                    是否加了 @Component:false
//                    是否加了 @Component派生注解:true

                    // reader里可以拿到类的一些注解或名字啥的
                    System.out.println("类名:"+reader.getClassMetadata().getClassName()); //reader.getClassMetadata
                    // 会得到类的元信息
                    System.out.println("是否加了 @Component:" + reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
                    System.out.println("是否加了 @Component派生注解:" + reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));
                }
            }
        }

        // 初始化容器
        context.refresh();

        for (String name:context.getBeanDefinitionNames()){
            //没有加        context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //config(只有一个bean,也就是Config类中的组件扫描没有生效,Config类中的三个@Bean也没有生效)

            // 加上         context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //bean2
            //bean1
            //sqlSessionFactoryBean
            //dataSource
            System.out.println(name);
        }

        //销毁容器
        context.close();
    }

}

Bean2.java

java 复制代码
package com.lucifer.itheima.a05.component;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class Bean2 {
    public Bean2(){
        log.info("我被 Spring 管理啦");
    }
}

Bean4.java

java 复制代码
package com.lucifer.itheima.a05.component;

import org.springframework.stereotype.Controller;


@Controller
public class Bean4 {
}

工厂后处理器模拟实现-组件扫描2

A05Application.java

java 复制代码
package com.lucifer.itheima.a05;

import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class A05Application {

    public static void main(String[] args) throws IOException {
        // GenericApplicationContext是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config",Config.class);
//        context.registerBean(ConfigurationClassPostProcessor.class);  //能解析@Component @Bean @Import @ImportResource注解
//        context.registerBean(MapperScannerConfigurer.class,bd->{  // 能解析@MapperScanner注解
//            bd.getPropertyValues().add("basePackage","com.lucifer.itheima.a05.mapper");
//        });

        context.registerBean(ComponentScanPostProcessor.class);

        // 初始化容器
        context.refresh();

        for (String name:context.getBeanDefinitionNames()){
            //没有加        context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //config(只有一个bean,也就是Config类中的组件扫描没有生效,Config类中的三个@Bean也没有生效)

            // 加上         context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //bean2
            //bean1
            //sqlSessionFactoryBean
            //dataSource
            System.out.println(name);
        }

        //销毁容器
        context.close();
    }

}

ComponentScanPostProcessor.java

java 复制代码
package com.lucifer.itheima.a05;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;

import java.io.IOException;


public class ComponentScanPostProcessor implements BeanFactoryPostProcessor {
    @Override   //在context.refresh的时候会调用这个方法
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            ComponentScan componentScan = AnnotationUtils.findAnnotation(Config.class, ComponentScan.class);
            if (componentScan != null) {
                for (String p:componentScan.basePackages()) {
                    // 输出结果为
                    //com.lucifer.itheima.a05.component
                    System.out.println(p);

                    //com.lucifer.itheima.a05.component -> classpath*:com/lucifer/itheima/a05/component/**/*.class
                    String path = "classpath*:" + p.replace(".","/") + "/**/*.class";
                    //输出结果为
                    //classpath*:com/lucifer/itheima/a05/component/**/*.class
                    System.out.println(path);
                    CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
                    //CachingMetadataReaderFactory可以遍历类的原信息
                    Resource[] resources = new PathMatchingResourcePatternResolver().getResources(path);
                    AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
                    for (Resource resource : resources){
                        // 输出结果为 file [E:\Project\target\classes\com\lucifer\itheima\a05\component\Bean2.class]
                        System.out.println(resource);
                        MetadataReader reader = factory.getMetadataReader(resource);//会去读取我们的每一个class,这里是Bean2.class
                        //输出结果为
                        //                    类名:com.lucifer.itheima.a05.component.Bean2
                        //                    是否加了 @Component:true
                        //                    是否加了 @Component派生注解:false
                        //                    类名:com.lucifer.itheima.a05.component.Bean4
                        //                    是否加了 @Component:false
                        //                    是否加了 @Component派生注解:true

                        // reader里可以拿到类的一些注解或名字啥的
                        System.out.println("类名:"+reader.getClassMetadata().getClassName()); //reader.getClassMetadata
                        // 会得到类的元信息
                        AnnotationMetadata annotationMetadata = reader.getAnnotationMetadata();
                        System.out.println("是否加了 @Component:" + reader.getAnnotationMetadata().hasAnnotation(Component.class.getName()));
                        System.out.println("是否加了 @Component派生注解:" + reader.getAnnotationMetadata().hasMetaAnnotation(Component.class.getName()));

                        if (annotationMetadata.hasAnnotation(Component.class.getName()) ||
                            annotationMetadata.hasMetaAnnotation(Component.class.getName())) {
                            AbstractBeanDefinition bd =
                                BeanDefinitionBuilder.genericBeanDefinition(reader.getClassMetadata().getClassName()).getBeanDefinition();
                            if (configurableListableBeanFactory instanceof DefaultListableBeanFactory beanFactory) {
                                String name = generator.generateBeanName(bd, beanFactory);
                                beanFactory.registerBeanDefinition(name,bd);
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

工厂后处理器模拟实现-@Bean

A05Application.java

java 复制代码
package com.lucifer.itheima.a05;

import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class A05Application {

    public static void main(String[] args) throws IOException {
        // GenericApplicationContext是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config",Config.class);
//        context.registerBean(ConfigurationClassPostProcessor.class);  //能解析@Component @Bean @Import @ImportResource注解
//        context.registerBean(MapperScannerConfigurer.class,bd->{  // 能解析@MapperScanner注解
//            bd.getPropertyValues().add("basePackage","com.lucifer.itheima.a05.mapper");
//        });

//        context.registerBean(ComponentScanPostProcessor.class);

        context.registerBean(AtBeanPostProcessor.class);

        // 初始化容器
        context.refresh();

        for (String name:context.getBeanDefinitionNames()){
            //没有加        context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //config(只有一个bean,也就是Config类中的组件扫描没有生效,Config类中的三个@Bean也没有生效)

            // 加上         context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //bean2
            //bean1
            //sqlSessionFactoryBean
            //dataSource
            System.out.println(name);
        }

        //销毁容器
        context.close();
    }

}

AtBeanPostProcessor.java

java 复制代码
package com.lucifer.itheima.a05;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;


public class AtBeanPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/lucifer/itheima/a05/config" +
                                                                                        ".class"));
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method:methods) {
                //输出结果为
                //            com.lucifer.itheima.a05.Config.bean1()
                //            com.lucifer.itheima.a05.Config.dataSource()
                System.out.println(method);
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();

                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                builder.setFactoryMethodOnBean(method.getMethodName(),"config");
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (initMethod.length()>0) {
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition bd = builder.getBeanDefinition();
                if (configurableListableBeanFactory instanceof DefaultListableBeanFactory beanFactory) {
                    beanFactory.registerBeanDefinition(method.getMethodName(),bd);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

工厂后处理器模拟实现-Mapper

A05Application.java

java 复制代码
package com.lucifer.itheima.a05;

import org.springframework.context.support.GenericApplicationContext;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class A05Application {

    public static void main(String[] args) throws IOException {
        // GenericApplicationContext是一个【干净】的容器
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean("config",Config.class);
//        context.registerBean(ConfigurationClassPostProcessor.class);  //能解析@Component @Bean @Import @ImportResource注解
//        context.registerBean(MapperScannerConfigurer.class,bd->{  // 能解析@MapperScanner注解
//            bd.getPropertyValues().add("basePackage","com.lucifer.itheima.a05.mapper");
//        });

//        context.registerBean(ComponentScanPostProcessor.class);  //解析@ComponentScan
//        context.registerBean(AtBeanPostProcessor.class);  //解析@Bean

        context.registerBean(MapperPostProcessor.class);   //解析Mapper接口



        // 初始化容器
        context.refresh();

        for (String name:context.getBeanDefinitionNames()){
            //没有加        context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //config(只有一个bean,也就是Config类中的组件扫描没有生效,Config类中的三个@Bean也没有生效)

            // 加上         context.registerBean(ConfigurationClassPostProcessor.class);的话
            //输出结果为
            //bean2
            //bean1
            //sqlSessionFactoryBean
            //dataSource
            System.out.println(name);
        }

        //销毁容器
        context.close();
    }

}

MapperPostProcessor.java

java 复制代码
package com.lucifer.itheima.a05;

import org.checkerframework.checker.units.qual.A;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;


public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
        try {
            PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = resolver.getResources("classpath:com/lucifer/itheima/a05/mapper/**/*.class");
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            for (Resource resource:resources){
                MetadataReader reader = factory.getMetadataReader(resource);
                ClassMetadata classMetadata = reader.getClassMetadata();
                if (classMetadata.isInterface()) {
                    AbstractBeanDefinition bd =
                        BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class).addConstructorArgValue(classMetadata.getClassName()).setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE).getBeanDefinition();
                    AbstractBeanDefinition bd2 = BeanDefinitionBuilder
                        .genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String name = generator.generateBeanName(bd2,beanFactory);
                    beanFactory.registerBeanDefinition(name,bd);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}
相关推荐
legend_jz1 分钟前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
Komorebi.py2 分钟前
【Linux】-学习笔记04
linux·笔记·学习
乌啼霜满天24917 分钟前
Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系
java·spring boot·spring·mvc
Elaine20239140 分钟前
零碎04 MybatisPlus自定义模版生成代码
java·spring·mybatis
weiabc1 小时前
学习electron
javascript·学习·electron
fengbizhe1 小时前
笔试-笔记2
c++·笔记
余为民同志1 小时前
mini-lsm通关笔记Week2Day4
笔记
墨染风华不染尘1 小时前
python之开发笔记
开发语言·笔记·python
徐霞客3201 小时前
Qt入门1——认识Qt的几个常用头文件和常用函数
开发语言·c++·笔记·qt
HackKong2 小时前
小白怎样入门网络安全?
网络·学习·安全·web安全·网络安全·黑客