Spring底层原理学习笔记--第五讲--(常见工厂后处理器与工厂后处理器模拟实现)
常见工厂后处理器
A05Application.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//dataSourceSystem.out.println(name);}//销毁容器context.close();}}
Config.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 {@Beanpublic Bean1 bean1(){return new Bean1();}@Beanpublic 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
package com.lucifer.itheima.a05;public class Bean1 {
}
Bean2.java
package com.lucifer.itheima.a05.component;import lombok.extern.slf4j.Slf4j;@Slf4j
public class Bean2 {public Bean2(){log.info("我被 Spring 管理啦");}
}
Mapper1.java
package com.lucifer.itheima.a05.mapper;import org.apache.ibatis.annotations.Mapper;@Mapper
public interface Mapper1 {
}
Mapper2.java
package com.lucifer.itheima.a05.mapper;import org.apache.ibatis.annotations.Mapper;@Mapper
public interface Mapper2 {
}
工厂后处理器模拟实现-组件扫描1
A05Application.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.componentSystem.out.println(p);//com.lucifer.itheima.a05.component -> classpath*:com/lucifer/itheima/a05/component/**/*.classString path = "classpath*:" + p.replace(".","/") + "/**/*.class";//输出结果为//classpath*:com/lucifer/itheima/a05/component/**/*.classSystem.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//dataSourceSystem.out.println(name);}//销毁容器context.close();}}
Bean2.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
package com.lucifer.itheima.a05.component;import org.springframework.stereotype.Controller;@Controller
public class Bean4 {
}
工厂后处理器模拟实现-组件扫描2
A05Application.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//dataSourceSystem.out.println(name);}//销毁容器context.close();}}
ComponentScanPostProcessor.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.componentSystem.out.println(p);//com.lucifer.itheima.a05.component -> classpath*:com/lucifer/itheima/a05/component/**/*.classString path = "classpath*:" + p.replace(".","/") + "/**/*.class";//输出结果为//classpath*:com/lucifer/itheima/a05/component/**/*.classSystem.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
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//dataSourceSystem.out.println(name);}//销毁容器context.close();}}
AtBeanPostProcessor.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 {@Overridepublic 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
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); //解析@Beancontext.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//dataSourceSystem.out.println(name);}//销毁容器context.close();}}
MapperPostProcessor.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 {@Overridepublic 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();}}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}
}