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 {

    }
}
相关推荐
掘金小豆8 小时前
Spring 事务失效的 6 大场景,你踩过几个?
后端·spring·面试
咖啡八杯2 天前
GoF设计模式——备忘录模式
java·后端·spring·设计模式
Flittly3 天前
【AgentScope Java新手村系列】(16)从RAG到多路检索
java·spring boot·spring
咖啡八杯4 天前
GoF设计模式——中介者模式
java·后端·spring·设计模式
Flittly5 天前
【AgentScope Java新手村系列】(14)人机交互
java·spring boot·spring
RainCity5 天前
Java Swing 自定义组件库分享(十二)
java·笔记·后端
唐青枫9 天前
Java Spring WebFlux 实战指南:用 Mono、Flux 和 WebClient 写响应式接口
java·spring
咖啡八杯11 天前
GoF设计模式——策略模式
java·后端·spring·设计模式
Flittly12 天前
【AgentScope Java新手村系列】(11)中断与恢复
java·spring boot·spring
dunky12 天前
Spring 的三级缓存与循环依赖
后端·spring